Merged branch 'jetty-7' into 'jetty-8'.
diff --git a/.gitignore b/.gitignore
index 12ab1b6..815d296 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,4 @@
 
 #maven
 *.versionsBackup
+*.releaseBackup
diff --git a/VERSION.txt b/VERSION.txt
index 21b0980..8433c05 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1,9 +1,20 @@
-jetty-7.6.19-SNAPSHOT
+jetty-8.1.19-SNAPSHOT
 
-jetty-7.6.18.20150929 - 29 September 2015
+jetty-8.1.18.v20150929 - 29 September 2015
+ + 467434 NPE in SslContextFactory
  + 475851 AbstractGenerator.setResponse can produce an invalid Response header
+ + 477817 Fixed memory leak in QueuedThreadPool
  + 477948 Connections leaked when response contains Connection: close header.
 
+jetty-8.1.17.v20150415 - 15 April 2015
+ + 409788 Large POST body causes java.lang.IllegalStateException: SENDING =>
+   HEADERS.
+ + 433802 check EOF in send1xx
+ + 442839 highly fragmented websocket messages can result in corrupt binary
+   messages
+ + 445953 fixed loop closing stream write
+ + 456741 Eof check in flush
+
 jetty-7.6.17.v20150415 - 15 April 2015
  + 409788 Large POST body causes java.lang.IllegalStateException: SENDING =>
    HEADERS.
@@ -12,6 +23,17 @@
    messages
  + 445953 fixed loop closing stream write
 
+jetty-8.1.16.v20140903 - 03 September 2014
+ + 409788 Large POST body causes java.lang.IllegalStateException: SENDING =>
+   HEADERS.
+ + 433689 Evict idle HttpDestinations from client
+ + 433802 check EOF in send1xx
+ + 438996 Scavenger-Timer in HashSessionManager can die because of
+   IllegalStateException from getMaxInactiveInterval
+ + 442048 fixed sendRedirect %2F encoding
+ + 442839 highly fragmented websocket messages can result in corrupt binary
+   messages
+
 jetty-7.6.16.v20140903 - 03 September 2014
  + 409788 Large POST body causes java.lang.IllegalStateException: SENDING =>
    HEADERS.
@@ -19,6 +41,24 @@
  + 442839 highly fragmented websocket messages can result in corrupt binary
    messages
 
+jetty-8.1.15.v20140411 - 11 April 2014
+ + 397167 Remote Access documentation is wrong
+ + 419799 complete after exceptions thrown from async error pages
+ + 420776 complete error pages after startAsync
+ + 421197 fix method comment and ensure close synchronized
+ + 422137 Added maxQueued to QueuedThreadPool MBean
+ + 424180 improve bad message errors
+ + 425038 WebSocketClient leaks file handles when exceptions are thrown from
+   open()
+ + 425551 Memory Leak in SelectConnector$ConnectTimeout.expired.
+ + 426658 backport Bug 425930 to jetty-8
+ + 427761 allow endpoints to be interrupted
+ + 428708 JDBCSessionIdManager when clearing expired sessions failed, jetty
+   should still be able to startup
+ + 428710 JDBCSession(Id)Manager use 'read committed isolation level'
+ + 430968 Use wrapped response with async dispatch
+ + 432452 ConnectHandler does not timeout sockets in FIN_WAIT2.
+
 jetty-7.6.15.v20140411 - 11 April 2014
  + 422137 Added maxQueued to QueuedThreadPool MBean
  + 425038 WebSocketClient leaks file handles when exceptions are thrown from
@@ -26,6 +66,13 @@
  + 425551 Memory Leak in SelectConnector$ConnectTimeout.expired.
  + 432452 ConnectHandler does not timeout sockets in FIN_WAIT2.
 
+jetty-8.1.14.v20131031 - 31 October 2013
+ + 417772 fixed low resources idle timeout
+ + 418636 Name anonymous filter and holders with classname-hashcode
+ + 419432 Allow to override the SslContextFactory on a per-destination basis.
+ + 420048 DefaultServlet alias checks configured resourceBase
+ + 420530 AbstractLoginModule never fails a login
+
 jetty-7.6.14.v20131031 - 31 October 2013
  + 417772 fixed low resources idle timeout
  + 418636 Name anonymous filter and holders with classname-hashcode
@@ -33,6 +80,29 @@
  + 420048 DefaultServlet alias checks configured resourceBase
  + 420530 AbstractLoginModule never fails a login
 
+jetty-8.1.13.v20130916 - 16 September 2013
+ + 412629 PropertyFileLoginModule doesn't cache user configuration file even
+   for refreshInterval=0
+ + 413484 setAttribute in nosql session management better handles _dirty status
+ + 413684 deprecated unsafe alias checkers
+ + 414235 RequestLogHandler configured on a context fails to handle forwarded
+   requests
+ + 414393 StringIndexOutofBoundsException with > 8k multipart content without
+   CR or LF
+ + 414431 Avoid debug NPE race
+ + 414507 Ensure AnnotationParser ignores parent dir hierarchy when checking
+   for hidden dirnames
+ + 414652 WebSocket's sendMessage() may hang on congested connections.
+ + 415192 <jsp-file> maps to JspPropertyGroupServlet instead of JspServlet
+ + 415401 Add XmlConfiguration.initializeDefaults that allows to set default
+   values for any XmlConfiguration that may be overridden in the config file
+ + 416266 HttpServletResponse.encodeURL() encodes on first request when only
+   SessionTrackingMode.COOKIE is used
+ + 416585 WebInfConfiguration examines webapp classloader first instead of its
+   parent when looking for container jars
+ + 416787 StringIndexOutOfBounds with a pathMap of ""
+ + 416990 JMX names statically unique
+
 jetty-7.6.13.v20130916 - 16 September 2013
  + 412629 PropertyFileLoginModule doesn't cache user configuration file even
    for refreshInterval=0
@@ -53,6 +123,44 @@
    parent when looking for container jars
  + 416990 JMX names statically unique
 
+jetty-8.1.12.v20130726 - 26 July 2013
+ + 396706 CGI support parameters
+ + 397193 MongoSessionManager refresh updates last access time
+ + 407342 ReloadedSessionMissingClassTest uses class compiled with jdk7
+ + 408529 Etags set in 304 response
+ + 408600 set correct jetty.url in all pom files
+ + 408642 setContentType from addHeader
+ + 408662 In pax-web servlet services requests even if init() has not finished
+   running
+ + 408806 getParameter returns null on Multipart request if called before
+   request.getPart()/getParts()
+ + 408909 GzipFilter setting of headers when reset and/or not compressed
+ + 409028 Jetty HttpClient does not work with proxy CONNECT method.
+ + 409133 Empty <welcome-file> causes StackOverflowError
+ + 409436 NPE on context restart using dynamic servlet registration
+ + 409449 Ensure servlets, filters and listeners added via dynamic
+   registration, annotations or descriptors are cleaned on context restarts
+ + 409556 FileInputStream not closed in DirectNIOBuffer
+ + 410405 Avoid NPE for requestDispatcher(../)
+ + 410630 MongoSessionManager conflicting session update op
+ + 410750 NoSQLSessions: implement session context data persistence across
+   server restarts
+ + 410893 async support defaults to false for spec created servlets and filters
+ + 411135 HttpClient may send proxied https requests to the proxy instead of
+   the target server.
+ + 411216 RequestLogHandler handles async completion
+ + 411458 MultiPartFilter getParameterMap doesn't preserve multivalued
+   parameters 411459  MultiPartFilter.Wrapper getParameter should use charset
+   encoding of part
+ + 411755 MultiPartInputStreamParser fails on base64 encoded content
+ + 411909 GzipFilter flushbuffer() results in erroneous finish() call
+ + 412712 HttpClient does not send the terminal chunk after partial writes.
+ + 412750 HttpClient close expired connections fix
+ + 413371 Default JSON.Converters for List and Set.
+ + 413372 JSON Enum uses name rather than toString()
+ + 413684 Trailing slash shows JSP source
+ + 413812 Make RateTracker serializable
+
 jetty-7.6.12.v20130726 - 26 July 2013
  + 396706 CGI support parameters
  + 397193 MongoSessionManager refresh updates last access time
@@ -84,6 +192,70 @@
  + 413684 Trailing slash shows JSP source
  + 413812 Make RateTracker serializable
 
+jetty-8.1.11.v20130520 - 20 May 2013
+ + 402844 STOP.PORT & STOP.KEY behaviour has changed
+ + 403281 jetty.sh waits for started or failure before returning
+ + 403513 jetty:run goal cannot be executed twice during the maven build
+ + 403570 Asynchronous Request Logging
+ + 404010 fix cast exception in mongodb session manager
+ + 404128 Add Vary headers rather than set them
+ + 404283 org.eclipse.jetty.util.Scanner.scanFile() dies with an NPE if
+   listFiles() returns null
+ + 404325 data constraint redirection does send default port
+ + 404517 Close connection if request received after half close
+ + 404789 Support IPv6 addresses in DoSFilter white list.
+ + 404958 Fixed Resource.newSystemResource striped / handling
+ + 405281 allow filemappedbuffers to not be used
+ + 405537 NPE in rendering JSP using SPDY and wrapped ServletRequest
+ + 406437 Digest Auth supports out of order nc
+ + 406618 Jetty startup in OSGi Equinox fails when using option
+   jetty.home.bundle=org.eclipse.jetty.osgi.boot
+ + 406923 CR line termination
+ + 407136 @PreDestroy called after Servlet.destroy()
+ + 407173 java.lang.IllegalStateException: null when using JDBCSessionManager
+ + 407931 Add toggle for failing on servlet availability
+ + 407976 JDBCSessionIdManager potentially leaves server in bad state after
+   startup
+ + 408077 HashSessionManager leaves file handles open after being stopped
+ + 408446 Multipart parsing issue with boundry and charset in ContentType
+   header
+
+jetty-8.1.10.v20130312 - 12 March 2013
+ + 376273 Early EOF because of SSL Protocol Error on
+   https://api-3t.paypal.com/nvp.
+ + 381521 allow compress methods to be configured
+ + 392129 fixed handling of timeouts after startAsync
+ + 394064 ensure that JarFile instances are closed on JarFileResource.release()
+ + 398649 ServletContextListener.contextDestroyed() is not called on
+   ContextHandler unregistration
+ + 399703 made encoding error handling consistent
+ + 399799 do not hold lock while calling invalidation listeners
+ + 399967 Shutdown hook calls destroy
+ + 400040 NullPointerException in HttpGenerator.prepareBuffers
+ + 400142 ConcurrentModificationException in JDBC SessionManger
+ + 400144 When loading a session fails the JDBCSessionManger produces duplicate
+   session IDs
+ + 400312 ServletContextListener.contextInitialized() is not called when added
+   in ServletContainerInitializer.onStartup
+ + 400457 Thread context classloader hierarchy not searched when finding
+   webapp's java:comp/env
+ + 400859 limit max size of writes from cached content
+ + 401211 Remove requirement for jetty-websocket.jar in WEB-INF/lib
+ + 401317 Make Safari 5.x websocket support minVersion level error more clear
+ + 401382 Prevent parseAvailable from parsing next chunk when previous has not
+   been consumed. Handle no content-type in chunked request.
+ + 401474 Performance problem in org.eclipse.jetty.annotation.AnnotationParser
+ + 401485 zip file closed exception
+ + 401531 StringIndexOutOfBoundsException for "/*" <url-pattern> of
+   <jsp-property-group> fix for multiple mappings to *.jsp
+ + 401908 Enhance DosFilter to allow dynamic configuration of attributes.
+ + 402048 org.eclipse.jetty.server.ShutdownMonitor doesn't stop after the jetty
+   server is stopped
+ + 402485 reseed secure random
+ + 402735 jetty.sh to support status which is == check
+ + 402833 Test harness for global error page and hide exception message from
+   reason string
+
 jetty-7.6.11.v20130520 - 20 May 2013
  + 402844 STOP.PORT & STOP.KEY behaviour has changed
  + 403281 jetty.sh waits for started or failure before returning
@@ -141,6 +313,57 @@
  + 402833 Test harness for global error page and hide exception message from
    reason string
 
+jetty-8.1.9.v20130131 - 31 January 2013
+ + 362226 HttpConnection "wait" call causes thread resource exhaustion
+ + 367638 throw exception for excess form keys
+ + 381521 Only set Vary header when content could be compressed
+ + 382237 support non java JSON classes
+ + 391248 fixing localhost checking in statistics servlet
+ + 391249 fix for invalid XML node dispatchedTimeMean in statistics servlet
+ + 391345 fix missing br tag in statistics servlet
+ + 391623 Add option to --stop to wait for target jetty to stop
+ + 392417 Prevent Cookie parsing interpreting unicode chars
+ + 392492 expect headers only examined for requests>=HTTP/1.1
+ + 393075 1xx 204 and 304 ignore all headers suggesting content
+ + 393158 java.lang.IllegalStateException when sending an empty InputStream
+ + 393220 remove dead code from ServletHandler and log ServletExceptions in
+   warn instead of debug
+ + 393947 additional tests
+ + 393968 fix typo in javadoc
+ + 394294 A web-bundle started before jetty-osgi should be deployed as a webapp
+   when jetty-osgi starts
+ + 394514 Preserve URI parameters in sendRedirect
+ + 394541 remove continuation jar from distro, add as dep to test-jetty-webapp
+ + 394719 remove regex from classpath matching
+ + 394811 Make JAASLoginService log login failures to DEBUG instead of WARN.
+   Same for some other exceptions.
+ + 394829 Session can not be restored after SessionManager.setIdleSavePeriod
+   has saved the session
+ + 394839 Allow multipart mime with no boundary
+ + 394870 Make enablement of remote access to test webapp configurable in
+   override-web.xml
+ + 395215 Multipart mime with just LF and no CRLF
+ + 395380 add ValidUrlRule to jetty-rewrite
+ + 395394 allow logging from boot classloader
+ + 396253 FilterRegistration wrong order
+ + 396459 Log specific message for empty request body for multipart mime
+   requests
+ + 396500 HttpClient Exchange takes forever to complete when less content sent
+   than Content-Length
+ + 396574 add JETTY_HOME as a location for pid to be found
+ + 396886 MultiPartFilter strips bad escaping on filename="..."
+ + 397110 Accept %uXXXX encodings in URIs
+ + 397111 Tolerate empty or excessive whitespace preceeding MultiParts
+ + 397112 Requests with byte-range throws NPE if requested file has no mimetype
+   (eg no file extension)
+ + 397130 maxFormContentSize set in jetty.xml is ignored
+ + 397190 improve ValidUrlRule to iterate on codepoints
+ + 397321 Wrong condition in default start.config for annotations
+ + 397535 Support pluggable alias checking to support symbolic links
+ + 398337 UTF-16 percent encoding in UTF-16 form content
+ + 399132 check parent dir of session store against file to be removed
+ + JETTY-1533 handle URL with no path
+
 jetty-7.6.9.v20130131 - 31 January 2013
  + 362226 HttpConnection "wait" call causes thread resource exhaustion
  + 367638 throw exception for excess form keys
@@ -186,6 +409,52 @@
  + 399132 check parent dir of session store against file to be removed
  + JETTY-1533 handle URL with no path
 
+jetty-8.1.8.v20121106 - 06 November 2012
+ + 371170 MongoSessionManager LastAccessTimeTest fails
+ + 388675 Non utf8 encoded query strings not decoded to parameter map using
+   queryEncoding
+ + 388706 Avoid unnecessary indirection through Charset.name
+ + 389390 AnnotationConfiguration is ignored if the metadata-complete attribute
+   is present in an override descriptor regardless of the value
+ + 389452 if web-fragment metadata-complete==true still scan its related jar if
+   there there is a ServletContainerInitializer, ensure webapp restarts work
+ + 389686 Fix reference to org.eclipse.jetty.util.log.stderr.LONG system
+   property in javadoc for StdErrLog
+ + 389956 Bad __context set in WebAppContext.start sequence with respect to ENC
+   setup
+ + 389965 OPTIONS should allow spaces in comma separated list
+ + 390108 Servlet 3.0 API for programmatic login doesn't appear to work
+ + 390161 Apply DeferredAuthentication fix to jaspi
+ + 390163 Implement ServletRegistration.Dynamic.setServletSecurity
+ + 390503 http-method-omission element not being processed
+ + 390560 The method AnnotationParser.getAnnotationHandlers(String) always
+   returns a empty collection.
+ + 391080 Multipart temp files can be left on disk from Request.getPart and
+   getParts
+ + 391082 No exception if multipart input stream incomplete
+ + 391188 Files written with Request.getPart().write(filename) should not be
+   auto-deleted
+ + 391483 fix bad javadoc example in shutdown handler
+ + 391622 Be lenient on RFC6265 restriction on duplicate cookie names in same
+   response
+ + 391623 Add option to --stop to wait for target jetty to stop
+ + 391877 org.eclipse.jetty.webapp.FragmentDescriptor incorrectly reporting
+   duplicate others for after ordering
+ + 392239 Allow no error-code or exception for error-pages
+ + 392525 Add option to --stop-wait to specify timeout
+ + 392641 JDBC Sessions not scavenged if expired during downtime
+ + 392812 MongoSessionIDManager never purges old sessions
+ + 393014 Mongodb purgevalid using query for purgeinvalid
+ + 393015 Mongodb purge not rescheduled
+ + 393075 Jetty WebSocket client cannot connect to Tomcat WebSocket Server
+ + 393218 add xsd=application/xml mime mapping to defaults
+ + 393363 Use Locale.ENGLISH for all toUpperCase and toLowerCase calls
+ + 393368 min websocket version
+ + 393383 delay onClose call until closeOut is done
+ + 393494 HashSessionManager can't delete unrestorable sessions on Windows
+ + JETTY-1547 Jetty does not honor web.xml
+   web-app/jsp-config/jsp-property-group/default-content-type
+
 jetty-7.6.8.v20121106 - 06 November 2012
  + 371170 MongoSessionManager LastAccessTimeTest fails
  + 388675 Non utf8 encoded query strings not decoded to parameter map using
@@ -215,11 +484,11 @@
  + 393383 delay onClose call until closeOut is done
  + 393494 HashSessionManager can't delete unrestorable sessions on Windows
 
-jetty-7.6.7.v20120910 - 10 September 2012
+jetty-8.1.7.v20120910 - 10 September 2012
  + 388895 Update dependencies for jetty-jndi
  + fix busy logging statement re: sessions
 
-jetty-7.6.6.v20120903 - 03 September 2012
+jetty-8.1.6.v20120903 - 03 September 2012
  + 347130 Empty getResourcePaths due to ZipFileClosedException
  + 367591 Support Env variables in XmlConfiguration.
  + 377055 Prevent webapp classloader leaks
@@ -252,7 +521,7 @@
  + 385925 make SslContextFactory.setProtocols and
    SslContextFactory.setCipherSuites preserve the order of the given parameters
 
-jetty-7.6.5.v20120716 - 16 July 2012
+jetty-8.1.5.v20120716 - 16 June 2012
  + 376717 Balancer Servlet with round robin support, contribution, added
    missing license
  + 379250 Server is added to shutdown hook twice
@@ -270,15 +539,20 @@
  + 383251 500 for SocketExceptions
  + 383881 WebSocketHandler sets request as handled
  + 384254 revert change to writable when not dispatched
+ + 384280 Implement preliminary ServletRegistrations
  + 384847 CrossOriginFilter is not working.
  + 384896 JDBCSessionManager fails to load existing sessions on oracle when
    contextPath is /
  + 384980 Jetty client unable to recover from Time outs when connection count
    per address hits max.
+ + 385138 add getter for session path and max cookie age that seemed to
+   disappear in a merge long ago
+ + JETTY-1523 It is imposible to map servlet to "/" using
+   WebApplicationInitializer
  + JETTY-1525 Show handle status in response debug message
  + JETTY-1530 refine search control on ldap login module
 
-jetty-7.6.4.v20120524 - 24 May 2012
+jetty-8.1.4.v20120524 - 24 May 2012
  + 367608 ignore the aysncrequestreadtest as it is known to fail and is waiting
    for a fix
  + 371853 Support bundleentry: protocol for webapp embedded as directory in
@@ -287,9 +561,10 @@
    jetty-osgi-boot-logback bundle
  + 376152 apply context resources recursively
  + 376801 Make JAAS login modules useable without jetty infrastructure
+ + 377323 Request#getParts() throws ServletException when it should be throwing
+   IllegalStateException
  + 377391 Manifest updates to jetty-osgi-boot-logback
- + 377492 NPE when deploying a Web Application Bundle with unresolved
-   Require-TldBundle
+ + 377492 NPE if jsp taglibs bundle not deployed
  + 377550 set charset when content type is set
  + 377587 ConnectHandler write will block on partial write
  + 377610 New session not timed out if an old session is invalidated in scope
@@ -310,14 +585,18 @@
  + 380212 Clear buffer if parsing fails due to full buffer
  + 380222 JettyPolicyRuntimeTest failure
 
-jetty-7.6.3.v20120416 - 16 April 2012
+jetty-8.1.3.v20120416 - 16 April 2012
+ + 349110 MultiPartFilter records the content-type in request params
  + 367172 Remove detection for slf4j NOPLogger
+ + 372678 Embedded Examples need updates for new LoginService requirement
  + 373269 Make ServletHandler.notFound() method impl do nothing - override to
    send back 404.
  + 373421 address potential race condition related to the nonce queue removing
    the same nonce twice
  + 373952 bind called too frequently on refresh
  + 374018 correctly handle requestperminuted underflow
+ + 374152 jetty-all-server MANIFEST contains wrong import:
+   javax.servlet.annotation;version="[2.6,3)"
  + 374252 SslConnection.onClose() does not forward to nested connection.
  + 374258 SPDY leaks SSLEngines. Made the test more reliable.
  + 374367 NPE in QueuedThreadPool.dump() with early java6 jvms
@@ -336,13 +615,19 @@
  + 375594 fixed SSL tests so they are not order dependent
  + 375709 Ensure resolveTempDirectory failure does not deadlock; improve error
    message
+ + 375906 Part.getHeader method not case insensitive
  + 375970 HttpServletRequest.getRemoteAddr() returns null when HTTP is over
    SPDY.
  + 376201 HalfClosed state not handled properly. Addendum to restore previous
    behavior, where a closed stream was also half closed.
+ + 376324 <max-file-size> is not respected in <multipart-config>
+ + JETTY-1495 Ensure dynamic servlet addition does not cause servlets to be
+   inited.
+ + JETTY-1500 form parameters from multipart request not available via
+   request.getParameter
  + JETTY-1504 HttpServletResponseWrapper ignored when using asyncContext?
 
-jetty-7.6.2.v20120308 - 08 March 2012
+jetty-8.1.2.v20120308 - 08 March 2012
  + 370387 SafariWebsocketDraft0Test failure during build.
  + 371168 Update ClientCrossContextSessionTest
  + 372093 handle quotes in Require-Bundle manifest string
@@ -359,11 +644,12 @@
  + 373306 Set default user agent extraction pattern for UserAgentFilter
  + 373567 cert validation issue with ocsp and crldp always being enabled when
    validating turned on fixed
+ + 373603 NullPointer in WebServletAnnotation
  + JETTY-1409 GzipFilter will double-compress application/x-gzip content
  + JETTY-1489 WebAppProvider attempts to deploy .svn folder
  + JETTY-1494 .
 
-jetty-7.6.1.v20120215 - 15 February 2012
+jetty-8.1.1.v20120215 - 15 February 2012
  + 369121 simplified test
  + 370120 jvm arguments added via start.ini and --exec are missing spaces
  + 370137 SslContextFactory does not respect order for
@@ -377,12 +663,98 @@
  + JETTY-1484 Add option for HashSessionManager to delete session files if it
    can't restore them
 
-jetty-7.6.0.v20120127 - 27 January 2012
+jetty-8.1.0.v20120127 - 27 January 2012
  + 368773 allow authentication to be set by non securityHandler handlers
  + 368992 avoid update key while flushing during a write
  + 369216 turned off the shared resource cache
  + 369349 replace quotes with a space escape method
 
+jetty-8.1.0.RC5 - 20 January 2012
+ + 359329 Prevent reinvocation of LoginModule.login with jaspi for already
+   authed user
+ + 368632 Remove superfluous removal of org.apache.catalina.jsp_file
+ + 368633 fixed configure.dtd resource mappings
+ + 368635 moved lifecycle state reporting from toString to dump
+ + 368773 process data constraints without realm
+ + 368787 always set token view to new header buffers in httpparser
+ + 368821 improved test harness
+ + 368920 JettyAwareLogger always formats the arguments.
+ + 368948 POM for jetty-jndi references unknown version for javax.activation.
+ + 368992 NPE in HttpGenerator.prepareBuffers() test case.
+ + JETTY-1475 made output state fields volatile to provide memory barrier for
+   non dispatched thread IO
+
+jetty-8.1.0.RC4 - 13 January 2012
+ + 365048 jetty Http client does not send proxy authentication when requesting
+   a Https-resource through a web-proxy.
+ + 366774 removed XSS vulnerbility
+ + 367099 Upgrade jetty-websocket for RFC 6455 - Addendum.
+ + 367433 added tests to investigate
+ + 367435 improved D00 test harness
+ + 367485 HttpExchange canceled before response do not release connection.
+ + 367502 WebSocket connections should be closed when application context is
+   stopped.
+ + 367548 jetty-osgi-boot must not import the nested package twice
+ + 367591 corrected configuration.xml version to 7.6
+ + 367635 Added support for start.d directory
+ + 367716 simplified maxIdleTime logic
+ + 368035 WebSocketClientFactory does not invoke super.doStop().
+ + 368060 do not encode sendRedirect URLs
+ + 368112 NPE on <jsp-config><taglib> element parsing web.xml
+ + 368113 Support servlet mapping to ""
+ + 368114 Protect against non-Strings in System properties for Log
+ + 368189 WebSocketClientFactory should not manage external thread pool. 368240
+   - Improve AggregateLifeCycle handling of shared lifecycles
+ + 368215 Remove debug from jaspi
+ + 368240 Better handling of locally created ThreadPool. Forgot to null out
+   field.
+ + 368291 Change warning to info for NoSuchFieldException on
+   BeanELResolver.properties
+ + 367638 limit number of form parameters to avoid DOS
+ + JETTY-1467 close half closed when idle
+
+jetty-8.1.0.RC2 - 22 December 2011
+ + 359329 jetty-jaspi must exports its packages. jetty-plus must import
+   javax.security
+ + 364638 HttpParser closes if data received while seeking EOF. Tests fixed to
+   cope
+ + 364921 Made test less time sensitive
+ + 364936 use Resource for opening URL streams
+ + 365267 NullPointerException in bad Address
+ + 365375 ResourceHandler should be a HandlerWrapper
+ + 365750 Support WebSocket over SSL, aka wss://
+ + 365932 Produce jetty-websocket aggregate jar for android use
+ + 365947 Set headers for Auth failure and retry in http-spi
+ + 366316 Superfluous printStackTrace on 404
+ + 366342 Dont persist DosFilter trackers in http session
+ + 366730 pass the time idle to onIdleExpire
+ + 367048 test harness for guard on suspended requests
+ + 367175 SSL 100% CPU spin in case of blocked write and RST.
+ + 367219 WebSocketClient.open() fails when URI uses default ports.
+ + 367383 jsp-config element must be returned for
+   ServletContext.getJspConfigDescriptor
+ + JETTY-1460 suppress PrintWriter exceptions
+ + JETTY-1463 websocket D0 parser should return progress even if no fill done
+ + JETTY-1465 NPE in ContextHandler.toString
+
+jetty-8.1.0.RC1 - 06 December 2011
+ + 360245 The version of the javax.servlet packages to import is 2.6 instead of
+   3.0
+ + 365370 ServletHandler can fall through to nested handler
+
+jetty-8.1.0.RC0 - 30 November 2011
+ + 352565 cookie httponly flag ignored
+ + 353285 ServletSecurity annotation ignored
+ + 357163 jetty 8 ought to proxy jetty8 javadocs
+ + 357209 JSP tag listeners not called
+ + 360051 SocketConnectionTest.testServerClosedConnection is excluded.
+ + 361135 Allow session cookies to NEVER be marked as secure, even on HTTPS
+   requests.
+ + 362249 update shell scripts to jetty8
+ + 363878 Add ecj compiler to jetty-8 for jsp
+ + 364283 can't parse the servlet multipart-config for the web.xml
+ + 364430 Support web.xml enabled state for servlets
+
 jetty-7.6.0.RC5 - 20 January 2012
  + 359329 Prevent reinvocation of LoginModule.login with jaspi for already
    authed user
@@ -489,6 +861,22 @@
  + 364657 Support HTTP only cookies from standard API
  + JETTY-1442 add _hostHeader setter for ProxyRule
 
+jetty-8.0.4.v20111024 - 24 October 2011
+ + 358263 JDBCSessionIdManager add setDatasource(DataSource) method
+ + 358649 Replace existing StdErrLog system properties for DEBUG/IGNORED with
+   LEVEL instead.
+ + 360836 Accept parameters with bad UTF-8. Use replacement character
+ + 360912 CrossOriginFilter does not send Access-Control-Allow-Origin on
+   responses. 355103 Make allowCredentials default to true in
+   CrossOriginFilter.
+ + 360938 Connections closed after a while.
+ + 361135 secure cookies for sessions
+ + 361319 Log initialization does not catch correct exceptions on all jvms
+ + 361325 359292 Allow KeyStore to be set
+ + 361456 release timer task on connection failed
+ + 361655 ExecutorThreadPool.isLowOnThreads() returns wrong value.
+ + JETTY-1444 start threadpool before selector manager
+
 jetty-7.5.4.v20111024 - 24 October 2011
  + 358263 JDBCSessionIdManager add setDatasource(DataSource) method
  + 358649 Replace existing StdErrLog system properties for DEBUG/IGNORED with
@@ -504,12 +892,12 @@
  + 361655 ExecutorThreadPool.isLowOnThreads() returns wrong value.
  + JETTY-1444 start threadpool before selector manager
 
-jetty-7.5.3.v20111011 - 11 October 2011
+jetty-8.0.3.v20111011 - 11 October 2011
  + 348978 migrate jetty-http-spi
  + 358649 StdErrLog system properties for package/class logging LEVEL.
 
-jetty-7.5.2.v20111006 - 06 October 2011
- + 336443 check nonce count is increasing
+jetty-8.0.2.v20111006 - 06 October 2011
+ + 336443 add missing comma in DigestAuthenticator string
  + 342161 ScannerTest fails intermittently on Mac OS X
  + 346419 testing HttpClient FDs
  + 353267 Request._parameters initialization bug
@@ -517,8 +905,10 @@
  + 353627 Basic Auth checks that Basic method has been send
  + 356144 Allow SelectorManager thread priority to be set
  + 356274 Start SSL socket factory in call to open()
+ + 357163 jetty 8 ought to proxy jetty8 javadocs
  + 357178 websockets draft 14 support
  + 357188 Send content buffer directly
+ + 357209 JSP tag listeners not called
  + 357216 Logging via Log4J does not expand braces in format strings
  + 357240 more half close refinements
  + 357338 remove debug
@@ -558,6 +948,73 @@
  + JETTY-1434 Add a jsp that exercises jstl.
  + JETTY-1439 space in directory installation path causes classloader problem
 
+jetty-7.5.3.v20111011 - 11 October 2011
+ + 348978 migrate jetty-http-spi
+ + 358649 StdErrLog system properties for package/class logging LEVEL.
+
+jetty-7.5.2.v20111006 - 06 October 2011
+ + 336443 check nonce count is increasing
+ + 342161 ScannerTest fails intermittently on Mac OS X
+ + 346419 testing HttpClient FDs
+ + 353267 Request._parameters initialization bug
+ + 353509 jetty-client unit tests are running too long
+ + 353627 Basic Auth checks that Basic method has been send
+ + 356144 Allow SelectorManager thread priority to be set
+ + 356274 Start SSL socket factory in call to open()
+ + 357178 websockets draft 14 support
+ + 357188 Send content buffer directly
+ + 357209 JSP tag listeners not called
+ + 357216 Logging via Log4J does not expand braces in format strings
+ + 357240 more half close refinements
+ + 357338 remove debug
+ + 357672 resolve issue with serializing pojos with mongodb session manager,
+   thanks to john simone for the discovery and fix
+ + 357959 Include javadoc in distribution
+ + 358027 NullPointerException in ResourceHandler with jetty-stylesheet.css
+ + 358035 idle time only active if > 0
+ + 358147 Add catch for UnknownHostException to fix leaky file descriptor in
+   client
+ + 358164 Dispatch from servlet to handler
+ + 358263 add method for osgi users to register a driver as Class.forName does
+   not work for them
+ + 358649 StdErrLog system properties for package/class logging LEVEL.
+ + 358674 Still allows sslv3 for now
+ + 358687 Updated jsp does not scan for system tlds Fixed pattern.
+ + 358784 JSP broken on Java 1.5
+ + 358925 bit more javadoc on usage
+ + 358959 File descriptor leak with UnresolvedAddressException
+ + 359309 adjust previous test for servletPath to include pathInfo
+ + 359673 updated websocket version handling
+ + 359675 Principal != String, fix for issue in property file login manager
+ + 360051 SocketConnectionTest.testServerClosedConnection is excluded.
+ + 360066 jsps referenced in web.xml <jsp-file> elements do not compile
+ + JETTY-1130 Access Sessions from HashSessionIdManager
+ + JETTY-1277 Fixed sendRedirect encoding of relative locations
+ + JETTY-1322 idle sweeper checks for closed endp
+ + JETTY-1377 extra logging for busy selector
+ + JETTY-1378 new sys property for the latest jsp-impl to force the use of the
+   JDTCompiler when running in OSGi.
+ + JETTY-1414 applied to PropertyUserStore
+ + JETTY-1415 Start/Stop Server and Client only once in test, code format
+ + JETTY-1420 Set Host header for new request in RedirectListener
+ + JETTY-1421 Implement RedirectListener.onException,onConnectionFailed
+ + JETTY-1423 force connection to be closed returned
+ + JETTY-1430 local JNDI contexts don't carry environment
+ + JETTY-1434 Add a jsp that exercises jstl.
+ + JETTY-1439 space in directory installation path causes classloader problem
+
+jetty-8.0.1.v20110908 - 08 September 2011
+ + 350634 Added Resource.newResource(File)
+ + 356190 fix monodb tests  for changed test api
+ + 356428 removed timed waits from test
+ + 356693 reduce visibility to webapp of websocket implementations
+ + 356695 jetty server jars are provided for websockets
+ + 356726 Instead of the sessionDestroyed called sessionCreated after
+   invalidate session
+ + 356751 Add null protection to ServletContextHandler.doStop
+ + 356823 correctly decode close codes.  Send not utf-8 close code.
+ + 357058 Acceptor thread blocking
+
 jetty-7.5.1.v20110908 - 08 September 2011
  + 350634 Added Resource.newResource(File)
  + 356190 fix monodb tests  for changed test api
@@ -570,6 +1027,12 @@
  + 356823 correctly decode close codes.  Send not utf-8 close code.
  + 357058 Acceptor thread blocking
 
+jetty-8.0.0.v20110901 - 01 September 2011
+ + 352565 cookie httponly flag ignored
+ + 353073 better warnings
+ + 353285 ServletSecurity annotation ignored
+ + 356421 Upgraded websocket to draft 13 support
+
 jetty-7.5.0.v20110901 - 01 September 2011
  + 356421 Upgraded websocket to draft 13 support
  + 353073 better warnings
@@ -604,6 +1067,19 @@
  + JETTY-1414 HashLoginService doesn't refresh realm if specified config
    filename is not an absolute platform specific value
 
+jetty-8.0.0.RC0 - 16 August 2011
+ + Merge from jetty-7.4.3
+ + Enable annotations by default
+ + 352565 cookie httponly flag ignored
+ + 353285 ServletSecurity annotation ignored
+
+jetty-8.0.0.M3 - 27 May 2011
+ + 324505 Implement API login
+ + 335500 request.getParts() throws a NullPointerException
+ + 343472 isUserInRole does not prevent subsequent login call.
+ + 346180 jsp-2.2 support
+ + Updated to jetty-7.4.2.v20110526
+
 jetty-7.5.0.RC0 - 15 August 2011
  + 298502 Handle 200 Connect responses with no content-length
  + 347484 / - > ${/} in some paths in grant codebases
@@ -786,6 +1262,26 @@
  + Ensure generated fragment names are unique
  + Added extra session removal test
 
+jetty-8.0.0.M2 - 16 November 2010
+ + 320073 Reconsile configuration mechanism
+ + 321068 JSF2 fails to initialize
+ + 324493 Registration init parameter handling null check, setInitParameters
+   additive
+ + 324505 Request.login method must throw ServletException if it cant login
+ + 324872 allow disabling listener restriction from using *Registration
+   interfaces
+ + 327416 Change meaning of @HandlesTypes in line with latest interpretation by
+   JSR315
+ + 327489 Change meaning of @MultipartConfig to match servlet spec 3.0
+   maintenance release 3.0a
+ + 328008 Handle update to Servlet Spec 3 Section 8.2.3.h.ii
+ + 330188 Reject web-fragment.xml with same <name> as another already loaded
+   one
+ + 330208 Support new wording on servlet-mapping and filter-mapping merging
+   from servlet3.0a
+ + 330292 request.getParts() returns only one part when the name is the same
+ + Update to jetty-7.2.1.v20101111
+
 jetty-7.3.1.v20110307 - 07 March 2011
  + 316382 Support a more strict SSL option with certificates
  + 333481 Handle UCS-4 codepoints in decode and encode
@@ -811,9 +1307,7 @@
  + 338068 Leaking ConstraintMappings on redeploy
  + 338092 ProxyServlet leaks memory
  + 338607 Removed managed attributes when context is stopped
- + 338880 Fixed failing buffer range checks
- + 338920 Handle non existent real path directories
- + 338961 AJP packet size
+ + 338819 Externally control Deployment Manager application lifecycle
  + JETTY-1304 Allow quoted boundaries in Multipart filter
  + JETTY-1317 More elegent handling of bad URIs in requests
  + JETTY-1331 Allow alternate XML configuration processors (eg spring)
@@ -999,7 +1493,6 @@
  + JETTY-1245 Do not use direct buffers with NIO SSL
  + JETTY-1249 Apply max idle time to all connectors
  + JETTY-1250 Parallel start of HandlerCollection
- + JETTY-1252 Handle more multipart transfer encodings
  + JETTY-1256 annotation and jta jars from Orbit
  + JETTY-1259 NullPointerException in JDBCSessionIdManager when invalidating
    session
@@ -1027,6 +1520,15 @@
  + JETTY-1249 Apply max idle time to all connectors
  + JETTY-1251 Replace then close selector for JVM bugs
 
+jetty-8.0.0.M1 - 12 July 2010
+ + 306350 Ensure jars excluded by ordering are not scanned for annotations
+ + JETTY-1224 Change jetty-8 merge rules for fragment descriptors and
+   annotations
+ + Ensure <absolute-ordering> in web.xml overrides relative <ordering> in
+   fragments
+ + Ensure empty <absolute-ordering> implies exclusion of all fragments
+ + Ensure servlet-api jar class inheritance hierarchy is scanned
+
 jetty-7.1.5.v20100705
  + Update ecj to 3.6 Helios release drop
  + 288194 Add blacklist/whitelist to ProxyServlet and ProxyHandler
@@ -1190,6 +1692,9 @@
  + Fix jetty-plus.xml reference to addLifeCycle
  + JETTY-1200 SSL NIO Endpoint wraps non NIO buffers
  + JETTY-1202 Use platform default algorithm for SecureRandom
+ + Merged 7.0.2.v20100331
+ + Add NPE protection to ContainerInitializerConfiguration
+ + Temporarily remove jetty-osgi module to clarify jsp version compatibility
  + JETTY-1212 handle long content lengths
  + JETTY-1214 avoid ISE when scavenging invalid session
  + JETTY-903 Stop both caches
@@ -1338,6 +1843,11 @@
  + 305997 Coalesce buffers in ChannelEndPoint.flush()
  + 306028 Enable TCP_NODELAY by default in client connectors
 
+jetty-8.0.0.M0 - 28 February 2010
+ + Updated servlet 3.0 spec 20100224
+ + Merged 7.0.1.v20091116
+ + Updated to cometd 1.0.1
+
 jetty-7.0.1.v20091125 - 25 November 2009
  + 274251 DefaultServlet supports exact match mode.
  + 288401 HttpExchange.cancel() Method Unimplemented
diff --git a/example-async-rest/async-rest-jar/pom.xml b/example-async-rest/async-rest-jar/pom.xml
new file mode 100644
index 0000000..87c5de9
--- /dev/null
+++ b/example-async-rest/async-rest-jar/pom.xml
@@ -0,0 +1,24 @@
+<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>example-async-rest</artifactId>
+    <version>8.1.19-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.eclipse.jetty.example-async-rest</groupId>
+  <artifactId>example-async-rest-jar</artifactId>
+  <packaging>jar</packaging>
+  <name>Example Async Rest :: Jar</name>
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-client</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+         <groupId>org.eclipse.jetty.orbit</groupId>
+         <artifactId>javax.servlet</artifactId>
+         <scope>provided</scope>
+       </dependency>
+  </dependencies>
+</project>
diff --git a/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java
new file mode 100644
index 0000000..f23518e
--- /dev/null
+++ b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java
@@ -0,0 +1,120 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.example.asyncrest;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.URLEncoder;
+import java.util.Map;
+import java.util.Queue;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Abstract Servlet implementation class AsyncRESTServlet.
+ * Enquires ebay REST service for auctions by key word.
+ * May be configured with init parameters: <dl>
+ * <dt>appid</dt><dd>The eBay application ID to use</dd>
+ * </dl>
+ * Each request examines the following request parameters:<dl>
+ * <dt>items</dt><dd>The keyword to search for</dd>
+ * </dl>
+ */
+public class AbstractRestServlet extends HttpServlet
+{
+    protected final static String __DEFAULT_APPID = "Webtide81-adf4-4f0a-ad58-d91e41bbe85";
+    protected final static String STYLE = 
+        "<style type='text/css'>"+
+        "  img.thumb:hover {height:50px}"+
+        "  img.thumb {vertical-align:text-top}"+
+        "  span.red {color: #ff0000}"+
+        "  span.green {color: #00ff00}"+
+        "  iframe {border: 0px}"+
+        "</style>";
+
+    protected final static String ITEMS_PARAM = "items";
+    protected final static String APPID_PARAM = "appid";
+
+    protected String _appid;
+
+    public void init(ServletConfig servletConfig) throws ServletException
+    {
+        if (servletConfig.getInitParameter(APPID_PARAM) == null)
+            _appid = __DEFAULT_APPID;
+        else
+            _appid = servletConfig.getInitParameter(APPID_PARAM);
+    }
+    
+    protected String restURL(String item) 
+    {
+        try
+        {
+            return ("http://open.api.ebay.com/shopping?MaxEntries=3&appid=" + _appid + 
+                    "&version=573&siteid=0&callname=FindItems&responseencoding=JSON&QueryKeywords=" + 
+                    URLEncoder.encode(item,"UTF-8"));
+        }
+        catch(Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    protected String generateThumbs(Queue<Map<String,String>> results)
+    {
+        StringBuilder thumbs = new StringBuilder();
+        for (Map<String, String> m : results)
+        {
+            if (!m.containsKey("GalleryURL"))
+                continue;
+                
+            thumbs.append("<a href=\""+m.get("ViewItemURLForNaturalSearch")+"\">");
+            thumbs.append("<img class='thumb' border='1px' height='25px'"+
+                        " src='"+m.get("GalleryURL")+"'"+
+                        " title='"+m.get("Title")+"'"+
+                        "/>");
+            thumbs.append("</a>&nbsp;");
+        }
+        return thumbs.toString();
+    }
+
+    protected String ms(long nano)
+    {
+        BigDecimal dec = new BigDecimal(nano);
+        return dec.divide(new BigDecimal(1000000L)).setScale(1,RoundingMode.UP).toString();
+    }
+    
+    protected int width(long nano)
+    {
+        int w=(int)((nano+999999L)/5000000L);
+        if (w==0)
+            w=2;
+        return w;
+    }
+    
+    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        doGet(request, response);
+    }
+
+}
diff --git a/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java
new file mode 100644
index 0000000..4438559
--- /dev/null
+++ b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.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.example.asyncrest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.util.ajax.JSON;
+
+/**
+ * Servlet implementation class AsyncRESTServlet.
+ * Enquires ebay REST service for auctions by key word.
+ * May be configured with init parameters: <dl>
+ * <dt>appid</dt><dd>The eBay application ID to use</dd>
+ * </dl>
+ * Each request examines the following request parameters:<dl>
+ * <dt>items</dt><dd>The keyword to search for</dd>
+ * </dl>
+ */
+public class AsyncRestServlet extends AbstractRestServlet
+{
+    final static String RESULTS_ATTR = "org.eclipse.jetty.demo.client";
+    final static String DURATION_ATTR = "org.eclipse.jetty.demo.duration";
+    final static String START_ATTR = "org.eclispe.jetty.demo.start";
+
+    HttpClient _client;
+
+    public void init(ServletConfig servletConfig) throws ServletException
+    {
+        super.init(servletConfig);
+        
+        _client = new HttpClient();
+        _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
+
+        try
+        {
+            _client.start();
+        }
+        catch (Exception e)
+        {
+            throw new ServletException(e);
+        }
+    }
+
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        Long start=System.nanoTime();
+        
+        // Do we have results yet?
+        Queue<Map<String, String>> results = (Queue<Map<String, String>>) request.getAttribute(RESULTS_ATTR);
+        
+        // If no results, this must be the first dispatch, so send the REST request(s)
+        if (results==null)
+        {
+            // define results data structures
+            final Queue<Map<String, String>> resultsQueue = new ConcurrentLinkedQueue<Map<String,String>>();
+            request.setAttribute(RESULTS_ATTR, results=resultsQueue);
+            
+            // suspend the request
+            // This is done before scheduling async handling to avoid race of 
+            // dispatch before startAsync!
+            final AsyncContext async = request.startAsync();
+            async.setTimeout(30000);
+
+            // extract keywords to search for
+            String[] keywords=request.getParameter(ITEMS_PARAM).split(",");
+            final AtomicInteger outstanding=new AtomicInteger(keywords.length);
+            
+            // Send request each keyword
+            for (final String item:keywords)
+            {
+                _client.send(
+                        new AsyncRestRequest(item)
+                        {
+                            void onAuctionFound(Map<String,String> auction)
+                            {
+                                resultsQueue.add(auction);
+                            }
+                            void onComplete()
+                            {
+                                if (outstanding.decrementAndGet()<=0)
+                                    async.dispatch();
+                            }
+                        });
+            }
+            
+            // save timing info and return
+            request.setAttribute(START_ATTR, start);
+            request.setAttribute(DURATION_ATTR, new Long(System.nanoTime() - start));
+
+            return;
+        }
+
+        // We have results!
+        
+        // Generate the response
+        String thumbs = generateThumbs(results);
+        
+        response.setContentType("text/html");
+        PrintWriter out = response.getWriter();
+        out.println("<html><head>");
+        out.println(STYLE);
+        out.println("</head><body><small>");
+
+        long initial = (Long) request.getAttribute(DURATION_ATTR);
+        long start0 = (Long) request.getAttribute(START_ATTR);
+
+        long now = System.nanoTime();
+        long total=now-start0;
+        long generate=now-start;
+        long thread=initial+generate;
+        
+        out.print("<b>Asynchronous: "+request.getParameter(ITEMS_PARAM)+"</b><br/>");
+        out.print("Total Time: "+ms(total)+"ms<br/>");
+
+        out.print("Thread held (<span class='red'>red</span>): "+ms(thread)+"ms (" + ms(initial) + " initial + " + ms(generate) + " generate )<br/>");
+        out.print("Async wait (<span class='green'>green</span>): "+ms(total-thread)+"ms<br/>");
+        
+        out.println("<img border='0px' src='asyncrest/red.png'   height='20px' width='"+width(initial)+"px'>"+
+                    "<img border='0px' src='asyncrest/green.png' height='20px' width='"+width(total-thread)+"px'>"+
+                    "<img border='0px' src='asyncrest/red.png'   height='20px' width='"+width(generate)+"px'>");
+        
+        out.println("<hr />");
+        out.println(thumbs);
+        out.println("</small>");
+        out.println("</body></html>");
+        out.close();
+    }
+
+    private abstract class AsyncRestRequest extends ContentExchange
+    {
+        AsyncRestRequest(final String item)
+        {
+            // send the exchange
+            setMethod("GET");
+            setURL(restURL(item));   
+        }
+        
+        abstract void onAuctionFound(Map<String,String> details);
+        abstract void onComplete();
+        
+        protected void onResponseComplete() throws IOException
+        {
+            // extract auctions from the results
+            Map<String,?> query = (Map<String,?>) JSON.parse(this.getResponseContent());
+            Object[] auctions = (Object[]) query.get("Item");
+            if (auctions != null)
+            {
+                for (Object o : auctions)
+                    onAuctionFound((Map<String,String>)o);
+            }
+
+            onComplete();
+        }
+
+        /* ------------------------------------------------------------ */
+        protected void onConnectionFailed(Throwable ex)
+        {
+            getServletContext().log("onConnectionFailed: ",ex);
+            onComplete();
+        }
+
+        /* ------------------------------------------------------------ */
+        protected void onException(Throwable ex)
+        {
+            getServletContext().log("onConnectionFailed: ",ex);
+            onComplete();
+        }
+
+        /* ------------------------------------------------------------ */
+        protected void onExpire()
+        {
+            getServletContext().log("onConnectionFailed: expired");
+            onComplete();
+        }
+    }
+
+    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        doGet(request, response);
+    }
+
+}
diff --git a/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java
new file mode 100644
index 0000000..b6af591
--- /dev/null
+++ b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.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.example.asyncrest;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.util.ajax.JSON;
+
+/**
+ * Servlet implementation class SerialRestServlet
+ */
+public class SerialRestServlet extends AbstractRestServlet
+{   
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        long start = System.nanoTime();
+        
+
+        String[] keywords=request.getParameter(ITEMS_PARAM).split(",");
+        Queue<Map<String,String>> results = new LinkedList<Map<String,String>>();
+        
+        // make all requests serially
+        for (String itemName : keywords)
+        {
+            URL url = new URL(restURL(itemName));
+            
+            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
+            connection.setRequestMethod("GET");
+            
+            Map query = (Map)JSON.parse(new BufferedReader(new InputStreamReader(connection.getInputStream())));
+            Object[] auctions = (Object[]) query.get("Item");
+            if (auctions != null)
+            {
+                for (Object o : auctions)
+                    results.add((Map) o);
+            }
+        }
+        
+
+        // Generate the response
+        String thumbs=generateThumbs(results);
+        
+        response.setContentType("text/html");
+        PrintWriter out = response.getWriter();
+        out.println("<html><head>");
+        out.println(STYLE);
+        out.println("</head><body><small>");
+
+        long now = System.nanoTime();
+        long total=now-start;
+
+        out.print("<b>Blocking: "+request.getParameter(ITEMS_PARAM)+"</b><br/>");
+        out.print("Total Time: "+ms(total)+"ms<br/>");
+        out.print("Thread held (<span class='red'>red</span>): "+ms(total)+"ms<br/>");
+        
+        out.println("<img border='0px' src='asyncrest/red.png'   height='20px' width='"+width(total)+"px'>");
+        
+        out.println("<hr />");
+        out.println(thumbs);
+        out.println("</small>");
+        out.println("</body></html>");
+        out.close();
+        
+        
+
+    }
+
+    /**
+     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
+     *      response)
+     */
+    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        doGet(request, response);
+    }
+
+}
diff --git a/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest.html b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest.html
new file mode 100644
index 0000000..f92f7f6
--- /dev/null
+++ b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest.html
@@ -0,0 +1,38 @@
+<html>
+ <head>
+  <style type='text/css'>
+    iframe {border: 0px}
+    table, tr, td {border: 0px}
+  </style>
+</head>
+<body>
+<h1>Blocking vs Asynchronous REST</h1>
+<p>
+This demo calls the EBay WS API both synchronously and asynchronously,
+to obtain items matching each of the keywords passed on the query
+string.  The time the request thread is head is displayed for both.
+</p>
+
+<table width='100%'>
+	
+<tr>
+<td>
+  <iframe id="f1" width='100%' height='175px' src="testSerial?items=kayak"></iframe>
+</td>
+<td>
+  <iframe id="f3" width='100%' height='175px' src="testSerial?items=mouse,beer,gnome"></iframe>
+</td>
+</tr>
+ 
+<tr>
+<td>
+  <iframe id="f2" width='100%' height='175px' src="testAsync?items=kayak"/></iframe>
+</td>
+<td>
+  <iframe id="f4" width='100%' height='175px' src="testAsync?items=mouse,beer,gnome"/></iframe>
+</td>
+</tr>
+
+</table>
+</body>
+</html>
diff --git a/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/green.png b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/green.png
new file mode 100644
index 0000000..d0fb842
--- /dev/null
+++ b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/green.png
Binary files differ
diff --git a/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/red.png b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/red.png
new file mode 100644
index 0000000..f2a79a0
--- /dev/null
+++ b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/red.png
Binary files differ
diff --git a/example-async-rest/async-rest-jar/src/main/resources/META-INF/web-fragment.xml b/example-async-rest/async-rest-jar/src/main/resources/META-INF/web-fragment.xml
new file mode 100644
index 0000000..9876d99
--- /dev/null
+++ b/example-async-rest/async-rest-jar/src/main/resources/META-INF/web-fragment.xml
@@ -0,0 +1,22 @@
+<web-fragment>
+	<servlet>
+		<display-name>SerialRestServlet</display-name>
+		<servlet-name>SerialRestServlet</servlet-name>
+		<servlet-class>org.eclipse.jetty.example.asyncrest.SerialRestServlet</servlet-class>
+	</servlet>
+	<servlet-mapping>
+		<servlet-name>SerialRestServlet</servlet-name>
+		<url-pattern>/testSerial</url-pattern>
+	</servlet-mapping>
+	
+	<servlet>
+		<display-name>AsyncRestServlet</display-name>
+		<servlet-name>AsyncRestServlet</servlet-name>
+		<servlet-class>org.eclipse.jetty.example.asyncrest.AsyncRestServlet</servlet-class>
+		<async-supported>true</async-supported>
+	</servlet>
+	<servlet-mapping>
+		<servlet-name>AsyncRestServlet</servlet-name>
+		<url-pattern>/testAsync</url-pattern>
+	</servlet-mapping>	
+</web-fragment>
\ No newline at end of file
diff --git a/example-async-rest/async-rest-webapp/pom.xml b/example-async-rest/async-rest-webapp/pom.xml
new file mode 100644
index 0000000..3cf6a5c
--- /dev/null
+++ b/example-async-rest/async-rest-webapp/pom.xml
@@ -0,0 +1,34 @@
+<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>example-async-rest</artifactId>
+    <version>8.1.19-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.eclipse.jetty.example-async-rest</groupId>
+  <artifactId>example-async-rest-webapp</artifactId>
+  <name>Example Async Rest :: Webapp</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <packaging>war</packaging>
+  <build>
+    <finalName>async-rest</finalName>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty.example-async-rest</groupId>
+      <artifactId>example-async-rest-jar</artifactId>
+      <version>${project.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.orbit</groupId>
+         <artifactId>javax.servlet</artifactId>
+         <scope>provided</scope>
+       </dependency>
+  </dependencies>
+</project>
diff --git a/example-async-rest/async-rest-webapp/src/main/webapp/META-INF/MANIFEST.MF b/example-async-rest/async-rest-webapp/src/main/webapp/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/example-async-rest/async-rest-webapp/src/main/webapp/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0

+Class-Path: 

+

diff --git a/example-async-rest/async-rest-webapp/src/main/webapp/WEB-INF/web.xml b/example-async-rest/async-rest-webapp/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..8916bdb
--- /dev/null
+++ b/example-async-rest/async-rest-webapp/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<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">
+
+	<display-name>Async REST Webservice Example</display-name>
+
+</web-app>
diff --git a/example-async-rest/async-rest-webapp/src/main/webapp/index.html b/example-async-rest/async-rest-webapp/src/main/webapp/index.html
new file mode 100644
index 0000000..f92f7f6
--- /dev/null
+++ b/example-async-rest/async-rest-webapp/src/main/webapp/index.html
@@ -0,0 +1,38 @@
+<html>
+ <head>
+  <style type='text/css'>
+    iframe {border: 0px}
+    table, tr, td {border: 0px}
+  </style>
+</head>
+<body>
+<h1>Blocking vs Asynchronous REST</h1>
+<p>
+This demo calls the EBay WS API both synchronously and asynchronously,
+to obtain items matching each of the keywords passed on the query
+string.  The time the request thread is head is displayed for both.
+</p>
+
+<table width='100%'>
+	
+<tr>
+<td>
+  <iframe id="f1" width='100%' height='175px' src="testSerial?items=kayak"></iframe>
+</td>
+<td>
+  <iframe id="f3" width='100%' height='175px' src="testSerial?items=mouse,beer,gnome"></iframe>
+</td>
+</tr>
+ 
+<tr>
+<td>
+  <iframe id="f2" width='100%' height='175px' src="testAsync?items=kayak"/></iframe>
+</td>
+<td>
+  <iframe id="f4" width='100%' height='175px' src="testAsync?items=mouse,beer,gnome"/></iframe>
+</td>
+</tr>
+
+</table>
+</body>
+</html>
diff --git a/example-async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java b/example-async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java
new file mode 100644
index 0000000..bb5ded0
--- /dev/null
+++ b/example-async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.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.example.asyncrest;
+
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+public class DemoServer
+{
+    public static void main(String[] args)
+        throws Exception
+    {
+        String jetty_home = System.getProperty("jetty.home",".");
+
+        Server server = new Server();
+        
+        Connector connector=new SelectChannelConnector();
+        connector.setPort(Integer.getInteger("jetty.port",8080).intValue());
+        server.setConnectors(new Connector[]{connector});
+        
+        WebAppContext webapp = new WebAppContext();
+        webapp.setContextPath("/");
+        webapp.setWar(jetty_home+"/target/example-async-rest-webapp-8.0.0.M0-SNAPSHOT");
+        
+        server.setHandler(webapp);
+        
+        server.start();
+        server.join();
+    }
+}
diff --git a/example-async-rest/pom.xml b/example-async-rest/pom.xml
new file mode 100644
index 0000000..df9baaf
--- /dev/null
+++ b/example-async-rest/pom.xml
@@ -0,0 +1,17 @@
+<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>8.1.19-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.eclipse.jetty</groupId>
+  <artifactId>example-async-rest</artifactId>
+  <packaging>pom</packaging>
+  <name>Example Async Rest</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <modules>
+    <module>async-rest-jar</module>
+    <module>async-rest-webapp</module>
+  </modules>
+</project>
diff --git a/example-jetty-embedded/pom.xml b/example-jetty-embedded/pom.xml
index c594d0a..7630c72 100644
--- a/example-jetty-embedded/pom.xml
+++ b/example-jetty-embedded/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>example-jetty-embedded</artifactId>
diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java
index 76a8bc2..2e72770 100644
--- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java
+++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java
@@ -149,7 +149,7 @@
         webapp_provider.setDefaultsDescriptor(jetty_home + "/etc/webdefault.xml");
         webapp_provider.setContextXmlDir(jetty_home + "/contexts");
         deployer.addAppProvider(webapp_provider);
-        
+
         HashLoginService login = new HashLoginService();
         login.setName("Test Realm");
         login.setConfig(jetty_home + "/etc/realm.properties");
diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java
index 1104f9a..bdc8057 100644
--- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java
+++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java
@@ -74,5 +74,4 @@
         System.err.println(server.dump());
         server.join();
     }
-
 }
diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java
index 192d7f2..5414ddf 100644
--- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java
+++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java
@@ -34,7 +34,11 @@
         server.setConnectors(new Connector[]
         { connector });
 
-        String war = args.length > 0?args[0]: "../test-jetty-webapp/target/test-jetty-webapp-" + Server.getVersion();
+
+        //If you're running this from inside Eclipse, then Server.getVersion will not provide
+        //the correct number as there is no manifest. Use the command line instead to provide the path to the
+        //test webapp
+        String war = args.length > 0?args[0]: "../test-jetty-webapp/target/test-jetty-webapp-"+Server.getVersion();
         String path = args.length > 1?args[1]:"/";
 
         System.err.println(war + " " + path);
@@ -42,6 +46,15 @@
         WebAppContext webapp = new WebAppContext();
         webapp.setContextPath(path);
         webapp.setWar(war);
+        
+        //If the webapp contains security constraints, you will need to configure a LoginService
+        if (war.contains("test-jetty-webapp"))
+        {
+            org.eclipse.jetty.security.HashLoginService loginService = new org.eclipse.jetty.security.HashLoginService();
+            loginService.setName("Test Realm");
+            loginService.setConfig("src/test/resources/realm.properties");
+            webapp.getSecurityHandler().setLoginService(loginService);
+        }
 
         server.setHandler(webapp);
 
diff --git a/jetty-aggregate/jetty-all-server/pom.xml b/jetty-aggregate/jetty-all-server/pom.xml
index 7bf09c0..9ebcc1e 100644
--- a/jetty-aggregate/jetty-all-server/pom.xml
+++ b/jetty-aggregate/jetty-all-server/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.aggregate</groupId>
         <artifactId>jetty-aggregate-project</artifactId>
-        <version>7.6.19-SNAPSHOT</version>
+        <version>8.1.19-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jetty-all-server</artifactId>
@@ -79,10 +79,11 @@
                     <instructions>
                         <Import-Package>
                             !org.eclipse.jetty*,
-                            com.sun.org.apache.commons.logging;version="[2.1,3)";split="glassfish";resolution:=optional,
                             javax.annotation;version="1.0.0";resolution:=optional,
-                            javax.servlet;version="2.5.0",
-                            javax.servlet.http;version="2.5.0",
+                            javax.servlet;version="2.6.0",
+                            javax.servlet.annotation;version="2.6.0",
+                            javax.servlet.descriptor;version="2.6.0",
+                            javax.servlet.http;version="2.6.0",
                             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,
diff --git a/jetty-aggregate/jetty-all/pom.xml b/jetty-aggregate/jetty-all/pom.xml
index 6e77e04..d326cff 100644
--- a/jetty-aggregate/jetty-all/pom.xml
+++ b/jetty-aggregate/jetty-all/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.eclipse.jetty.aggregate</groupId>
     <artifactId>jetty-aggregate-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-all</artifactId>
diff --git a/jetty-aggregate/jetty-client/pom.xml b/jetty-aggregate/jetty-client/pom.xml
index b6614b8..1f184bf 100644
--- a/jetty-aggregate/jetty-client/pom.xml
+++ b/jetty-aggregate/jetty-client/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.aggregate</groupId>
     <artifactId>jetty-aggregate-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-client</artifactId>
diff --git a/jetty-aggregate/jetty-plus/pom.xml b/jetty-aggregate/jetty-plus/pom.xml
index 5f9e9dc..8958c9a 100644
--- a/jetty-aggregate/jetty-plus/pom.xml
+++ b/jetty-aggregate/jetty-plus/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.aggregate</groupId>
     <artifactId>jetty-aggregate-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-plus</artifactId>
diff --git a/jetty-aggregate/jetty-server/pom.xml b/jetty-aggregate/jetty-server/pom.xml
index f4f230a..710ebb1 100644
--- a/jetty-aggregate/jetty-server/pom.xml
+++ b/jetty-aggregate/jetty-server/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.aggregate</groupId>
     <artifactId>jetty-aggregate-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-server</artifactId>
diff --git a/jetty-aggregate/jetty-servlet/pom.xml b/jetty-aggregate/jetty-servlet/pom.xml
index a275eec..bdcab66 100644
--- a/jetty-aggregate/jetty-servlet/pom.xml
+++ b/jetty-aggregate/jetty-servlet/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.aggregate</groupId>
     <artifactId>jetty-aggregate-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-servlet</artifactId>
diff --git a/jetty-aggregate/jetty-webapp/pom.xml b/jetty-aggregate/jetty-webapp/pom.xml
index ccefbe8..0765356 100644
--- a/jetty-aggregate/jetty-webapp/pom.xml
+++ b/jetty-aggregate/jetty-webapp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.aggregate</groupId>
     <artifactId>jetty-aggregate-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-webapp</artifactId>
diff --git a/jetty-aggregate/jetty-websocket/pom.xml b/jetty-aggregate/jetty-websocket/pom.xml
index b51b437..b56eae1 100644
--- a/jetty-aggregate/jetty-websocket/pom.xml
+++ b/jetty-aggregate/jetty-websocket/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.aggregate</groupId>
     <artifactId>jetty-aggregate-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-websocket</artifactId>
diff --git a/jetty-aggregate/pom.xml b/jetty-aggregate/pom.xml
index 3f1e3e0..afed546 100644
--- a/jetty-aggregate/pom.xml
+++ b/jetty-aggregate/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <groupId>org.eclipse.jetty.aggregate</groupId>
   <artifactId>jetty-aggregate-project</artifactId>
diff --git a/jetty-ajp/pom.xml b/jetty-ajp/pom.xml
index 2b866e0..1347258 100644
--- a/jetty-ajp/pom.xml
+++ b/jetty-ajp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-ajp</artifactId>
@@ -22,6 +22,11 @@
             <goals>
               <goal>manifest</goal>
             </goals>
+            <configuration>
+              <instructions>
+                <Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
+              </instructions>
+            </configuration>
            </execution>
         </executions>
       </plugin>
diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml
index dd7fb3b..9b17371 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-annotations</artifactId>
@@ -15,6 +15,23 @@
   <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>
@@ -26,7 +43,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>javax.servlet.*;version="[2.5,3.0)",*</Import-Package>
+                <Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
               </instructions>
             </configuration>
           </execution>
diff --git a/jetty-annotations/src/main/config/etc/jetty-annotations.xml b/jetty-annotations/src/main/config/etc/jetty-annotations.xml
new file mode 100644
index 0000000..7aa719d
--- /dev/null
+++ b/jetty-annotations/src/main/config/etc/jetty-annotations.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+    <!-- ================================================================= -->
+    <!-- Enable annotations - configure deployment steps for every web app -->
+    <!-- ================================================================= -->
+    <Call name="setAttribute">
+      <Arg>org.eclipse.jetty.webapp.configuration</Arg>
+      <Arg>
+          <Array type="java.lang.String">
+               <Item>org.eclipse.jetty.webapp.WebInfConfiguration</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.annotations.AnnotationConfiguration</Item>
+               <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
+          </Array>
+      </Arg>
+    </Call>
+
+</Configure>
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractDiscoverableAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractDiscoverableAnnotationHandler.java
index abd99bb..afdc266 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractDiscoverableAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractDiscoverableAnnotationHandler.java
@@ -22,7 +22,7 @@
 import java.util.List;
 
 import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
-import org.eclipse.jetty.annotations.AnnotationParser.Value;
+import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.webapp.DiscoveredAnnotation;
 import org.eclipse.jetty.webapp.WebAppContext;
 
@@ -34,13 +34,32 @@
 public abstract class AbstractDiscoverableAnnotationHandler implements DiscoverableAnnotationHandler
 {
     protected WebAppContext _context;
-    protected List<DiscoveredAnnotation> _annotations = new ArrayList<DiscoveredAnnotation>();
+    protected List<DiscoveredAnnotation> _annotations; 
+    protected Resource _resource;
     
     public AbstractDiscoverableAnnotationHandler(WebAppContext context)
     {
+        this(context, null);
+    }
+    
+    public AbstractDiscoverableAnnotationHandler(WebAppContext  context, List<DiscoveredAnnotation> list)
+    {
         _context = context;
+        if (list == null)
+            _annotations = new ArrayList<DiscoveredAnnotation>();
+        else
+            _annotations = list;
     }
 
+    public Resource getResource()
+    {
+        return _resource;
+    }
+    
+    public void setResource(Resource resource)
+    {
+        _resource = resource;
+    }
     
     public List<DiscoveredAnnotation> getAnnotationList ()
     {
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 2b2dfae..d24cb02 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
@@ -18,8 +18,26 @@
 
 package org.eclipse.jetty.annotations;
 
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ServiceLoader;
+
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.annotation.HandlesTypes;
+
+import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
+import org.eclipse.jetty.plus.annotation.ContainerInitializer;
+import org.eclipse.jetty.util.MultiMap;
+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.webapp.AbstractConfiguration;
+import org.eclipse.jetty.webapp.FragmentDescriptor;
+import org.eclipse.jetty.webapp.MetaDataComplete;
 import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.webapp.WebDescriptor;
 
 /**
  * Configuration for Annotations
@@ -28,15 +46,478 @@
  */
 public class AnnotationConfiguration extends AbstractConfiguration
 {
+    private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class);
+    public static final String CLASS_INHERITANCE_MAP  = "org.eclipse.jetty.classInheritanceMap";    
+    public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers";
+    public static final String CONTAINER_INITIALIZER_LISTENER = "org.eclipse.jetty.containerInitializerListener";
+  
+    
+    protected List<DiscoverableAnnotationHandler> _discoverableAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
+    protected ClassInheritanceHandler _classInheritanceHandler;
+    protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
+   
+    
+    @Override
+    public void preConfigure(final WebAppContext context) throws Exception
+    {
+    }
+   
+    @Override
+    public void deconfigure(WebAppContext context) throws Exception
+    {
+        context.removeAttribute(CLASS_INHERITANCE_MAP);
+        context.removeAttribute(CONTAINER_INITIALIZERS);
+        ServletContainerInitializerListener listener = (ServletContainerInitializerListener)context.getAttribute(CONTAINER_INITIALIZER_LISTENER);
+        if (listener != null)
+        {
+            context.removeBean(listener);
+            context.removeAttribute(CONTAINER_INITIALIZER_LISTENER);
+        }
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.webapp.AbstractConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
+     */
     @Override
     public void configure(WebAppContext context) throws Exception
-    {      
+    {
+       boolean metadataComplete = context.getMetaData().isMetaDataComplete();
        context.addDecorator(new AnnotationDecorator(context));   
+      
+       
+       //Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any
+       AnnotationParser parser = null;
+       if (!metadataComplete)
+       {
+           //If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
+           if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
+           {
+               _discoverableAnnotationHandlers.add(new WebServletAnnotationHandler(context));
+               _discoverableAnnotationHandlers.add(new WebFilterAnnotationHandler(context));
+               _discoverableAnnotationHandlers.add(new WebListenerAnnotationHandler(context));
+           }
+       }
+       else
+           if (LOG.isDebugEnabled()) LOG.debug("Metadata-complete==true,  not processing discoverable servlet annotations for context "+context);
+       
+       
+       
+       //Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the
+       //classes so we can call their onStartup() methods correctly
+       createServletContainerInitializerAnnotationHandlers(context, getNonExcludedInitializers(context));
+       
+       if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
+       {           
+           parser = createAnnotationParser();
+           if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered());
+           parseContainerPath(context, parser);
+           //email from Rajiv Mordani jsrs 315 7 April 2010
+           //    If there is a <others/> then the ordering should be 
+           //          WEB-INF/classes the order of the declared elements + others.
+           //    In case there is no others then it is 
+           //          WEB-INF/classes + order of the elements.
+           parseWebInfClasses(context, parser);
+           parseWebInfLib (context, parser);
+           
+           for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
+               context.getMetaData().addDiscoveredAnnotations(((AbstractDiscoverableAnnotationHandler)h).getAnnotationList());      
+       }
+    }
+    
+    
+    
+    /** 
+     * @see org.eclipse.jetty.webapp.AbstractConfiguration#postConfigure(org.eclipse.jetty.webapp.WebAppContext)
+     */
+    @Override
+    public void postConfigure(WebAppContext context) throws Exception
+    {
+        MultiMap map = (MultiMap)context.getAttribute(CLASS_INHERITANCE_MAP);
+        if (map != null)
+            map.clear();
+        
+        context.removeAttribute(CLASS_INHERITANCE_MAP);
+        
+        List<ContainerInitializer> initializers = (List<ContainerInitializer>)context.getAttribute(CONTAINER_INITIALIZERS);
+        if (initializers != null)
+            initializers.clear();
+        if (_discoverableAnnotationHandlers != null)
+            _discoverableAnnotationHandlers.clear();
+      
+        _classInheritanceHandler = null;
+        if (_containerInitializerAnnotationHandlers != null)
+            _containerInitializerAnnotationHandlers.clear();
+  
+        super.postConfigure(context);
     }
 
+    /**
+     * @return a new AnnotationParser. This method can be overridden to use a different impleemntation of
+     * the AnnotationParser. Note that this is considered internal API.
+     */
+    protected AnnotationParser createAnnotationParser()
+    {
+        return new AnnotationParser();
+    }
+    
+    /** 
+     * @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));   
     }
+    
+    
+    
+    /**
+     * @param context
+     * @param scis
+     * @throws Exception
+     */
+    public void createServletContainerInitializerAnnotationHandlers (WebAppContext context, List<ServletContainerInitializer> scis)
+    throws Exception
+    {
+        
+        if (scis == null || scis.isEmpty())
+            return; // nothing to do
+        
+
+        List<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
+        context.setAttribute(CONTAINER_INITIALIZERS, initializers);
+
+        for (ServletContainerInitializer service : scis)
+        {
+            HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class);
+            ContainerInitializer initializer = new ContainerInitializer();
+            initializer.setTarget(service);
+            initializers.add(initializer);
+            if (annotation != null)
+            {
+                //There is a HandlesTypes annotation on the on the ServletContainerInitializer
+                Class[] classes = annotation.value();
+                if (classes != null)
+                {
+                    initializer.setInterestedTypes(classes);
+
+                    //If we haven't already done so, we need to register a handler that will
+                    //process the whole class hierarchy to satisfy the ServletContainerInitializer
+                    if (context.getAttribute(CLASS_INHERITANCE_MAP) == null)
+                    {
+                        MultiMap map = new MultiMap();
+                        context.setAttribute(CLASS_INHERITANCE_MAP, map);
+                        _classInheritanceHandler = new ClassInheritanceHandler(map);
+                    }
+                                     
+                    for (Class c: classes)
+                    {
+                        //The value of one of the HandlesTypes classes is actually an Annotation itself so
+                        //register a handler for it
+                        if (c.isAnnotation())
+                        {
+                            if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName());
+                           
+                           _containerInitializerAnnotationHandlers.add(new ContainerInitializerAnnotationHandler(initializer, c));
+                        }
+                    }
+                }
+                else
+                    if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass());
+            }
+            else
+                if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
+        }
+        
+
+        //add a bean which will call the servletcontainerinitializers when appropriate
+        ServletContainerInitializerListener listener = (ServletContainerInitializerListener)context.getAttribute(CONTAINER_INITIALIZER_LISTENER);
+        if (listener != null)
+            throw new IllegalStateException("ServletContainerInitializerListener already exists");
+        listener = new ServletContainerInitializerListener();
+        listener.setWebAppContext(context);
+        context.setAttribute(CONTAINER_INITIALIZER_LISTENER, listener);
+        context.addBean(listener, true);
+    }
+
+    
+    
+    /**
+     * 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 orderedJars
+     * @param service
+     * @return
+     */
+    public boolean isFromExcludedJar (WebAppContext context, ServletContainerInitializer service)
+    throws Exception
+    {
+        List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars();
+
+        //If no ordering, nothing is excluded
+        if (context.getMetaData().getOrdering() == null)
+            return false;
+
+        //there is an ordering, but there are no jars resulting from the ordering, everything excluded
+        if (orderedJars.isEmpty())
+            return true; 
+
+        String loadingJarName = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class").toString();
+
+        int i = loadingJarName.indexOf(".jar");  
+        if (i < 0)
+            return false; //not from a jar therefore not from WEB-INF so not excludable
+
+        loadingJarName = loadingJarName.substring(0,i+4);
+        loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName);
+        URI loadingJarURI = Resource.newResource(loadingJarName).getURI();
+        boolean found = false;
+        Iterator<Resource> itor = orderedJars.iterator();
+        while (!found && itor.hasNext())
+        {
+            Resource r = itor.next();         
+            found = r.getURI().equals(loadingJarURI);
+        }
+
+        return !found;
+    }
+   
+    
+    
+    /**
+     * @param context
+     * @return
+     * @throws Exception
+     */
+    public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
+    throws Exception
+    {
+        List<ServletContainerInitializer> nonExcludedInitializers = new ArrayList<ServletContainerInitializer>();
+        
+        //We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect
+        ServiceLoader<ServletContainerInitializer> loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class, context.getClassLoader());
+       
+        if (loadedInitializers != null)
+        {  
+            for (ServletContainerInitializer service : loadedInitializers)
+            {
+                if (!isFromExcludedJar(context, service))
+                    nonExcludedInitializers.add(service);
+            }
+        }
+        return nonExcludedInitializers;
+    }
+    
+    
+    
+    
+    /**
+     * Scan jars on container path.
+     * 
+     * @param context
+     * @param parser
+     * @throws Exception
+     */
+    public void parseContainerPath (final WebAppContext context, final AnnotationParser parser)
+    throws Exception
+    {
+        //if no pattern for the container path is defined, then by default scan NOTHING
+        LOG.debug("Scanning container jars");
+        
+        //always parse for discoverable annotations as well as class hierarchy and servletcontainerinitializer related annotations
+        parser.clearHandlers();
+        for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
+        {
+            if (h instanceof AbstractDiscoverableAnnotationHandler)
+                ((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
+        }
+        parser.registerHandlers(_discoverableAnnotationHandlers);
+        parser.registerHandler(_classInheritanceHandler);
+        parser.registerHandlers(_containerInitializerAnnotationHandlers);
+        
+        //Convert from Resource to URI
+        ArrayList<URI> containerUris = new ArrayList<URI>();
+        for (Resource r : context.getMetaData().getOrderedContainerJars())
+        {
+            URI uri = r.getURI();
+                containerUris.add(uri);          
+        }
+        
+        parser.parse (containerUris.toArray(new URI[containerUris.size()]),
+                new ClassNameResolver ()
+                {
+                    public boolean isExcluded (String name)
+                    {
+                        if (context.isSystemClass(name)) return false;
+                        if (context.isServerClass(name)) return true;
+                        return false;
+                    }
+
+                    public boolean shouldOverride (String name)
+                    { 
+                        //looking at system classpath
+                        if (context.isParentLoaderPriority())
+                            return true;
+                        return false;
+                    }
+                });   
+        
+         
+    }
+    
+    
+    /**
+     * Scan jars in WEB-INF/lib
+     * 
+     * @param context
+     * @param parser
+     * @throws Exception
+     */
+    public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser)
+    throws Exception
+    {  
+        List<FragmentDescriptor> frags = context.getMetaData().getFragments();
+        
+        //email from Rajiv Mordani jsrs 315 7 April 2010
+        //jars that do not have a web-fragment.xml are still considered fragments
+        //they have to participate in the ordering
+        ArrayList<URI> webInfUris = new ArrayList<URI>();
+        
+        List<Resource> jars = context.getMetaData().getOrderedWebInfJars();
+        
+        //No ordering just use the jars in any order
+        if (jars == null || jars.isEmpty())
+            jars = context.getMetaData().getWebInfJars();
+   
+        for (Resource r : jars)
+        {          
+            //for each jar, we decide which set of annotations we need to parse for
+            parser.clearHandlers();
+            URI uri  = r.getURI();
+            FragmentDescriptor f = getFragmentFromJar(r, frags);
+           
+            //if its from a fragment jar that is metadata complete, we should skip scanning for @webservlet etc
+            // but yet we still need to do the scanning for the classes on behalf of  the servletcontainerinitializers
+            //if a jar has no web-fragment.xml we scan it (because it is not excluded by the ordering)
+            //or if it has a fragment we scan it if it is not metadata complete
+            if (f == null || !isMetaDataComplete(f) || _classInheritanceHandler != null ||  !_containerInitializerAnnotationHandlers.isEmpty())
+            {
+                //register the classinheritance handler if there is one
+                parser.registerHandler(_classInheritanceHandler);
+                
+                //register the handlers for the @HandlesTypes values that are themselves annotations if there are any
+                parser.registerHandlers(_containerInitializerAnnotationHandlers);
+                
+                //only register the discoverable annotation handlers if this fragment is not metadata complete, or has no fragment descriptor
+                if (f == null || !isMetaDataComplete(f))
+                {
+                    for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
+                    {
+                        if (h instanceof AbstractDiscoverableAnnotationHandler)
+                            ((AbstractDiscoverableAnnotationHandler)h).setResource(r);
+                    }
+                    parser.registerHandlers(_discoverableAnnotationHandlers);
+                }
+
+                parser.parse(uri, 
+                             new ClassNameResolver()
+                             {
+                                 public boolean isExcluded (String name)
+                                 {    
+                                     if (context.isSystemClass(name)) return true;
+                                     if (context.isServerClass(name)) return false;
+                                     return false;
+                                 }
+
+                                 public boolean shouldOverride (String name)
+                                 {
+                                    //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
+                                    if (context.isParentLoaderPriority())
+                                        return false;
+                                    return true;
+                                 }
+                             });   
+            }
+        }
+    }
+     
+    /**
+     * Scan classes in WEB-INF/classes
+     * 
+     * @param context
+     * @param parser
+     * @throws Exception
+     */
+    public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser)
+    throws Exception
+    {
+        LOG.debug("Scanning classes in WEB-INF/classes");
+        if (context.getWebInf() != null)
+        {
+            Resource classesDir = context.getWebInf().addPath("classes/");
+            if (classesDir.exists())
+            {
+                parser.clearHandlers();
+                for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
+                {
+                    if (h instanceof AbstractDiscoverableAnnotationHandler)
+                        ((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
+                }
+                parser.registerHandlers(_discoverableAnnotationHandlers);
+                parser.registerHandler(_classInheritanceHandler);
+                parser.registerHandlers(_containerInitializerAnnotationHandlers);
+                
+                parser.parse(classesDir, 
+                             new ClassNameResolver()
+                {
+                    public boolean isExcluded (String name)
+                    {
+                        if (context.isSystemClass(name)) return true;
+                        if (context.isServerClass(name)) return false;
+                        return false;
+                    }
+
+                    public boolean shouldOverride (String name)
+                    {
+                        //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
+                        if (context.isParentLoaderPriority())
+                            return false;
+                        return true;
+                    }
+                });
+            }
+        }
+    }
+    
+ 
+    
+    /**
+     * Get the web-fragment.xml from a jar
+     * 
+     * @param jar
+     * @param frags
+     * @return
+     * @throws Exception
+     */
+    public FragmentDescriptor getFragmentFromJar (Resource jar,  List<FragmentDescriptor> frags)
+    throws Exception
+    {
+        //check if the jar has a web-fragment.xml
+        FragmentDescriptor d = null;
+        for (FragmentDescriptor frag: frags)
+        {
+            Resource fragResource = frag.getResource(); //eg jar:file:///a/b/c/foo.jar!/META-INF/web-fragment.xml
+            if (Resource.isContainedIn(fragResource,jar))
+            {
+                d = frag;
+                break;
+            }
+        }
+        return d;
+    }
+    
+    public boolean isMetaDataComplete (WebDescriptor d)
+    {
+        return (d!=null && d.getMetaDataComplete() == MetaDataComplete.True);
+    }
 }
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 766af72..7802224 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
@@ -50,6 +50,8 @@
         _introspector.registerHandler(new PostConstructAnnotationHandler(context));
         _introspector.registerHandler(new PreDestroyAnnotationHandler(context));
         _introspector.registerHandler(new DeclareRolesAnnotationHandler(context));
+        _introspector.registerHandler(new MultiPartConfigAnnotationHandler(context));
+        _introspector.registerHandler(new ServletSecurityAnnotationHandler(context));
     }
 
     /* ------------------------------------------------------------ */
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 0a2e628..3e252c2 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
@@ -25,12 +25,9 @@
 import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 import java.util.jar.JarEntry;
 
@@ -56,10 +53,7 @@
     private static final Logger LOG = Log.getLogger(AnnotationParser.class);
  
     protected Set<String> _parsedClassNames = new HashSet<String>();
-    protected Map<String, List<DiscoverableAnnotationHandler>> _annotationHandlers = new HashMap<String, List<DiscoverableAnnotationHandler>>();
-    protected List<ClassHandler> _classHandlers = new ArrayList<ClassHandler>();
-    protected List<MethodHandler> _methodHandlers = new ArrayList<MethodHandler>();
-    protected List<FieldHandler> _fieldHandlers = new ArrayList<FieldHandler>();
+    protected List<Handler> _handlers = new ArrayList<Handler>();
     
     public static String normalize (String name)
     {
@@ -170,37 +164,122 @@
     
     
     
-    public interface DiscoverableAnnotationHandler
+    /**
+     * Handler
+     *
+     * Signature for all handlers that respond to parsing class files.
+     */
+    public interface Handler
     {
+       
+    }
+    
+    
+    
+    /**
+     * DiscoverableAnnotationHandler
+     *
+     * Processes an annotation when it is discovered on a class.
+     */
+    public interface DiscoverableAnnotationHandler extends Handler
+    {
+        /**
+         * Process an annotation that was discovered on a class
+         * @param className
+         * @param version
+         * @param access
+         * @param signature
+         * @param superName
+         * @param interfaces
+         * @param annotation
+         * @param values
+         */
         public void handleClass (String className, int version, int access, 
                                  String signature, String superName, String[] interfaces, 
                                  String annotation, List<Value>values);
         
+        /**
+         * Process an annotation that was discovered on a method
+         * @param className
+         * @param methodName
+         * @param access
+         * @param desc
+         * @param signature
+         * @param exceptions
+         * @param annotation
+         * @param values
+         */
         public void handleMethod (String className, String methodName, int access,  
                                   String desc, String signature,String[] exceptions, 
                                   String annotation, List<Value>values);
         
+        
+        /**
+         * Process an annotation that was discovered on a field
+         * @param className
+         * @param fieldName
+         * @param access
+         * @param fieldType
+         * @param signature
+         * @param value
+         * @param annotation
+         * @param values
+         */
         public void handleField (String className, String fieldName,  int access, 
                                  String fieldType, String signature, Object value, 
                                  String annotation, List<Value>values);
+        
+        
+        /**
+         * Get the name of the annotation processed by this handler. Can be null
+         * 
+         * @return
+         */
+        public String getAnnotationName();
     }
     
     
-    public interface ClassHandler
+    
+    /**
+     * ClassHandler
+     *
+     * Responds to finding a Class
+     */
+    public interface ClassHandler extends Handler
     {
         public void handle (String className, int version, int access, String signature, String superName, String[] interfaces);
     }
     
-    public interface MethodHandler
+    
+    
+    /**
+     * MethodHandler
+     *
+     * Responds to finding a Method
+     */
+    public interface MethodHandler extends Handler
     {
         public void handle (String className, String methodName, int access,  String desc, String signature,String[] exceptions);
     }
     
-    public interface FieldHandler
+    
+    /**
+     * FieldHandler
+     *
+     * Responds to finding a Field
+     */
+    public interface FieldHandler extends Handler
     {
         public void handle (String className, String fieldName, int access, String fieldType, String signature, Object value);
     }
     
+    
+    
+    /**
+     * MyAnnotationVisitor
+     *
+     * ASM Visitor for Annotations
+     */
     public class MyAnnotationVisitor implements AnnotationVisitor
     {
         List<Value> _annotationValues;
@@ -309,10 +388,13 @@
                 for (String s : interfaces)
                     normalizedInterfaces[i++] = normalize(s);
             }
-            
-            for (ClassHandler h : AnnotationParser.this._classHandlers)
+
+            for (Handler h : AnnotationParser.this._handlers)
             {
-                h.handle(_className, _version, _access, _signature, normalize(_superName), normalizedInterfaces);
+                if (h instanceof ClassHandler)
+                {
+                    ((ClassHandler)h).handle(_className, _version, _access, _signature, normalize(_superName), normalizedInterfaces);
+                }
             }
         }
 
@@ -325,12 +407,13 @@
                     super.visitEnd();
 
                     //call all AnnotationHandlers with classname, annotation name + values
-                    List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
-                    if (handlers != null)
+                    for (Handler h : AnnotationParser.this._handlers)
                     {
-                        for (DiscoverableAnnotationHandler h:handlers)
+                        if (h instanceof DiscoverableAnnotationHandler)
                         {
-                            h.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
+                            DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
+                            if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
+                                dah.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
                         }
                     }
                 }
@@ -356,12 +439,13 @@
                         {   
                             super.visitEnd();
                             //call all AnnotationHandlers with classname, method, annotation name + values
-                            List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
-                            if (handlers != null)
+                            for (Handler h : AnnotationParser.this._handlers)
                             {
-                                for (DiscoverableAnnotationHandler h:handlers)
+                                if (h instanceof DiscoverableAnnotationHandler)
                                 {
-                                    h.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
+                                    DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
+                                    if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
+                                        dah.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
                                 }
                             }
                         }
@@ -388,12 +472,13 @@
                         public void visitEnd()
                         {
                             super.visitEnd();
-                            List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
-                            if (handlers != null)
+                            for (Handler h : AnnotationParser.this._handlers)
                             {
-                                for (DiscoverableAnnotationHandler h:handlers)
+                                if (h instanceof DiscoverableAnnotationHandler)
                                 {
-                                    h.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
+                                    DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
+                                    if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
+                                        dah.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
                                 }
                             }
                         }
@@ -409,46 +494,130 @@
      * Register a handler that will be called back when the named annotation is
      * encountered on a class.
      * 
+     * @deprecated see registerHandler(Handler)
      * @param annotationName
      * @param handler
      */
     public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler)
     {
-        List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
-        if (handlers == null)
-        {
-            handlers = new ArrayList<DiscoverableAnnotationHandler>();
-            _annotationHandlers.put(annotationName, handlers);
-        }
-        handlers.add(handler);
+        _handlers.add(handler);
     }
     
+    
+    /**
+     * @deprecated
+     * @param annotationName
+     * @return
+     */
     public List<DiscoverableAnnotationHandler> getAnnotationHandlers(String annotationName)
     {
-        List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
-        if (handlers == null)
-            return Collections.emptyList();
-        return new ArrayList<DiscoverableAnnotationHandler>(handlers);
+        List<DiscoverableAnnotationHandler> handlers = new ArrayList<DiscoverableAnnotationHandler>();
+        for (Handler h:_handlers)
+        {
+            if (h instanceof DiscoverableAnnotationHandler)
+            {
+                DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
+                if (annotationName.equals(dah.getAnnotationName()))
+                    handlers.add(dah);
+            }
+        }
+ 
+        return handlers;
     }
 
+    /**
+     * @deprecated
+     * @return
+     */
     public List<DiscoverableAnnotationHandler> getAnnotationHandlers()
     {
-        List<DiscoverableAnnotationHandler> allHandlers = new ArrayList<DiscoverableAnnotationHandler>();
-        for (List<DiscoverableAnnotationHandler> list:_annotationHandlers.values())
-            allHandlers.addAll(list);
-        return allHandlers;
+        List<DiscoverableAnnotationHandler> allAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
+        for (Handler h:_handlers)
+        {
+            if (h instanceof DiscoverableAnnotationHandler)
+            allAnnotationHandlers.add((DiscoverableAnnotationHandler)h);
+        }
+        return allAnnotationHandlers;
     }
 
+    /**
+     * @deprecated see registerHandler(Handler)
+     * @param handler
+     */
     public void registerClassHandler (ClassHandler handler)
     {
-        _classHandlers.add(handler);
+        _handlers.add(handler);
     }
+    
+    
+    
+    /**
+     * Add a particular handler
+     * 
+     * @param h
+     */
+    public void registerHandler(Handler h)
+    {
+        if (h == null)
+            return;
+        
+        _handlers.add(h);
+    }
+    
+    
+    /**
+     * Add a list of handlers
+     * 
+     * @param handlers
+     */
+    public void registerHandlers(List<? extends Handler> handlers)
+    {
+        if (handlers == null)
+            return;
+        _handlers.addAll(handlers);
+    }
+    
+    
+    /**
+     * Remove a particular handler
+     * 
+     * @param h
+     * @return
+     */
+    public boolean deregisterHandler(Handler h)
+    {
+        return _handlers.remove(h);
+    }
+    
+    
+    /**
+     * Remove all registered handlers
+     */
+    public void clearHandlers()
+    {
+        _handlers.clear();
+    }
+    
 
+    /**
+     * True if the class has already been processed, false otherwise
+     * @param className
+     * @return
+     */
     public boolean isParsed (String className)
     {
         return _parsedClassNames.contains(className);
     }
     
+    
+    
+    /**
+     * Parse a given class
+     * 
+     * @param className
+     * @param resolver
+     * @throws Exception
+     */
     public void parse (String className, ClassNameResolver resolver) 
     throws Exception
     {
@@ -470,6 +639,16 @@
         }
     }
     
+    
+    
+    /**
+     * Parse the given class, optionally walking its inheritance hierarchy
+     * 
+     * @param clazz
+     * @param resolver
+     * @param visitSuperClasses
+     * @throws Exception
+     */
     public void parse (Class clazz, ClassNameResolver resolver, boolean visitSuperClasses)
     throws Exception
     {
@@ -496,6 +675,15 @@
         }
     }
     
+    
+    
+    /**
+     * Parse the given classes
+     * 
+     * @param classNames
+     * @param resolver
+     * @throws Exception
+     */
     public void parse (String[] classNames, ClassNameResolver resolver)
     throws Exception
     {
@@ -505,6 +693,14 @@
         parse(Arrays.asList(classNames), resolver); 
     }
     
+    
+    /**
+     * Parse the given classes
+     * 
+     * @param classNames
+     * @param resolver
+     * @throws Exception
+     */
     public void parse (List<String> classNames, ClassNameResolver resolver)
     throws Exception
     {
@@ -523,6 +719,14 @@
         }
     }
     
+    
+    /**
+     * Parse all classes in a directory
+     * 
+     * @param dir
+     * @param resolver
+     * @throws Exception
+     */
     public void parse (Resource dir, ClassNameResolver resolver)
     throws Exception
     {
@@ -563,8 +767,9 @@
     
     
     /**
-     * Find annotations on classes in the supplied classloader. 
+     * Parse classes in the supplied classloader. 
      * Only class files in jar files will be scanned.
+     * 
      * @param loader
      * @param visitParents
      * @param nullInclusive
@@ -617,7 +822,8 @@
     
     
     /**
-     * Find annotations in classes in the supplied url of jar files.
+     * Parse classes in the supplied url of jar files.
+     * 
      * @param uris
      * @param resolver
      * @throws Exception
@@ -663,10 +869,8 @@
         scanner.scan(null, uris, true);
     }
     
-    
     /**
-     * Parse a single jar file for classes.
-     * 
+     * Parse a particular resource
      * @param uri
      * @param resolver
      * @throws Exception
@@ -680,14 +884,15 @@
         parse(uris, resolver);
     }
     
-
+    
+    
     /**
-     * Scan a class for annotations.
+     * Use ASM on a class
      * 
      * @param is
      * @throws IOException
      */
-    private void scanClass (InputStream is)
+    protected void scanClass (InputStream is)
     throws IOException
     {
         ClassReader reader = new ClassReader(is);
@@ -756,3 +961,4 @@
         return true;
     }
 }
+
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassInheritanceHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassInheritanceHandler.java
index c1e8de5..b8ea523 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassInheritanceHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassInheritanceHandler.java
@@ -35,10 +35,16 @@
     private static final Logger LOG = Log.getLogger(ClassInheritanceHandler.class);
 
     
-    MultiMap _inheritanceMap = new MultiMap();
+    MultiMap _inheritanceMap;
     
     public ClassInheritanceHandler()
     {
+       _inheritanceMap = new MultiMap();
+    }
+    
+    public ClassInheritanceHandler(MultiMap map)
+    {
+        _inheritanceMap = map;
     }
 
     public void handle(String className, int version, int access, String signature, String superName, String[] interfaces)
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
new file mode 100644
index 0000000..6c60c0e
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.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.annotations;
+
+import java.util.List;
+
+import javax.servlet.annotation.HandlesTypes;
+
+import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
+import org.eclipse.jetty.annotations.AnnotationParser.Value;
+import org.eclipse.jetty.plus.annotation.ContainerInitializer;
+import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.log.Log;
+
+/**
+ * ContainerInitializerAnnotationHandler
+ *
+ *  Discovers classes that contain the specified annotation, either at class or
+ *  method level. The specified annotation is derived from an @HandlesTypes on
+ *  a ServletContainerInitializer class. 
+ */
+public class ContainerInitializerAnnotationHandler implements DiscoverableAnnotationHandler
+{
+    ContainerInitializer _initializer;
+    Class _annotation;
+
+    public ContainerInitializerAnnotationHandler (ContainerInitializer initializer, Class annotation)
+    {
+        _initializer = initializer;
+        _annotation = annotation;
+    }
+    
+    /** 
+     * Handle finding a class that is annotated with the annotation we were constructed with.
+     * @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List)
+     */
+    public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotationName,
+                            List<Value> values)
+    { 
+         _initializer.addAnnotatedTypeName(className);
+    }
+
+    public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
+                            List<Value> values)
+    {
+       _initializer.addAnnotatedTypeName(className);
+    }
+
+    public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
+                             List<Value> values)
+    {
+       _initializer.addAnnotatedTypeName(className);
+    }
+
+    @Override
+    public String getAnnotationName()
+    {
+       return _annotation.getName();
+    }
+    
+    public ContainerInitializer getContainerInitializer()
+    {
+        return _initializer;
+    }
+
+}
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java
new file mode 100644
index 0000000..f2b20eb
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.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.annotations;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.Servlet;
+import javax.servlet.annotation.MultipartConfig;
+
+import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.webapp.Descriptor;
+import org.eclipse.jetty.webapp.MetaData;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * MultiPartConfigAnnotationHandler
+ *
+ *
+ */
+public class MultiPartConfigAnnotationHandler extends AbstractIntrospectableAnnotationHandler
+{
+    protected WebAppContext _context;
+
+    public MultiPartConfigAnnotationHandler(WebAppContext context)
+    {
+        //TODO verify that MultipartConfig is not inheritable
+        super(false); 
+        _context = context;
+    }
+    /** 
+     * @see org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler#doHandle(java.lang.Class)
+     */
+    public void doHandle(Class clazz)
+    {
+        if (!Servlet.class.isAssignableFrom(clazz))
+            return;
+        
+        MultipartConfig multi = (MultipartConfig) clazz.getAnnotation(MultipartConfig.class);
+        if (multi == null)
+            return;
+        
+        MetaData metaData = _context.getMetaData();
+              
+        //TODO: The MultipartConfigElement needs to be set on the ServletHolder's Registration.
+        //How to identify the correct Servlet?  If the Servlet has no WebServlet annotation on it, does it mean that this MultipartConfig
+        //annotation applies to all declared instances in web.xml/programmatically?
+        //Assuming TRUE for now.
+
+        ServletHolder holder = getServletHolderForClass(clazz);
+        if (holder != null)
+        {
+            Descriptor d = metaData.getOriginDescriptor(holder.getName()+".servlet.multipart-config");
+            //if a descriptor has already set the value for multipart config, do not 
+            //let the annotation override it
+            if (d == null)
+            {
+                metaData.setOrigin(holder.getName()+".servlet.multipart-config");
+                holder.getRegistration().setMultipartConfig(new MultipartConfigElement(multi));
+            }
+        }
+    }
+    
+    private ServletHolder getServletHolderForClass (Class clazz)
+    {
+        ServletHolder holder = null;
+        ServletHolder[] holders = _context.getServletHandler().getServlets();
+        if (holders != null)
+        {
+            for (ServletHolder h : holders)
+            {
+                if (h.getClassName() != null && h.getClassName().equals(clazz.getName()))
+                {
+                    holder = h;
+                }
+            }
+        }
+        return holder;
+    }
+}
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java
index 10f8dcb..ad22ff4 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java
@@ -107,7 +107,7 @@
         {
             for (ServletHolder h : holders)
             {
-                if (h.getClassName().equals(clazz.getName()))
+                if (h.getClassName() != null && h.getClassName().equals(clazz.getName()))
                 {
                     holder = h;
                 }
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializerListener.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializerListener.java
new file mode 100644
index 0000000..082fead
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializerListener.java
@@ -0,0 +1,144 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.annotations;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jetty.annotations.AnnotationConfiguration;
+import org.eclipse.jetty.plus.annotation.ContainerInitializer;
+import org.eclipse.jetty.util.MultiMap;
+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.webapp.WebAppContext;
+
+/**
+ * ServletContainerInitializerListener
+ *
+ *
+ */
+public class ServletContainerInitializerListener extends AbstractLifeCycle
+{
+    private static final Logger LOG = Log.getLogger(ServletContainerInitializerListener.class);
+    protected WebAppContext _context = null;
+    
+    
+    public void setWebAppContext (WebAppContext context)
+    {
+        _context = context;
+    }
+
+    
+    /** 
+     * Call the doStart method of the ServletContainerInitializers
+     * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
+     */
+    public void doStart()
+    {
+        List<ContainerInitializer> initializers = (List<ContainerInitializer>)_context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
+        MultiMap classMap = (MultiMap)_context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
+        
+        if (initializers != null)
+        {
+            for (ContainerInitializer i : initializers)
+            {
+                //We have already found the classes that directly have an annotation that was in the HandlesTypes
+                //annotation of the ServletContainerInitializer. For each of those classes, walk the inheritance
+                //hierarchy to find classes that extend or implement them.
+                if (i.getAnnotatedTypeNames() != null)
+                {
+                    Set<String> annotatedClassNames = new HashSet<String>(i.getAnnotatedTypeNames());
+                    for (String name : annotatedClassNames)
+                    {
+                        //add the class with the annotation
+                        i.addApplicableTypeName(name);
+                        //add the classes that inherit the annotation
+                        if (classMap != null)
+                        {
+                            List<String> implementsOrExtends = (List<String>)classMap.getValues(name);
+                            if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
+                                addInheritedTypes(classMap, i, implementsOrExtends);
+                        }
+                    }
+                }
+
+
+                //Now we need to look at the HandlesTypes classes that were not annotations. We need to
+                //find all classes that extend or implement them.
+                if (i.getInterestedTypes() != null)
+                {
+                    for (Class c : i.getInterestedTypes())
+                    {
+                        if (!c.isAnnotation())
+                        {
+                            //add the classes that implement or extend the class.
+                            //TODO but not including the class itself?
+                            if (classMap != null)
+                            {
+                                List<String> implementsOrExtends = (List<String>)classMap.getValues(c.getName());
+                                if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
+                                    addInheritedTypes(classMap, i, implementsOrExtends);
+                            }
+                        }
+                    }
+                }
+
+                //instantiate ServletContainerInitializers, call doStart
+                try
+                {
+                    i.callStartup(_context);
+                }
+                catch (Exception e)
+                {
+                    LOG.warn(e);
+                    throw new RuntimeException(e);
+                }
+            }
+        }       
+    }
+
+    
+    void addInheritedTypes (MultiMap classMap, ContainerInitializer initializer, List<String> applicableTypes)
+    {
+        for (String s : applicableTypes)
+        {
+            //add the name of the class that extends or implements
+            initializer.addApplicableTypeName(s);
+            
+            //walk the hierarchy and find all types that extend or implement it
+            List<String> implementsOrExtends = (List<String>)classMap.getValues(s);
+            if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
+                addInheritedTypes (classMap, initializer, implementsOrExtends);
+        }
+    }
+    
+    
+   
+    /** 
+     * Nothing to do for ServletContainerInitializers on stop
+     * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
+     */
+    public void doStop()
+    {
+       
+    }
+
+}
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
new file mode 100644
index 0000000..d6432f8
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.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.annotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.annotation.HttpConstraint;
+import javax.servlet.annotation.HttpMethodConstraint;
+import javax.servlet.annotation.ServletSecurity;
+import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
+import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
+
+import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
+import org.eclipse.jetty.security.ConstraintAware;
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.ServletMapping;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.security.Constraint;
+import org.eclipse.jetty.webapp.Origin;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * ServletSecurityAnnotationHandler
+ *
+ * Inspect a class to see if it has an @ServletSecurity annotation on it,
+ * setting up the <security-constraint>s.
+ * 
+ * A servlet can be defined in:
+ * <ul>
+ * <li>web.xml
+ * <li>web-fragment.xml
+ * <li>@WebServlet annotation discovered
+ * <li>ServletContext.createServlet
+ * </ul>
+ * 
+ * The ServletSecurity annotation for a servlet should only be processed
+ * iff metadata-complete == false.
+ */
+public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnnotationHandler
+{
+    private static final Logger LOG = Log.getLogger(ServletSecurityAnnotationHandler.class);
+
+    private WebAppContext _context;
+    
+    public ServletSecurityAnnotationHandler(WebAppContext wac)
+    {
+        super(false);
+        _context = wac;
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.annotations.AnnotationIntrospector.IntrospectableAnnotationHandler#handle(java.lang.Class)
+     */
+    public void doHandle(Class clazz)
+    {
+        if (!(_context.getSecurityHandler() instanceof ConstraintAware))
+        {
+            LOG.warn("SecurityHandler not ConstraintAware, skipping security annotation processing");
+            return;
+        }
+        
+       ServletSecurity servletSecurity = (ServletSecurity)clazz.getAnnotation(ServletSecurity.class);
+       if (servletSecurity == null)
+           return;
+       
+       //If there are already constraints defined (ie from web.xml) that match any 
+       //of the url patterns defined for this servlet, then skip the security annotation.
+      
+       List<ServletMapping> servletMappings = getServletMappings(clazz.getCanonicalName());
+       List<ConstraintMapping> constraintMappings =  ((ConstraintAware)_context.getSecurityHandler()).getConstraintMappings();
+     
+       if (constraintsExist(servletMappings, constraintMappings))
+       {
+           LOG.warn("Constraints already defined for "+clazz.getName()+", skipping ServletSecurity annotation");
+           return;
+       }
+
+       //Make a fresh list
+       constraintMappings = new ArrayList<ConstraintMapping>();
+       
+       ServletSecurityElement securityElement = new ServletSecurityElement(servletSecurity);
+       for (ServletMapping sm : servletMappings)
+       {
+           for (String url : sm.getPathSpecs())
+           {
+               _context.getMetaData().setOrigin("constraint.url."+url, Origin.Annotation);
+               constraintMappings.addAll(ConstraintSecurityHandler.createConstraintsWithMappingsForPath(clazz.getName(), url, securityElement));
+           }
+       }
+
+       //set up the security constraints produced by the annotation
+       ConstraintAware securityHandler = (ConstraintAware)_context.getSecurityHandler();
+
+       for (ConstraintMapping m:constraintMappings)
+           securityHandler.addConstraintMapping(m); 
+    }
+    
+ 
+    
+    /**
+     * 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
+     * @return
+     */
+    protected Constraint makeConstraint (Class servlet, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
+    {  
+        return ConstraintSecurityHandler.createConstraint(servlet.getName(), rolesAllowed, permitOrDeny, transport);
+    }
+    
+    
+    
+    /**
+     * Get the ServletMappings for the servlet's class.
+     * @param className
+     * @return
+     */
+    protected List<ServletMapping> getServletMappings(String className)
+    {
+        List<ServletMapping> results = new ArrayList<ServletMapping>();
+        ServletMapping[] mappings = _context.getServletHandler().getServletMappings();
+        for (ServletMapping mapping : mappings)
+        {
+            //Check the name of the servlet that this mapping applies to, and then find the ServletHolder for it to find it's class
+            ServletHolder holder = _context.getServletHandler().getServlet(mapping.getServletName());
+            if (holder.getClassName() != null && holder.getClassName().equals(className))
+              results.add(mapping);
+        }
+        return results;
+    }
+    
+    
+    
+    /**
+     * Check if there are already <security-constraint> elements defined that match the url-patterns for
+     * the servlet.
+     * @param servletMappings
+     * @return
+     */
+    protected boolean constraintsExist (List<ServletMapping> servletMappings, List<ConstraintMapping> constraintMappings)
+    {
+        boolean exists = false;
+
+        //Check to see if the path spec on each constraint mapping matches a pathSpec in the servlet mappings.
+        //If it does, then we should ignore the security annotations.
+        for (ServletMapping mapping : servletMappings)
+        {  
+            //Get its url mappings
+            String[] pathSpecs = mapping.getPathSpecs();
+            if (pathSpecs == null)
+                continue;
+
+            //Check through the constraints to see if there are any whose pathSpecs (url mappings)
+            //match the servlet. If so, then we already have constraints defined for this servlet,
+            //and we will not be processing the annotation (ie web.xml or programmatic override).
+           for (int i=0; constraintMappings != null && i < constraintMappings.size() && !exists; i++)
+           {
+               for (int j=0; j < pathSpecs.length; j++)
+               {
+                   //TODO decide if we need to check the origin
+                   if (pathSpecs[j].equals(constraintMappings.get(i).getPathSpec()))
+                   {
+                       exists = true;
+                       break;
+                   }
+               }
+           }
+        }      
+        return exists;
+    }
+
+}
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 260dc5c..0ef5476 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
@@ -61,7 +61,8 @@
                 javax.servlet.ServletRequestListener.class.isAssignableFrom(c) ||
                 javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(c) ||
                 javax.servlet.http.HttpSessionListener.class.isAssignableFrom(c) ||
-                javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c))
+                javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c) ||
+                javax.servlet.AsyncListener.class.isAssignableFrom(c))
 
                 isServlet=true;
         
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
new file mode 100644
index 0000000..4e3567d
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java
@@ -0,0 +1,223 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.annotations;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.annotation.WebInitParam;
+
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.FilterMapping;
+import org.eclipse.jetty.servlet.Holder;
+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.webapp.DiscoveredAnnotation;
+import org.eclipse.jetty.webapp.MetaData;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.webapp.Origin;
+
+/**
+ * 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);
+    }
+    
+    public WebFilterAnnotation(WebAppContext context, String className, Resource resource)
+    {
+        super(context, className, resource);
+    }
+
+    /** 
+     * @see org.eclipse.jetty.annotations.ClassAnnotation#apply()
+     */
+    public void apply()
+    {
+        // TODO verify against rules for annotation v descriptor
+        
+        Class clazz = getTargetClass();
+        if (clazz == null)
+        {
+            LOG.warn(_className+" cannot be loaded");
+            return;
+        }
+        
+        
+        //Servlet Spec 8.1.2
+        if (!Filter.class.isAssignableFrom(clazz))
+        {
+            LOG.warn(clazz.getName()+" is not assignable from javax.servlet.Filter");
+            return;
+        }
+        MetaData metaData = _context.getMetaData();
+        
+        WebFilter filterAnnotation = (WebFilter)clazz.getAnnotation(WebFilter.class);
+
+        if (filterAnnotation.value().length > 0 && filterAnnotation.urlPatterns().length > 0)
+        {
+            LOG.warn(clazz.getName()+" defines both @WebFilter.value and @WebFilter.urlPatterns");
+            return;
+        }
+
+        String name = (filterAnnotation.filterName().equals("")?clazz.getName():filterAnnotation.filterName());
+        String[] urlPatterns = filterAnnotation.value();
+        if (urlPatterns.length == 0)
+            urlPatterns = filterAnnotation.urlPatterns();
+        
+        FilterHolder holder = _context.getServletHandler().getFilter(name);
+        if (holder == null)
+        {
+            //Filter with this name does not already exist, so add it
+            holder = _context.getServletHandler().newFilterHolder(Holder.Source.ANNOTATION);
+            holder.setName(name);
+            
+            holder.setHeldClass(clazz);
+            metaData.setOrigin(name+".filter.filter-class");
+ 
+            holder.setDisplayName(filterAnnotation.displayName()); 
+            metaData.setOrigin(name+".filter.display-name");
+
+            for (WebInitParam ip:  filterAnnotation.initParams())
+            {
+                holder.setInitParameter(ip.name(), ip.value());
+                metaData.setOrigin(name+".filter.init-param."+ip.name());
+            }
+
+            FilterMapping mapping = new FilterMapping();
+            mapping.setFilterName(holder.getName());
+
+            if (urlPatterns.length > 0)
+            {
+                ArrayList paths = new ArrayList();
+                for (String s:urlPatterns)
+                {
+                    paths.add(Util.normalizePattern(s));
+                }
+                mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()]));
+            }
+
+            if (filterAnnotation.servletNames().length > 0)
+            {
+                ArrayList<String> names = new ArrayList<String>();
+                for (String s : filterAnnotation.servletNames())
+                {
+                    names.add(s);
+                }
+                mapping.setServletNames((String[])names.toArray(new String[names.size()]));
+            }
+
+            EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class);           
+            for (DispatcherType d : filterAnnotation.dispatcherTypes())
+            {
+                dispatcherSet.add(d);
+            }
+            mapping.setDispatcherTypes(dispatcherSet);
+            metaData.setOrigin(name+".filter.mappings");
+
+            holder.setAsyncSupported(filterAnnotation.asyncSupported());
+            metaData.setOrigin(name+".filter.async-supported");
+
+            _context.getServletHandler().addFilter(holder);
+            _context.getServletHandler().addFilterMapping(mapping);
+        }
+        else
+        {
+            //A Filter definition for the same name already exists from web.xml
+            //ServletSpec 3.0 p81 if the Filter is already defined and has mappings,
+            //they override the annotation. If it already has DispatcherType set, that
+            //also overrides the annotation. Init-params are additive, but web.xml overrides
+            //init-params of the same name.
+            for (WebInitParam ip:  filterAnnotation.initParams())
+            {
+                //if (holder.getInitParameter(ip.name()) == null)
+                if (metaData.getOrigin(name+".filter.init-param."+ip.name())==Origin.NotSet)
+                {
+                    holder.setInitParameter(ip.name(), ip.value());
+                    metaData.setOrigin(name+".filter.init-param."+ip.name());
+                }
+            }
+            
+            FilterMapping[] mappings = _context.getServletHandler().getFilterMappings();
+            boolean mappingExists = false;
+            if (mappings != null)
+            {
+                for (FilterMapping m:mappings)
+                {
+                    if (m.getFilterName().equals(name))
+                    {
+                        mappingExists = true;
+                        break;
+                    }
+                }
+            }
+            //if a descriptor didn't specify at least one mapping, use the mappings from the annotation and the DispatcherTypes
+            //from the annotation
+            if (!mappingExists)
+            {
+                FilterMapping mapping = new FilterMapping();
+                mapping.setFilterName(holder.getName());
+
+                if (urlPatterns.length > 0)
+                {
+                    ArrayList paths = new ArrayList();
+                    for (String s:urlPatterns)
+                    {
+                        paths.add(Util.normalizePattern(s));
+                    }
+                    mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()]));
+                }
+                if (filterAnnotation.servletNames().length > 0)
+                {
+                    ArrayList<String> names = new ArrayList<String>();
+                    for (String s : filterAnnotation.servletNames())
+                    {
+                        names.add(s);
+                    }
+                    mapping.setServletNames((String[])names.toArray(new String[names.size()]));
+                }
+                
+                EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class);           
+                for (DispatcherType d : filterAnnotation.dispatcherTypes())
+                {
+                    dispatcherSet.add(d);
+                }
+                mapping.setDispatcherTypes(dispatcherSet);
+                _context.getServletHandler().addFilterMapping(mapping);   
+                metaData.setOrigin(name+".filter.mappings");
+            }
+        }
+    }
+
+}
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java
new file mode 100644
index 0000000..b37b85d
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.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.annotations;
+
+import java.util.List;
+
+import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
+import org.eclipse.jetty.annotations.AnnotationParser.Value;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.webapp.DiscoveredAnnotation;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * WebFilterAnnotationHandler
+ *
+ *
+ */
+public class WebFilterAnnotationHandler extends AbstractDiscoverableAnnotationHandler
+{
+    private static final Logger LOG = Log.getLogger(WebFilterAnnotationHandler.class);
+
+    public WebFilterAnnotationHandler (WebAppContext context)
+    {
+        super(context);
+    }
+    
+    public WebFilterAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
+    {
+        super(context, list);
+    }
+    
+    public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
+                            List<Value> values)
+    {
+        WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, className, _resource);
+        addAnnotation(wfAnnotation);
+    }
+
+    public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
+                            List<Value> values)
+    {
+        LOG.warn ("@WebFilter not applicable for fields: "+className+"."+fieldName);
+    }
+
+    public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
+                             List<Value> values)
+    {
+        LOG.warn ("@WebFilter not applicable for methods: "+className+"."+methodName+" "+signature);
+    }
+
+    @Override
+    public String getAnnotationName()
+    {
+        return "javax.servlet.annotation.WebFilter";
+    }
+
+}
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
new file mode 100644
index 0000000..0ad8242
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.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.annotations;
+
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionListener;
+
+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.webapp.DiscoveredAnnotation;
+import org.eclipse.jetty.webapp.MetaData;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.webapp.Origin;
+
+/**
+ * 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);
+    }
+    
+    public WebListenerAnnotation(WebAppContext context, String className, Resource resource)
+    {
+        super(context, className, resource);
+    }
+
+    /** 
+     * @see org.eclipse.jetty.annotations.ClassAnnotation#apply()
+     */
+    public void apply()
+    {
+        // TODO check algorithm against ordering rules for descriptors v annotations
+        
+        Class clazz = getTargetClass();
+        
+        if (clazz == null)
+        {
+            LOG.warn(_className+" cannot be loaded");
+            return;
+        }
+
+        try
+        {
+            if (ServletContextListener.class.isAssignableFrom(clazz) || 
+                    ServletContextAttributeListener.class.isAssignableFrom(clazz) ||
+                    ServletRequestListener.class.isAssignableFrom(clazz) ||
+                    ServletRequestAttributeListener.class.isAssignableFrom(clazz) ||
+                    HttpSessionListener.class.isAssignableFrom(clazz) ||
+                    HttpSessionAttributeListener.class.isAssignableFrom(clazz))
+            {
+                java.util.EventListener listener = (java.util.EventListener)clazz.newInstance();
+                MetaData metaData = _context.getMetaData();
+                if (metaData.getOrigin(clazz.getName()+".listener") == Origin.NotSet)
+                    _context.addEventListener(listener);
+            }
+            else
+                LOG.warn(clazz.getName()+" does not implement one of the servlet listener interfaces");
+        }
+        catch (Exception e)
+        {
+            LOG.warn(e);
+        }
+    }
+}
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
new file mode 100644
index 0000000..74753a8
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.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.annotations;
+
+import java.util.List;
+
+import org.eclipse.jetty.annotations.AnnotationParser.Value;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.webapp.DiscoveredAnnotation;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotationHandler
+{
+    private static final Logger LOG = Log.getLogger(WebListenerAnnotationHandler.class);
+
+    public WebListenerAnnotationHandler (WebAppContext context)
+    {
+       super(context);
+    }
+    
+    public WebListenerAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
+    {
+       super(context, list);
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List)
+     */
+    public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
+                            List<Value> values)
+    {
+        WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, className, _resource);
+        addAnnotation(wlAnnotation);
+    }
+
+    public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
+                            List<Value> values)
+    {
+        LOG.warn ("@WebListener is not applicable to fields: "+className+"."+fieldName);
+    }
+
+    public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
+                             List<Value> values)
+    {
+        LOG.warn ("@WebListener is not applicable to methods: "+className+"."+methodName+" "+signature);
+    }
+
+    @Override
+    public String getAnnotationName()
+    {
+        return "javax.servlet.annotation.WebListener";
+    }
+
+}
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
new file mode 100644
index 0000000..82f7290
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.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.annotations;
+
+import java.util.ArrayList;
+
+import javax.servlet.annotation.WebInitParam;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+
+import org.eclipse.jetty.servlet.Holder;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.ServletMapping;
+import org.eclipse.jetty.util.LazyList;
+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.webapp.DiscoveredAnnotation;
+import org.eclipse.jetty.webapp.MetaData;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.webapp.Origin;
+
+/**
+ * WebServletAnnotation
+ *
+ *
+ */
+public class WebServletAnnotation extends DiscoveredAnnotation
+{
+    private static final Logger LOG = Log.getLogger(WebServletAnnotation.class);
+    
+    public WebServletAnnotation (WebAppContext context, String className)
+    {
+        super(context, className);
+    }
+    
+    
+    public WebServletAnnotation (WebAppContext context, String className, Resource resource)
+    {
+        super(context, className, resource);
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.annotations.ClassAnnotation#apply()
+     */
+    public void apply()
+    {
+        //TODO check this algorithm with new rules for applying descriptors and annotations in order
+        Class clazz = getTargetClass();
+        
+        if (clazz == null)
+        {
+            LOG.warn(_className+" cannot be loaded");
+            return;
+        }
+        
+        //Servlet Spec 8.1.1
+        if (!HttpServlet.class.isAssignableFrom(clazz))
+        {
+            LOG.warn(clazz.getName()+" is not assignable from javax.servlet.http.HttpServlet");
+            return;
+        }
+        
+        WebServlet annotation = (WebServlet)clazz.getAnnotation(WebServlet.class);
+        
+        if (annotation.urlPatterns().length > 0 && annotation.value().length > 0)
+        {
+            LOG.warn(clazz.getName()+ " defines both @WebServlet.value and @WebServlet.urlPatterns");
+            return;
+        }
+        
+        String[] urlPatterns = annotation.value();
+        if (urlPatterns.length == 0)
+            urlPatterns = annotation.urlPatterns();
+        
+        if (urlPatterns.length == 0)
+        {
+            LOG.warn(clazz.getName()+ " defines neither @WebServlet.value nor @WebServlet.urlPatterns");
+            return;
+        }
+        
+        //canonicalize the patterns
+        ArrayList<String> urlPatternList = new ArrayList<String>();
+        for (String p : urlPatterns)
+            urlPatternList.add(Util.normalizePattern(p));
+        
+        String servletName = (annotation.name().equals("")?clazz.getName():annotation.name());
+        
+        MetaData metaData = _context.getMetaData();
+
+        //Find out if a <servlet> already exists with this name
+        ServletHolder[] holders = _context.getServletHandler().getServlets();
+        boolean isNew = true;
+        ServletHolder holder = null;
+        if (holders != null)
+        {
+            for (ServletHolder h : holders)
+            {
+                if (h.getName() != null && servletName.equals(h.getName()))
+                {
+                    holder = h;
+                    isNew = false;
+                    break;
+                }
+            }
+        }
+
+        if (isNew)
+        {
+            //No servlet of this name has already been defined, either by a descriptor
+            //or another annotation (which would be impossible).
+            holder = _context.getServletHandler().newServletHolder(Holder.Source.ANNOTATION);
+            holder.setHeldClass(clazz);   
+            metaData.setOrigin(servletName+".servlet.servlet-class");
+            
+            holder.setName(servletName);
+            holder.setDisplayName(annotation.displayName());
+            metaData.setOrigin(servletName+".servlet.display-name");
+            
+            holder.setInitOrder(annotation.loadOnStartup());
+            metaData.setOrigin(servletName+".servlet.load-on-startup");
+            
+            holder.setAsyncSupported(annotation.asyncSupported());
+            metaData.setOrigin(servletName+".servlet.async-supported");
+            
+            for (WebInitParam ip:annotation.initParams())
+            {
+                holder.setInitParameter(ip.name(), ip.value());
+                metaData.setOrigin(servletName+".servlet.init-param."+ip.name());
+            }
+          
+            _context.getServletHandler().addServlet(holder);
+            ServletMapping mapping = new ServletMapping();  
+            mapping.setServletName(holder.getName());
+            mapping.setPathSpecs( LazyList.toStringArray(urlPatternList));
+            _context.getServletHandler().addServletMapping(mapping);
+            metaData.setOrigin(servletName+".servlet.mappings");
+        }
+        else
+        {
+            //set the class according to the servlet that is annotated, if it wasn't already
+            //NOTE: this may be considered as "completing" an incomplete servlet registration, and it is
+            //not clear from servlet 3.0 spec whether this is intended, or if only a ServletContext.addServlet() call
+            //can complete it, see http://java.net/jira/browse/SERVLET_SPEC-42
+            if (holder.getClassName() == null) 
+                holder.setClassName(clazz.getName());
+            if (holder.getHeldClass() == null)
+                holder.setHeldClass(clazz);
+            
+            //check if the existing servlet has each init-param from the annotation
+            //if not, add it
+            for (WebInitParam ip:annotation.initParams())
+            {
+                if (metaData.getOrigin(servletName+".servlet.init-param"+ip.name())==Origin.NotSet)
+                {
+                    holder.setInitParameter(ip.name(), ip.value());
+                    metaData.setOrigin(servletName+".servlet.init-param."+ip.name());
+                }  
+            }
+            
+            //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     
+            boolean mappingsExist = false;
+            boolean anyNonDefaults = false;
+            ServletMapping[] allMappings = _context.getServletHandler().getServletMappings();
+            if (allMappings != null)
+            {
+                for (ServletMapping m:allMappings)
+                {
+                    if (m.getServletName() != null && servletName.equals(m.getServletName()))
+                    {    
+                        mappingsExist = true;
+                        if (!m.isDefault())
+                        {
+                            anyNonDefaults = true;
+                            break;
+                        }
+                    }
+                }
+            }
+            
+            if (anyNonDefaults)
+                return;  //if any mappings already set by a descriptor that is not webdefault.xml, we're done
+       
+            boolean clash = false;
+            if (mappingsExist)
+            {
+                for (String p:urlPatternList)
+                {
+                    ServletMapping m = _context.getServletHandler().getServletMapping(p);
+                    if (m != null && !m.isDefault())
+                    {
+                        //trying to override a servlet-mapping that was added not by webdefault.xml
+                        clash = true;
+                        break;
+                    }
+                }
+            }
+       
+            if (!mappingsExist || !clash)
+            {
+                ServletMapping m = new ServletMapping();
+                m.setServletName(servletName);
+                m.setPathSpecs(LazyList.toStringArray(urlPatternList));
+                _context.getServletHandler().addServletMapping(m); 
+            }
+        }
+    }   
+}
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
new file mode 100644
index 0000000..f89dd4e
--- /dev/null
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java
@@ -0,0 +1,85 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.annotations;
+
+import java.util.List;
+
+import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
+import org.eclipse.jetty.annotations.AnnotationParser.Value;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.webapp.DiscoveredAnnotation;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * WebServletAnnotationHandler
+ *
+ * Process a WebServlet annotation on a class.
+ * 
+ */
+public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationHandler
+{
+    private static final Logger LOG = Log.getLogger(WebServletAnnotationHandler.class);
+    
+    public WebServletAnnotationHandler (WebAppContext context)
+    {
+        super(context);
+    }
+    
+    public WebServletAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
+    {
+        super(context, list);
+    }
+    
+    
+    /** 
+     * Handle discovering a WebServlet annotation.
+     * 
+     *  
+     * @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List)
+     */
+    public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotationName,
+                            List<Value> values)
+    {
+        if (!"javax.servlet.annotation.WebServlet".equals(annotationName))
+            return;    
+       
+        WebServletAnnotation annotation = new WebServletAnnotation (_context, className, _resource);
+        addAnnotation(annotation);
+    }
+
+    public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
+                            List<Value> values)
+    {
+        LOG.warn ("@WebServlet annotation not supported for fields");
+    }
+
+    public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
+                             List<Value> values)
+    {
+        LOG.warn ("@WebServlet annotation not supported for methods");
+    }
+
+
+    @Override
+    public String getAnnotationName()
+    {
+        return "javax.servlet.annotation.WebServlet";
+    }    
+}
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java
index 3886e0f..d123274 100644
--- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java
@@ -24,16 +24,20 @@
 import javax.annotation.PreDestroy;
 import javax.annotation.Resource;
 import javax.annotation.security.RunAs;
+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.annotation.WebFilter;
+import javax.servlet.annotation.WebInitParam;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+@WebFilter(filterName="CFilter", dispatcherTypes={DispatcherType.REQUEST}, urlPatterns = {"/*"}, initParams={@WebInitParam(name="a", value="99")}, asyncSupported=false)
 @RunAs("admin")
 public class FilterC implements Filter
 {
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java
index 10fc5f9..c010e57 100644
--- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java
@@ -20,7 +20,9 @@
 
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
 
+@WebListener
 public class ListenerC implements ServletContextListener
 {
 
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java
index 9b5dcd4..96ed7c2 100644
--- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java
@@ -26,12 +26,21 @@
 import javax.annotation.security.DeclareRoles;
 import javax.annotation.security.RunAs;
 import javax.servlet.ServletException;
+import javax.servlet.annotation.HttpConstraint;
+import javax.servlet.annotation.HttpMethodConstraint;
+import javax.servlet.annotation.MultipartConfig;
+import javax.servlet.annotation.ServletSecurity;
+import javax.servlet.annotation.WebInitParam;
+import javax.servlet.annotation.WebServlet;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 @DeclareRoles({"alice"})
+@WebServlet(urlPatterns = { "/foo/*", "/bah/*" }, name="CServlet", initParams={@WebInitParam(name="x", value="y")}, loadOnStartup=2, asyncSupported=false)
+@MultipartConfig(fileSizeThreshold=1000, maxFileSize=2000, maxRequestSize=3000)
 @RunAs("admin")
+@ServletSecurity(value=@HttpConstraint(rolesAllowed={"fred", "bill", "dorothy"}), httpMethodConstraints={@HttpMethodConstraint(value="GET", rolesAllowed={"bob", "carol", "ted"})})
 public class ServletC extends HttpServlet
 {
     @Resource (mappedName="foo", type=Double.class)
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java
new file mode 100644
index 0000000..eca8092
--- /dev/null
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.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.annotations;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.webapp.FragmentDescriptor;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * TestAnnotationConfiguration
+ *
+ *
+ */
+public class TestAnnotationConfiguration extends TestCase
+{
+    public void testGetFragmentFromJar ()
+    throws Exception
+    {
+        String dir = System.getProperty("basedir", ".");   
+        File file = new File(dir);
+        file=new File(file.getCanonicalPath());
+        URL url=file.toURL();
+
+        Resource jar1 = Resource.newResource(url+"file.jar");
+
+        AnnotationConfiguration config = new AnnotationConfiguration();
+        WebAppContext wac = new WebAppContext();
+
+        List<FragmentDescriptor> frags = new ArrayList<FragmentDescriptor>();
+        frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file.jar!/fooa.props")));
+        frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file2.jar!/foob.props")));
+
+        assertNotNull(config.getFragmentFromJar(jar1, frags));
+    }
+}
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java
index b2d7de1..c74155f 100644
--- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java
@@ -18,20 +18,23 @@
 
 package org.eclipse.jetty.annotations;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
 import java.util.ArrayList;
 import java.util.List;
-
+import java.util.Map;
 import javax.naming.Context;
 import javax.naming.InitialContext;
 
 import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
 import org.eclipse.jetty.annotations.AnnotationParser.Value;
+import org.eclipse.jetty.util.MultiMap;
 import org.junit.After;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 /**
  *
  */
@@ -63,6 +66,12 @@
         {
             annotatedMethods.add(className+"."+methodName);
         }
+        
+        @Override
+        public String getAnnotationName()
+        {
+            return "org.eclipse.jetty.annotations.Sample";
+        }
     }
 
     @After
@@ -82,7 +91,7 @@
 
         SampleHandler handler = new SampleHandler();
         AnnotationParser parser = new AnnotationParser();
-        parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", handler);
+        parser.registerHandler(handler);
         parser.parse(classNames, new ClassNameResolver ()
         {
             public boolean isExcluded(String name)
@@ -191,4 +200,40 @@
         });
         assertEquals (1, handler.annotatedClassNames.size());
     }
+
+    @Test
+    public void testTypeInheritanceHandling() throws Exception
+    {
+        AnnotationParser parser = new AnnotationParser();
+        ClassInheritanceHandler handler = new ClassInheritanceHandler();
+        parser.registerClassHandler(handler);
+
+        class Foo implements InterfaceD
+        {
+        }
+
+        classNames.clear();
+        classNames.add(ClassA.class.getName());
+        classNames.add(ClassB.class.getName());
+        classNames.add(InterfaceD.class.getName());
+        classNames.add(Foo.class.getName());
+
+        parser.parse(classNames, null);
+
+        MultiMap map = handler.getMap();
+        assertNotNull(map);
+        assertFalse(map.isEmpty());
+        assertEquals(2, map.size());
+        Map stringArrayMap = map.toStringArrayMap();
+        assertTrue (stringArrayMap.keySet().contains("org.eclipse.jetty.annotations.ClassA"));
+        assertTrue (stringArrayMap.keySet().contains("org.eclipse.jetty.annotations.InterfaceD"));
+        String[] classes = (String[])stringArrayMap.get("org.eclipse.jetty.annotations.ClassA");
+        assertEquals(1, classes.length);
+        assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]);
+
+        classes = (String[])stringArrayMap.get("org.eclipse.jetty.annotations.InterfaceD");
+        assertEquals(2, classes.length);
+        assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]);
+        assertEquals(Foo.class.getName(), classes[1]);
+    }
 }
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java
index 3359857..f39c599 100644
--- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java
@@ -53,10 +53,13 @@
     
     public static class TrackingAnnotationHandler implements DiscoverableAnnotationHandler
     {
+
+        private final String annotationName;
         public final Set<String> foundClasses;
 
-        public TrackingAnnotationHandler()
+        public TrackingAnnotationHandler(String annotationName)
         {
+            this.annotationName = annotationName;
             this.foundClasses = new HashSet<String>();
         }
 
@@ -80,6 +83,13 @@
         {
             /* ignore */
         }
+
+
+        @Override
+        public String getAnnotationName()
+        {
+           return this.annotationName;
+        }
     }
 
 
@@ -95,6 +105,9 @@
         {
             private List<String> methods = Arrays.asList("a", "b", "c", "d", "l");
 
+           
+            
+            
             public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
                                     List<Value> values)
             {
@@ -120,9 +133,15 @@
                 assertTrue(methods.contains(methodName));
                 assertEquals("org.eclipse.jetty.annotations.Sample", annotation);
             }
+
+            @Override
+            public String getAnnotationName()
+            {
+                return "org.eclipse.jetty.annotations.Sample";
+            }
         }
 
-        parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", new SampleAnnotationHandler());
+        parser.registerHandler(new SampleAnnotationHandler());
 
         long start = System.currentTimeMillis();
         parser.parse(classNames, new ClassNameResolver ()
@@ -169,9 +188,17 @@
                 assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className));
                 assertTrue("a".equals(methodName));
             }
+
+            @Override
+            public String getAnnotationName()
+            {
+                return "org.eclipse.jetty.annotations.Multi";
+            }
+            
+            
         }
 
-        parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Multi", new MultiAnnotationHandler());
+        parser.registerHandler(new MultiAnnotationHandler());
         parser.parse(classNames, null);
     }
 
@@ -200,11 +227,11 @@
         copyClass(ClassA.class,basedir);
 
         // Setup Tracker
-        TrackingAnnotationHandler tracker = new TrackingAnnotationHandler();
+        TrackingAnnotationHandler tracker = new TrackingAnnotationHandler(Sample.class.getName());
 
         // Setup annotation scanning
         AnnotationParser parser = new AnnotationParser();
-        parser.registerAnnotationHandler(Sample.class.getName(), tracker);
+        parser.registerHandler(tracker);
 
         // Parse
         parser.parse(Resource.newResource(basedir),null);
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java
new file mode 100644
index 0000000..bfce6f5
--- /dev/null
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.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.annotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.annotation.ServletSecurity;
+import javax.servlet.annotation.HttpConstraint;
+import javax.servlet.annotation.HttpMethodConstraint;
+import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
+import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
+import javax.servlet.http.HttpServlet;
+
+import org.eclipse.jetty.security.ConstraintAware;
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.servlet.Holder;
+import org.eclipse.jetty.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.ServletMapping;
+import org.eclipse.jetty.util.LazyList;
+import org.eclipse.jetty.util.security.Constraint;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+import junit.framework.TestCase;
+
+public class TestSecurityAnnotationConversions extends TestCase
+{
+    @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.DENY)) 
+    public static class DenyServlet extends HttpServlet
+    {}
+    
+    @ServletSecurity
+    public static class PermitServlet extends HttpServlet
+    {}
+    
+    @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"})) 
+    public static class RolesServlet extends HttpServlet
+    {}
+    
+    @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}),
+                     httpMethodConstraints={@HttpMethodConstraint(value="GET")}) 
+    public static class Method1Servlet extends HttpServlet
+    {}
+    
+    @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}),
+                     httpMethodConstraints={@HttpMethodConstraint(value="GET", transportGuarantee=TransportGuarantee.CONFIDENTIAL)}) 
+    public static class Method2Servlet extends HttpServlet
+    {}
+    
+    
+    public void setUp()
+    {
+    }
+    
+    public void testDenyAllOnClass ()
+    throws Exception
+    {
+
+        WebAppContext wac = makeWebAppContext(DenyServlet.class.getCanonicalName(), "denyServlet", new String[]{"/foo/*", "*.foo"});
+        
+        //Assume we found 1 servlet with a @HttpConstraint with value=EmptyRoleSemantic.DENY security annotation
+        ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
+        AnnotationIntrospector introspector = new AnnotationIntrospector();
+        introspector.registerHandler(annotationHandler);
+        
+        //set up the expected outcomes:
+        //1 ConstraintMapping per ServletMapping pathSpec
+        Constraint expectedConstraint = new Constraint();
+        expectedConstraint.setAuthenticate(true);
+        expectedConstraint.setDataConstraint(Constraint.DC_NONE);
+        
+        ConstraintMapping[] expectedMappings = new ConstraintMapping[2];
+        
+        expectedMappings[0] = new ConstraintMapping();
+        expectedMappings[0].setConstraint(expectedConstraint);
+        expectedMappings[0].setPathSpec("/foo/*");
+        
+        expectedMappings[1] = new ConstraintMapping();
+        expectedMappings[1].setConstraint(expectedConstraint);
+        expectedMappings[1].setPathSpec("*.foo");
+        
+        introspector.introspect(DenyServlet.class);
+       
+        compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());   
+    }
+    
+   
+    public void testPermitAll()
+    throws Exception
+    {
+        //Assume we found 1 servlet with a @ServletSecurity security annotation
+        WebAppContext wac = makeWebAppContext(PermitServlet.class.getCanonicalName(), "permitServlet", new String[]{"/foo/*", "*.foo"});
+        
+        ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
+        AnnotationIntrospector introspector = new AnnotationIntrospector();
+        introspector.registerHandler(annotationHandler);
+        
+      
+        //set up the expected outcomes:
+        //1 ConstraintMapping per ServletMapping pathSpec
+        Constraint expectedConstraint = new Constraint();
+        expectedConstraint.setAuthenticate(false);
+        expectedConstraint.setDataConstraint(Constraint.DC_NONE);
+                     
+        ConstraintMapping[] expectedMappings = new ConstraintMapping[2];
+        expectedMappings[0] = new ConstraintMapping();
+        expectedMappings[0].setConstraint(expectedConstraint);
+        expectedMappings[0].setPathSpec("/foo/*");
+        
+        expectedMappings[1] = new ConstraintMapping();
+        expectedMappings[1].setConstraint(expectedConstraint);
+        expectedMappings[1].setPathSpec("*.foo");
+
+        introspector.introspect(PermitServlet.class);
+       
+        compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
+    }
+    
+    public void testRolesAllowedWithTransportGuarantee ()
+    throws Exception
+    {
+        //Assume we found 1 servlet with annotation with roles defined and 
+        //and a TransportGuarantee
+        
+        WebAppContext wac = makeWebAppContext(RolesServlet.class.getCanonicalName(), "rolesServlet", new String[]{"/foo/*", "*.foo"});
+        
+        ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
+        AnnotationIntrospector introspector = new AnnotationIntrospector();
+        introspector.registerHandler(annotationHandler);
+        
+        //set up the expected outcomes:compareResults
+        //1 ConstraintMapping per ServletMapping 
+        Constraint expectedConstraint = new Constraint();
+        expectedConstraint.setAuthenticate(true);
+        expectedConstraint.setRoles(new String[]{"tom", "dick", "harry"});
+        expectedConstraint.setDataConstraint(Constraint.DC_CONFIDENTIAL);
+        
+        ConstraintMapping[] expectedMappings = new ConstraintMapping[2];
+        expectedMappings[0] = new ConstraintMapping();
+        expectedMappings[0].setConstraint(expectedConstraint);
+        expectedMappings[0].setPathSpec("/foo/*");
+        
+        expectedMappings[1] = new ConstraintMapping();
+        expectedMappings[1].setConstraint(expectedConstraint);
+        expectedMappings[1].setPathSpec("*.foo");
+        
+        introspector.introspect(RolesServlet.class);
+        compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
+    }
+  
+  
+    public void testMethodAnnotation ()
+    throws Exception
+    {
+        //ServletSecurity annotation with HttpConstraint of TransportGuarantee.CONFIDENTIAL, and a list of rolesAllowed, and
+        //a HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default)
+        
+        WebAppContext wac = makeWebAppContext(Method1Servlet.class.getCanonicalName(), "method1Servlet",  new String[]{"/foo/*", "*.foo"});
+       
+        //set up the expected outcomes: - a Constraint for the RolesAllowed on the class
+        //with userdata constraint of DC_CONFIDENTIAL 
+        //and mappings for each of the pathSpecs
+        Constraint expectedConstraint1 = new Constraint();
+        expectedConstraint1.setAuthenticate(true);
+        expectedConstraint1.setRoles(new String[]{"tom", "dick", "harry"});
+        expectedConstraint1.setDataConstraint(Constraint.DC_CONFIDENTIAL);       
+        
+        //a Constraint for the PermitAll on the doGet method with a userdata
+        //constraint of DC_CONFIDENTIAL inherited from the class
+        Constraint expectedConstraint2 = new Constraint();  
+        expectedConstraint2.setDataConstraint(Constraint.DC_NONE);
+        
+        ConstraintMapping[] expectedMappings = new ConstraintMapping[4];
+        expectedMappings[0] = new ConstraintMapping();
+        expectedMappings[0].setConstraint(expectedConstraint1);
+        expectedMappings[0].setPathSpec("/foo/*");
+        expectedMappings[0].setMethodOmissions(new String[]{"GET"});
+        expectedMappings[1] = new ConstraintMapping();
+        expectedMappings[1].setConstraint(expectedConstraint1);
+        expectedMappings[1].setPathSpec("*.foo"); 
+        expectedMappings[1].setMethodOmissions(new String[]{"GET"});
+        
+        expectedMappings[2] = new ConstraintMapping();
+        expectedMappings[2].setConstraint(expectedConstraint2);
+        expectedMappings[2].setPathSpec("/foo/*");
+        expectedMappings[2].setMethod("GET");
+        expectedMappings[3] = new ConstraintMapping();
+        expectedMappings[3].setConstraint(expectedConstraint2);
+        expectedMappings[3].setPathSpec("*.foo");
+        expectedMappings[3].setMethod("GET");
+        
+        AnnotationIntrospector introspector = new AnnotationIntrospector();
+        ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
+        introspector.registerHandler(annotationHandler);
+        introspector.introspect(Method1Servlet.class);
+        compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
+    }
+
+    public void testMethodAnnotation2 ()
+    throws Exception
+    {
+        //A ServletSecurity annotation that has HttpConstraint of CONFIDENTIAL with defined roles, but a
+        //HttpMethodConstraint for GET that permits all, but also requires CONFIDENTIAL
+        WebAppContext wac = makeWebAppContext(Method2Servlet.class.getCanonicalName(), "method2Servlet",  new String[]{"/foo/*", "*.foo"});
+
+        AnnotationIntrospector introspector = new AnnotationIntrospector();
+        ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
+        introspector.registerHandler(annotationHandler);
+
+        //set up the expected outcomes: - a Constraint for the RolesAllowed on the class
+        //with userdata constraint of DC_CONFIDENTIAL
+        //and mappings for each of the pathSpecs
+        Constraint expectedConstraint1 = new Constraint();
+        expectedConstraint1.setAuthenticate(true);
+        expectedConstraint1.setRoles(new String[]{"tom", "dick", "harry"});
+        expectedConstraint1.setDataConstraint(Constraint.DC_CONFIDENTIAL);
+     
+        //a Constraint for the Permit on the GET method with a userdata
+        //constraint of DC_CONFIDENTIAL      
+        Constraint expectedConstraint2 = new Constraint();  
+        expectedConstraint2.setDataConstraint(Constraint.DC_CONFIDENTIAL);
+        
+        ConstraintMapping[] expectedMappings = new ConstraintMapping[4];
+        expectedMappings[0] = new ConstraintMapping();
+        expectedMappings[0].setConstraint(expectedConstraint1);
+        expectedMappings[0].setPathSpec("/foo/*");
+        expectedMappings[0].setMethodOmissions(new String[]{"GET"});
+        expectedMappings[1] = new ConstraintMapping();
+        expectedMappings[1].setConstraint(expectedConstraint1);
+        expectedMappings[1].setPathSpec("*.foo"); 
+        expectedMappings[1].setMethodOmissions(new String[]{"GET"});
+        
+        expectedMappings[2] = new ConstraintMapping();
+        expectedMappings[2].setConstraint(expectedConstraint2);
+        expectedMappings[2].setPathSpec("/foo/*");
+        expectedMappings[2].setMethod("GET");
+        expectedMappings[3] = new ConstraintMapping();
+        expectedMappings[3].setConstraint(expectedConstraint2);
+        expectedMappings[3].setPathSpec("*.foo");
+        expectedMappings[3].setMethod("GET");
+        
+        introspector.introspect(Method2Servlet.class);
+        compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
+    }
+
+    private void compareResults (ConstraintMapping[] expectedMappings, List<ConstraintMapping> actualMappings)
+    {
+        assertNotNull(actualMappings);
+        assertEquals(expectedMappings.length, actualMappings.size());
+
+        for (int k=0; k < actualMappings.size(); k++)
+        {   
+            ConstraintMapping am = actualMappings.get(k);
+            boolean matched  = false;
+          
+            for (int i=0; i< expectedMappings.length && !matched; i++)
+            {
+                ConstraintMapping em = expectedMappings[i];
+                if (em.getPathSpec().equals(am.getPathSpec()))
+                {
+                    if ((em.getMethod()==null && am.getMethod() == null) || em.getMethod() != null && em.getMethod().equals(am.getMethod()))
+                    {
+                        matched = true; 
+                      
+                        assertEquals(em.getConstraint().getAuthenticate(), am.getConstraint().getAuthenticate());
+                        assertEquals(em.getConstraint().getDataConstraint(), am.getConstraint().getDataConstraint());
+                        if (em.getMethodOmissions() == null)
+                        {
+                            assertNull(am.getMethodOmissions());
+                        }
+                        else
+                        {
+                            assertTrue(Arrays.equals(am.getMethodOmissions(), em.getMethodOmissions()));
+                        }
+                        
+                        if (em.getConstraint().getRoles() == null)
+                        {
+                            assertNull(am.getConstraint().getRoles());
+                        }
+                        else
+                        {
+                            assertTrue(Arrays.equals(em.getConstraint().getRoles(), am.getConstraint().getRoles()));
+                        }  
+                    }
+                }
+            }
+           
+            if (!matched)
+                fail("No expected ConstraintMapping matching method:"+am.getMethod()+" pathSpec: "+am.getPathSpec());
+        }
+    }
+    
+    
+    private WebAppContext makeWebAppContext (String className, String servletName, String[] paths)
+    {
+        WebAppContext wac = new WebAppContext(); 
+   
+        ServletHolder[] holders = new ServletHolder[1];
+        holders[0] = new ServletHolder();
+        holders[0].setClassName(className);
+        holders[0].setName(servletName);
+        holders[0].setServletHandler(wac.getServletHandler());
+        wac.getServletHandler().setServlets(holders);
+        wac.setSecurityHandler(new ConstraintSecurityHandler());
+        
+        ServletMapping[] servletMappings = new ServletMapping[1];
+        servletMappings[0] = new ServletMapping();
+      
+        servletMappings[0].setPathSpecs(paths);
+        servletMappings[0].setServletName(servletName);
+        wac.getServletHandler().setServletMappings(servletMappings);
+        return wac;
+    }
+}
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 0bdd18a..bc43260 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,12 +18,19 @@
 
 package org.eclipse.jetty.annotations;
 
+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 java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 
 import org.eclipse.jetty.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.ServletMapping;
 import org.eclipse.jetty.webapp.WebAppContext;
 import org.junit.Test;
 
@@ -34,8 +41,50 @@
  */
 public class TestServletAnnotations
 {
-   
     @Test
+    public void testServletAnnotation() throws Exception
+    {
+        List<String> classes = new ArrayList<String>();
+        classes.add("org.eclipse.jetty.annotations.ServletC");
+        AnnotationParser parser = new AnnotationParser();
+
+        WebAppContext wac = new WebAppContext();       
+        WebServletAnnotationHandler handler = new WebServletAnnotationHandler(wac);
+        parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", handler);
+       
+        parser.parse(classes, new ClassNameResolver ()
+        {
+            public boolean isExcluded(String name)
+            {
+                return false;
+            }
+
+            public boolean shouldOverride(String name)
+            {
+                return false;
+            }
+        });
+        
+        assertEquals(1, handler.getAnnotationList().size());
+        assertTrue(handler.getAnnotationList().get(0) instanceof WebServletAnnotation);
+        
+        handler.getAnnotationList().get(0).apply();
+       
+        ServletHolder[] holders = wac.getServletHandler().getServlets();
+        assertNotNull(holders);
+        assertEquals(1, holders.length);
+        assertEquals("CServlet", holders[0].getName());
+        ServletMapping[] mappings = wac.getServletHandler().getServletMappings();
+        assertNotNull(mappings);
+        assertEquals(1, mappings.length);
+        String[] paths = mappings[0].getPathSpecs();
+        assertNotNull(paths);
+        assertEquals(2, paths.length);
+        assertEquals("y", holders[0].getInitParameter("x"));
+        assertEquals(2,holders[0].getInitOrder());
+        assertFalse(holders[0].isAsyncSupported());
+    }
+    
     public void testDeclareRoles ()
     throws Exception
     { 
diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml
index e9455c6..586113d 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>7.6.19-SNAPSHOT</version>
+        <version>8.1.19-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
@@ -76,7 +76,45 @@
                   </configuration>
                 </execution>
               </executions>
-            </plugin>   
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.0</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <shadedArtifactAttached>true</shadedArtifactAttached>
+                            <shadedClassifierName>hybrid</shadedClassifierName>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.eclipse.jetty:jetty-http</include>
+                                    <include>org.eclipse.jetty:jetty-io</include>
+                                    <include>org.eclipse.jetty:jetty-util</include>
+                                </includes>
+                            </artifactSet>
+                            <relocations>
+                                <relocation>
+                                    <pattern>org.eclipse.jetty.http</pattern>
+                                    <shadedPattern>org.eclipse.jetty.client.shaded.http</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>org.eclipse.jetty.io</pattern>
+                                    <shadedPattern>org.eclipse.jetty.client.shaded.io</shadedPattern>
+                                </relocation>
+                                <relocation>
+                                    <pattern>org.eclipse.jetty.util</pattern>
+                                    <shadedPattern>org.eclipse.jetty.client.shaded.util</shadedPattern>
+                                </relocation>
+                            </relocations>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java
index 37e39f0..0b968f8 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java
@@ -106,6 +106,8 @@
                                 LOG.debug("complete {}",exchange);
                                 progress=true;
                                 _generator.complete();
+                                if (exchange.getStatus() < HttpExchange.STATUS_WAITING_FOR_RESPONSE)
+                                    exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
                             }
                             else if (_generator.isEmpty())
                             {
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 81998f7..6ecf242 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
@@ -21,11 +21,14 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.LinkedList;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+
 import javax.net.ssl.SSLContext;
 
 import org.eclipse.jetty.client.security.Authentication;
@@ -79,6 +82,7 @@
     private int _connectorType = CONNECTOR_SELECT_CHANNEL;
     private boolean _useDirectBuffers = true;
     private boolean _connectBlocking = true;
+    private boolean _removeIdleDestinations=false;
     private int _maxConnectionsPerAddress = Integer.MAX_VALUE;
     private int _maxQueueSizePerAddress = Integer.MAX_VALUE;
     private ConcurrentMap<Address, HttpDestination> _destinations = new ConcurrentHashMap<Address, HttpDestination>();
@@ -157,6 +161,18 @@
     }
 
     /* ------------------------------------------------------------------------------- */
+    public boolean isRemoveIdleDestinations()
+    {
+        return _removeIdleDestinations;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public void setRemoveIdleDestinations(boolean removeIdleDestinations)
+    {
+        _removeIdleDestinations = removeIdleDestinations;
+    }
+
+    /* ------------------------------------------------------------------------------- */
     public void send(HttpExchange exchange) throws IOException
     {
         boolean ssl = HttpSchemes.HTTPS_BUFFER.equalsIgnoreCase(exchange.getScheme());
@@ -262,7 +278,19 @@
         }
         return destination;
     }
-
+    
+    /* ------------------------------------------------------------------------------- */
+    public Collection<Address> getDestinations()
+    {
+        return Collections.unmodifiableCollection(_destinations.keySet());
+    }
+    
+    /* ------------------------------------------------------------------------------- */
+    public void removeDestination(HttpDestination destination)
+    {
+        _destinations.remove(destination.getAddress(),destination);
+    }
+    
     /* ------------------------------------------------------------ */
     public void schedule(Timeout.Task task)
     {
@@ -908,4 +936,5 @@
     private static class LocalQueuedThreadPool extends QueuedThreadPool
     {
     }
+
 }
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 8bbef8c..fb83307 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
@@ -169,6 +169,15 @@
 
         // TODO query, remove and age methods
     }
+    
+    public void clearCookies()
+    {
+        synchronized (this)
+        {
+            _cookies.clear();
+        }
+
+    }
 
     /**
      * Get a connection. We either get an idle connection if one is available, or
@@ -442,15 +451,20 @@
         else
         {
             boolean startConnection = false;
+            boolean remove = false;
             synchronized (this)
             {
                 _connections.remove(connection);
-                if (!_exchanges.isEmpty())
+                if (_exchanges.isEmpty())
+                    remove=_client.isRemoveIdleDestinations() && ( _cookies==null || _cookies.isEmpty() ) &&_connections.isEmpty() && _idleConnections.isEmpty();
+                else if (_client.isStarted())
                     startConnection = true;
             }
 
             if (startConnection)
                 startNewConnection();
+            if (remove)
+                _client.removeDestination(this);
         }
     }
 
@@ -461,17 +475,22 @@
         connection.onIdleExpired(idleForMs);
 
         boolean startConnection = false;
+        boolean remove = false;
         synchronized (this)
         {
             _idleConnections.remove(connection);
             _connections.remove(connection);
 
-            if (!_exchanges.isEmpty() && _client.isStarted())
+            if (_exchanges.isEmpty())
+                remove=_client.isRemoveIdleDestinations() && ( _cookies==null || _cookies.isEmpty() ) &&_connections.isEmpty() && _idleConnections.isEmpty();
+            else if (_client.isStarted())
                 startConnection = true;
         }
 
         if (startConnection)
             startNewConnection();
+        if (remove)
+            _client.removeDestination(this);
     }
 
     public void send(HttpExchange ex) throws IOException
@@ -524,21 +543,24 @@
     {
         // add cookies
         // TODO handle max-age etc.
-        if (_cookies != null)
+        synchronized (this)
         {
-            StringBuilder buf = null;
-            for (HttpCookie cookie : _cookies)
+            if (_cookies != null)
             {
-                if (buf == null)
-                    buf = new StringBuilder();
-                else
-                    buf.append("; ");
-                buf.append(cookie.getName()); // TODO quotes
-                buf.append("=");
-                buf.append(cookie.getValue()); // TODO quotes
-            }
-            if (buf != null)
-                ex.addRequestHeader(HttpHeaders.COOKIE, buf.toString());
+                StringBuilder buf = null;
+                for (HttpCookie cookie : _cookies)
+                {
+                    if (buf == null)
+                        buf = new StringBuilder();
+                    else
+                        buf.append("; ");
+                    buf.append(cookie.getName()); // TODO quotes
+                    buf.append("=");
+                    buf.append(cookie.getValue()); // TODO quotes
+                }
+                if (buf != null)
+                    ex.addRequestHeader(HttpHeaders.COOKIE, buf.toString());
+            }  
         }
 
         // Add any known authorizations
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java
index 5676289..b0c7f59 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java
@@ -33,6 +33,7 @@
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.server.nio.SelectChannelConnector;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -58,10 +59,12 @@
             public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
                     throws IOException, ServletException
             {
+                httpResponse.setStatus(200);
                 request.setHandled(true);
                 try
                 {
-                    Thread.sleep(2000);
+                    if (request.getRequestURI().contains("/sleep"))
+                        Thread.sleep(2000);
                 }
                 catch (InterruptedException x)
                 {
@@ -76,7 +79,6 @@
         client.setTimeout(200);
         client.setMaxRetries(0);
         client.setMaxConnectionsPerAddress(100);
-        client.start();
     }
 
     @After
@@ -90,7 +92,10 @@
     @Test
     public void testExpire() throws Exception
     {
-        String baseUrl = "http://" + "localhost" + ":" + port + "/";
+        client.setIdleTimeout(5000);
+        client.start();
+        
+        String baseUrl = "http://" + "localhost" + ":" + port + "/sleep";
 
         int count = 200;
         final CountDownLatch expires = new CountDownLatch(count);
@@ -114,4 +119,41 @@
         // Wait to be sure that all exchanges have expired
         assertTrue(expires.await(5, TimeUnit.SECONDS));
     }
+    
+    @Test
+    public void testRemoveIdleDestination() throws Exception
+    {
+        client.setIdleTimeout(200);
+        client.setRemoveIdleDestinations(true);
+        client.start();
+        
+        String baseUrl = "http://" + "localhost" + ":" + port + "/other";
+
+        int count = 5;
+        final CountDownLatch latch = new CountDownLatch(count);
+
+        for (int i=0;i<count;i++)
+        {
+            final ContentExchange exchange = new ContentExchange()
+            {
+                @Override
+                protected void onResponseComplete()
+                {
+                    latch.countDown();
+                }
+            };
+            exchange.setMethod("GET");
+            exchange.setURL(baseUrl);
+
+            client.send(exchange);
+        }
+
+        // Wait to be sure that all exchanges have expired
+        assertTrue(latch.await(1, TimeUnit.SECONDS));
+        
+        Assert.assertEquals(1,client.getDestinations().size());
+        Thread.sleep(500);
+        Assert.assertEquals(0,client.getDestinations().size());
+                
+    }
 }
diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml
index 63f2242..b0eba22 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-continuation</artifactId>
@@ -25,7 +25,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>javax.servlet.*;version="[2.5,3.1)",org.mortbay.log.*;version="[6.1,7)";resolution:=optional,org.mortbay.util.ajax.*;version="[6.1,7)";resolution:=optional,*</Import-Package>
+                <Import-Package>javax.servlet.*;version="2.6.0",org.mortbay.log.*;version="[6.1,7)";resolution:=optional,org.mortbay.util.ajax.*;version="[6.1,7)";resolution:=optional,*</Import-Package>
               </instructions>
             </configuration>
            </execution>
diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java
index ab1ad05..52666cd 100644
--- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java
+++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.continuation;
 
 import java.lang.reflect.Constructor;
-
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletRequestWrapper;
 import javax.servlet.ServletResponse;
@@ -59,7 +58,7 @@
             __servlet3=servlet3Support;
             __newServlet3Continuation=s3cc;
         }
-        
+
         boolean jetty6Support=false;
         Constructor<? extends Continuation>j6cc=null;
         try
@@ -80,7 +79,7 @@
             __jetty6=jetty6Support;
             __newJetty6Continuation=j6cc;
         }
-        
+
         Class<?> waiting=null;
         try
         {
@@ -98,12 +97,12 @@
     /* ------------------------------------------------------------ */
     /**
      * Get a Continuation.  The type of the Continuation returned may
-     * vary depending on the container in which the application is 
+     * vary depending on the container in which the application is
      * deployed. It may be an implementation native to the container (eg
      * org.eclipse.jetty.server.AsyncContinuation) or one of the utility
      * implementations provided such as an internal <code>FauxContinuation</code>
      * or a real implementation like {@link org.eclipse.jetty.continuation.Servlet3Continuation}.
-     * @param request The request 
+     * @param request The request
      * @return a Continuation instance
      */
     public static Continuation getContinuation(ServletRequest request)
@@ -111,10 +110,10 @@
         Continuation continuation = (Continuation) request.getAttribute(Continuation.ATTRIBUTE);
         if (continuation!=null)
             return continuation;
-        
+
         while (request instanceof ServletRequestWrapper)
             request=((ServletRequestWrapper)request).getRequest();
-        
+
         if (__servlet3 )
         {
             try
diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java
index e0dfb14..fe16119 100644
--- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java
+++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java
@@ -21,7 +21,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
 import javax.servlet.AsyncListener;
@@ -34,7 +33,7 @@
 /* ------------------------------------------------------------ */
 /**
  * This implementation of Continuation is used by {@link ContinuationSupport}
- * when it detects that the application has been deployed in a non-jetty Servlet 3 
+ * when it detects that the application has been deployed in a non-jetty Servlet 3
  * server.
  */
 public class Servlet3Continuation implements Continuation
@@ -42,11 +41,11 @@
     // Exception reused for all continuations
     // Turn on debug in ContinuationFilter to see real stack trace.
     private final static ContinuationThrowable __exception = new ContinuationThrowable();
-    
+
     private final ServletRequest _request;
     private ServletResponse _response;
     private AsyncContext _context;
-    private List<AsyncListener> _listeners=new ArrayList<AsyncListener>(); 
+    private List<AsyncListener> _listeners=new ArrayList<AsyncListener>();
     private volatile boolean _initial=true;
     private volatile boolean _resumed=false;
     private volatile boolean _expired=false;
@@ -108,7 +107,7 @@
                 listener.onTimeout(Servlet3Continuation.this);
             }
         };
-        
+
         if (_context!=null)
             _context.addListener(wrapped);
         else
@@ -188,7 +187,7 @@
         _expired=false;
         _context=_request.startAsync();
         _context.setTimeout(_timeoutMs);
-        
+
         for (AsyncListener listener:_listeners)
             _context.addListener(listener);
         _listeners.clear();
@@ -201,7 +200,7 @@
         _expired=false;
         _context=_request.startAsync();
         _context.setTimeout(_timeoutMs);
-                
+
         for (AsyncListener listener:_listeners)
             _context.addListener(listener);
         _listeners.clear();
diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml
index 5e2e3ac..1afd666 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-deploy</artifactId>
@@ -25,7 +25,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>org.eclipse.jetty.jmx.*;version="[7.3,8)";resolution:=optional,*</Import-Package>
+                <Import-Package>org.eclipse.jetty.jmx.*;version="8.0";resolution:=optional,*</Import-Package>
               </instructions>
             </configuration>
            </execution>
diff --git a/jetty-deploy/src/main/config/etc/jetty-deploy.xml b/jetty-deploy/src/main/config/etc/jetty-deploy.xml
index dd25f7f..1b3fd66 100644
--- a/jetty-deploy/src/main/config/etc/jetty-deploy.xml
+++ b/jetty-deploy/src/main/config/etc/jetty-deploy.xml
@@ -22,7 +22,7 @@
           </Set>
           <Call name="setContextAttribute">
             <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
-            <Arg>.*/.*jsp-api-[^/]*\.jar$|.*/.*jsp-[^/]*\.jar$|.*/.*taglibs[^/]*\.jar$</Arg>
+            <Arg>.*/servlet-api-[^/]*\.jar$</Arg>
           </Call>
           
           
diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml
index 18bd90f..f2fe278 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>jetty-distribution</artifactId>
   <name>Jetty :: Distribution Assemblies</name>
@@ -145,7 +145,7 @@
                   <version>${orbit-servlet-api-version}</version>
                   <overWrite>true</overWrite>
                   <outputDirectory>${assembly-directory}/lib</outputDirectory>
-                  <destFileName>servlet-api-2.5.jar</destFileName>
+                  <destFileName>servlet-api-3.0.jar</destFileName>
                 </artifactItem>
               </artifactItems>
             </configuration>
diff --git a/jetty-distribution/src/main/resources/bin/jetty-cygwin.sh b/jetty-distribution/src/main/resources/bin/jetty-cygwin.sh
index 550390e..16371be 100755
--- a/jetty-distribution/src/main/resources/bin/jetty-cygwin.sh
+++ b/jetty-distribution/src/main/resources/bin/jetty-cygwin.sh
@@ -5,7 +5,7 @@
 # To get the service to restart correctly on reboot, uncomment below (3 lines):
 # ========================
 # chkconfig: 3 99 99
-# description: Jetty 7 webserver
+# description: Jetty 8 webserver
 # processname: jetty
 # ========================
 
@@ -134,8 +134,8 @@
 ##################################################
 # See if there's a default configuration file
 ##################################################
-if [ -f /etc/default/jetty7 ] ; then 
-  . /etc/default/jetty7
+if [ -f /etc/default/jetty8 ] ; then 
+  . /etc/default/jetty8
 elif [ -f /etc/default/jetty ] ; then 
   . /etc/default/jetty
 fi
@@ -196,13 +196,13 @@
         /home                    \
         "
   JETTY_DIR_NAMES="              \
-        jetty-7                  \
-        jetty7                   \
-        jetty-7.*                \
+        jetty-8                  \
+        jetty8                   \
+        jetty-8.*                \
         jetty                    \
-        Jetty-7                  \
-        Jetty7                   \
-        Jetty-7.*                \
+        Jetty-8                  \
+        Jetty8                   \
+        Jetty-8.*                \
         Jetty                    \
         "
         
@@ -511,7 +511,7 @@
         echo -n "Starting Jetty: "
 
         if [ "$NO_START" = "1" ]; then 
-	  echo "Not starting jetty - NO_START=1 in /etc/default/jetty7";
+	  echo "Not starting jetty - NO_START=1 in /etc/default/jetty8";
           exit 0;
 	fi
 
diff --git a/jetty-distribution/src/main/resources/bin/jetty.sh b/jetty-distribution/src/main/resources/bin/jetty.sh
index c9e2323..baafc4d 100755
--- a/jetty-distribution/src/main/resources/bin/jetty.sh
+++ b/jetty-distribution/src/main/resources/bin/jetty.sh
@@ -5,7 +5,7 @@
 # To get the service to restart correctly on reboot, uncomment below (3 lines):
 # ========================
 # chkconfig: 3 99 99
-# description: Jetty 7 webserver
+# description: Jetty 8 webserver
 # processname: jetty
 # ========================
 
@@ -161,7 +161,7 @@
   ETC=$HOME/etc
 fi
 
-for CONFIG in $ETC/default/jetty{,7} $HOME/.jettyrc; do
+for CONFIG in $ETC/default/jetty{,8} $HOME/.jettyrc; do
   if [ -f "$CONFIG" ] ; then 
     readConfig "$CONFIG"
   fi
@@ -217,13 +217,13 @@
         "/home"
         )
   JETTY_DIR_NAMES=(
-        "jetty-7"
-        "jetty7"
-        "jetty-7.*"
+        "jetty-8"
+        "jetty8"
+        "jetty-8.*"
         "jetty"
-        "Jetty-7"
-        "Jetty7"
-        "Jetty-7.*"
+        "Jetty-8"
+        "Jetty8"
+        "Jetty-8.*"
         "Jetty"
         )
         
diff --git a/jetty-distribution/src/main/resources/start.ini b/jetty-distribution/src/main/resources/start.ini
index 0ada4c0..dfc2783 100644
--- a/jetty-distribution/src/main/resources/start.ini
+++ b/jetty-distribution/src/main/resources/start.ini
@@ -46,7 +46,7 @@
 # for a full listing do
 #   java -jar start.jar --list-options
 #-----------------------------------------------------------
-OPTIONS=Server,jsp,jmx,resources,websocket,ext
+OPTIONS=Server,jsp,jmx,resources,websocket,ext,plus,annotations
 #-----------------------------------------------------------
 
 
@@ -57,6 +57,7 @@
 #-----------------------------------------------------------
 #etc/jetty-jmx.xml
 etc/jetty.xml
+etc/jetty-annotations.xml
 # etc/jetty-ssl.xml
 # etc/jetty-requestlog.xml
 etc/jetty-deploy.xml
diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml
index 5c6d2ec..f466790 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-http-spi</artifactId>
diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml
index 02e927e..7fe0716 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-http</artifactId>
@@ -42,7 +42,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>javax.net.*,*</Import-Package>
+                <Import-Package>javax.servlet.*;version="2.6.0",javax.net.*,*</Import-Package>
               </instructions>
             </configuration>
            </execution>
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java
index c615b18..3922410 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java
@@ -444,8 +444,10 @@
         {
             flushBuffer();
 
-            while (now<end && (content!=null && content.length()>0 ||buffer!=null && buffer.length()>0) && _endp.isOpen()&& !_endp.isOutputShutdown())
+            while (now<end && (content!=null && content.length()>0 ||buffer!=null && buffer.length()>0))
             {
+            	if (!_endp.isOpen() || _endp.isOutputShutdown())
+            		throw new EofException();
                 blockForOutput(end-now);
                 now=System.currentTimeMillis();
             }
@@ -480,6 +482,11 @@
                 completeHeader(null, false);
                 addContent(new View(new ByteArrayBuffer(content)), Generator.LAST);
             }
+            else if (code>=400)
+            {
+                completeHeader(null, false);
+                addContent(new View(new ByteArrayBuffer("Error: "+(reason==null?(""+code):reason))), Generator.LAST);
+            }
             else
             {
                 completeHeader(null, true);
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 a46ef08..d915582 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
@@ -24,10 +24,12 @@
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collections;
+import java.util.Collection;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -341,6 +343,22 @@
     
     /* -------------------------------------------------------------- */
     /**
+     * Get Collection of header names. 
+     */
+    public Collection<String> getFieldNamesCollection()
+    {
+        final List<String> list = new ArrayList<String>(_fields.size());
+
+	for (Field f : _fields)
+	{
+	    if (f!=null)
+	        list.add(BufferUtil.to8859_1_String(f._name));
+	}
+	return list;
+    }
+    
+    /* -------------------------------------------------------------- */
+    /**
      * Get enumeration of header _names. Returns an enumeration of strings representing the header
      * _names for this request.
      */
@@ -371,7 +389,7 @@
     /**
      * Get a Field by index.
      * @return A Field value or null if the Field value has not been set
-     * for this revision of the fields.
+     * 
      */
     public Field getField(int i)
     {
@@ -438,6 +456,30 @@
         return field==null?null:field._value;
     }
 
+
+    /* -------------------------------------------------------------- */
+    /**
+     * Get multi headers
+     * 
+     * @return Enumeration of the values, or null if no such header.
+     * @param name the case-insensitive field name
+     */
+    public Collection<String> getValuesCollection(String name)
+    {
+        Field field = getField(name);
+	if (field==null)
+	    return null;
+
+        final List<String> list = new ArrayList<String>();
+
+	while(field!=null)
+	{
+	    list.add(field.getValue());
+	    field=field._next;
+	}
+	return list;
+    }
+
     /* -------------------------------------------------------------- */
     /**
      * Get multi headers
@@ -1361,5 +1403,4 @@
             return ("[" + getName() + "=" + _value + (_next == null ? "" : "->") + "]");
         }
     }
-
 }
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 e38dcb7..ad7494e 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
@@ -660,8 +660,11 @@
                     // written yet?
 
                     // Response known not to have a body
-                    if (_contentWritten == 0 && isResponse() && (_status < 200 || _status == 204 || _status == 304))
+                    if (isResponse() && _noContent)
+                    {
                         _contentLength = HttpTokens.NO_CONTENT;
+                        _contentWritten=0;
+                    }
                     else if (_last)
                     {
                         // we have seen all the _content there is
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 bc7725d..1effdad 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
@@ -1032,7 +1032,7 @@
             {
                 LOG.warn("HttpParser Full for {} ",_endp);
                 _buffer.clear();
-                throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
+                throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head"));
             }
 
             try
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 01b0397..50c67dc 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
@@ -151,7 +151,16 @@
     @Override
     public Object put(Object pathSpec, Object object)
     {
-        StringTokenizer tok = new StringTokenizer(pathSpec.toString(),__pathSpecSeparators);
+        String str = pathSpec.toString();
+        if ("".equals(str.trim()))
+        {          
+            Entry entry = new Entry("",object);
+            entry.setMapped("");
+            _exactMap.put("", entry);
+            return super.put("", object);
+        }
+        
+        StringTokenizer tok = new StringTokenizer(str,__pathSpecSeparators);
         Object old =null;
 
         while (tok.hasMoreTokens())
@@ -223,13 +232,21 @@
      */
     public Entry getMatch(String path)
     {
-        Map.Entry entry;
+        Map.Entry entry=null;
 
         if (path==null)
             return null;
 
         int l=path.length();
-
+        
+        //special case
+        if (l == 1 && path.charAt(0)=='/')
+        {
+            entry = (Map.Entry)_exactMap.get("");
+            if (entry != null)
+                return (Entry)entry;
+        }
+        
         // try exact match
         entry=_exactMap.getEntry(path,0,l);
         if (entry!=null)
@@ -397,6 +414,9 @@
     public static boolean match(String pathSpec, String path, boolean noDefault)
     throws IllegalArgumentException
     {
+        if (pathSpec.length()==0)
+            return "/".equals(path);
+            
         char c = pathSpec.charAt(0);
         if (c=='/')
         {
@@ -460,6 +480,9 @@
      */
     public static String pathInfo(String pathSpec, String path)
     {
+        if ("".equals(pathSpec))
+            return path; //servlet 3 spec sec 12.2 will be '/'
+        
         char c = pathSpec.charAt(0);
 
         if (c=='/')
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 4497f42..2f84911 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
@@ -18,9 +18,6 @@
 
 package org.eclipse.jetty.http;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -33,6 +30,9 @@
 import org.eclipse.jetty.io.View;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 public class HttpGeneratorClientTest
 {
     public final static String CONTENT="The quick brown fox jumped over the lazy dog.\nNow is the time for all good men to come to the aid of the party\nThe moon is blue to a fish in love.\n";
@@ -125,7 +125,7 @@
      * screw up the chunking by leaving out the second chunk header.
      */
     @Test
-    public void testChunkedWithBackPressure() throws Exception 
+    public void testChunkedWithBackPressure() throws Exception
     {
         final AtomicInteger availableChannelBytes = new AtomicInteger(500);
         ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[0],4096)
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 530849d..721f702 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
@@ -444,7 +444,7 @@
             {
                 if (t+1 < tests.length)
                     throw e;
-                assertTrue(e.toString().indexOf("FULL")>=0);
+                assertTrue(e.toString().indexOf("Request Entity Too Large")>=0);
             }
         }
     }
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 4cae3f1..887662e 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
@@ -41,6 +41,7 @@
         p.put("*.gz", "7");
         p.put("/", "8");
         p.put("/XXX:/YYY", "9");
+        p.put("", "10");
 
         String[][] tests = {
                         { "/abs/path", "1"},
@@ -73,7 +74,7 @@
         assertEquals("Dir matches", "[/animal/fish/*=4, /animal/*=5, /=8]", p.getMatches("/animal/fish/").toString());
         assertEquals("Dir matches", "[/animal/fish/*=4, /animal/*=5, /=8]", p.getMatches("/animal/fish").toString());
         assertEquals("Dir matches", "[/=8]", p.getMatches("/").toString());
-        assertEquals("Dir matches", "[/=8]", p.getMatches("").toString());
+        assertEquals("Dir matches", "[=10, /=8]", p.getMatches("").toString());
 
         assertEquals("pathMatch exact", "/Foo/bar", PathMap.pathMatch("/Foo/bar", "/Foo/bar"));
         assertEquals("pathMatch prefix", "/Foo", PathMap.pathMatch("/Foo/*", "/Foo/bar"));
@@ -130,6 +131,10 @@
         assertTrue("!match /foo/*", !PathMap.match("/foo/*", "/bar/anything"));
         assertTrue("match *.foo", PathMap.match("*.foo", "anything.foo"));
         assertTrue("!match *.foo", !PathMap.match("*.foo", "anything.bar"));
+
+        assertEquals("match / with ''", "10", p.getMatch("/").getValue());
+        
+        assertTrue("match \"\"", PathMap.match("", "/"));
     }
 
     /**
diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml
index 17ec0a1..5d018e6 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-io</artifactId>
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffer.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffer.java
index ea0cc10..0569e1b 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffer.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffer.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.charset.Charset;
 
 import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.util.log.Log;
@@ -505,43 +506,37 @@
 
     public void setGetIndex(int getIndex)
     {
-        /* bounds checking */
-        if (__boundsChecking)
-        {
-            if (isImmutable()) 
-                throw new IllegalStateException(__IMMUTABLE);
-            if (getIndex < 0)
-                throw new IllegalArgumentException("getIndex<0: " + getIndex + "<0");
-            if (getIndex > putIndex())
-                throw new IllegalArgumentException("getIndex>putIndex: " + getIndex + ">" + putIndex());
-        }
-        
+        /* bounds checking
+        if (isImmutable()) 
+            throw new IllegalStateException(__IMMUTABLE);
+        if (getIndex < 0)
+            throw new IllegalArgumentException("getIndex<0: " + getIndex + "<0");
+        if (getIndex > putIndex())
+            throw new IllegalArgumentException("getIndex>putIndex: " + getIndex + ">" + putIndex());
+         */
         _get = getIndex;
         _hash=0;
     }
 
     public void setMarkIndex(int index)
     {
-        
+        /*
         if (index>=0 && isImmutable()) 
             throw new IllegalStateException(__IMMUTABLE);
-        
+        */
         _mark = index;
     }
 
     public void setPutIndex(int putIndex)
     {
-        if (__boundsChecking)
-        {
-            /* bounds checking */
-            if (isImmutable()) 
-                throw new IllegalStateException(__IMMUTABLE);
-            if (putIndex > capacity())
+        /* bounds checking
+        if (isImmutable()) 
+            throw new IllegalStateException(__IMMUTABLE);
+        if (putIndex > capacity())
                 throw new IllegalArgumentException("putIndex>capacity: " + putIndex + ">" + capacity());
-            if (getIndex() > putIndex)
+        if (getIndex() > putIndex)
                 throw new IllegalArgumentException("getIndex>putIndex: " + getIndex() + ">" + putIndex);
-        }
-
+         */
         _put = putIndex;
         _hash=0;
     }
@@ -651,6 +646,23 @@
     }
 
     /* ------------------------------------------------------------ */
+    public String toString(Charset charset)
+    {
+        try
+        {
+            byte[] bytes=array();
+            if (bytes!=null)
+                return new String(bytes,getIndex(),length(),charset);
+            return new String(asArray(), 0, length(),charset);
+        }
+        catch(Exception e)
+        {
+            LOG.warn(e);
+            return new String(asArray(), 0, length());
+        }
+    }
+
+    /* ------------------------------------------------------------ */
     public String toDebugString()
     {
         return getClass()+"@"+super.hashCode();
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/Buffer.java b/jetty-io/src/main/java/org/eclipse/jetty/io/Buffer.java
index 8f0ac59..5bb42ef 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/Buffer.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/Buffer.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.charset.Charset;
 
 
 /**
@@ -365,7 +366,10 @@
     /* ------------------------------------------------------------ */
     String toString(String charset);
     
-    /* 
+    /* ------------------------------------------------------------ */
+    String toString(Charset charset);
+
+    /*
      * Buffers implementing this interface should be compared with case insensitive equals
      *
      */
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java b/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java
index e08e508..c778b62 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java
@@ -354,6 +354,6 @@
     {
         if (buffer instanceof CachedBuffer)
             return buffer.toString();
-        return buffer.toString(StringUtil.__ISO_8859_1);
+        return buffer.toString(StringUtil.__ISO_8859_1_CHARSET);
     }
 }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedIOException.java b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedIOException.java
new file mode 100644
index 0000000..47b41ba
--- /dev/null
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedIOException.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.io;
+
+/* ------------------------------------------------------------ */
+/**
+ * Subclass of {@link java.lang.RuntimeException} used to signal that there
+ * was an {@link java.io.IOException} thrown by underlying {@link UncheckedPrintWriter}
+ */
+public class UncheckedIOException extends RuntimeException
+{
+    public UncheckedIOException()
+    {
+        super();
+    }
+
+    public UncheckedIOException(String message)
+    {
+        super(message);
+    }
+
+    public UncheckedIOException(Throwable cause)
+    {
+        super(cause);
+    }
+
+    public UncheckedIOException(String message, Throwable cause)
+    {
+        super(message,cause);
+    }
+}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java
index 4b9771b..07e82c2 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.io.nio;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
@@ -86,6 +87,8 @@
 
     private volatile long _idleTimestamp;
     private volatile boolean _checkIdle;
+    
+    private boolean _interruptable;
 
     private boolean _ishut;
 
@@ -445,9 +448,11 @@
                         updateKey();
                         this.wait(timeoutMs>0?(end-now):10000);
                     }
-                    catch (InterruptedException e)
+                    catch (final InterruptedException e)
                     {
                         LOG.warn(e);
+                        if (_interruptable)
+                            throw new InterruptedIOException(){{this.initCause(e);}};
                     }
                     finally
                     {
@@ -493,9 +498,11 @@
                         updateKey();
                         this.wait(timeoutMs>0?(end-now):10000);
                     }
-                    catch (InterruptedException e)
+                    catch (final InterruptedException e)
                     {
                         LOG.warn(e);
+                        if (_interruptable)
+                            throw new InterruptedIOException(){{this.initCause(e);}};
                     }
                     finally
                     {
@@ -515,6 +522,28 @@
     }
 
     /* ------------------------------------------------------------ */
+    /** Set the interruptable mode of the endpoint.
+     * If set to false (default), then interrupts are assumed to be spurious 
+     * and blocking operations continue unless the endpoint has been closed.
+     * If true, then interrupts of blocking operations result in InterruptedIOExceptions
+     * being thrown.
+     * @param interupable
+     */
+    public void setInterruptable(boolean interupable)
+    {
+        synchronized (this)
+        {
+            _interruptable=interupable;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isInterruptable()
+    {
+        return _interruptable;
+    }
+    
+    /* ------------------------------------------------------------ */
     /**
      * @see org.eclipse.jetty.io.AsyncEndPoint#scheduleWrite()
      */
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslConnection.java
index 42c9dab..c72d26b 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslConnection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslConnection.java
@@ -330,11 +330,11 @@
                 try
                 {
                     // Read any available data
-                    if (_inbound.space()>0 && (filled=_endp.fill(_inbound))>0)
+                    if (_inbound.space() > 0 && (filled = _endp.fill(_inbound)) > 0)
                         progress = true;
 
                     // flush any output data
-                    if (_outbound.hasContent() && (flushed=_endp.flush(_outbound))>0)
+                    if (_outbound.hasContent() && (flushed=_endp.flush(_outbound)) > 0)
                         progress = true;
                 }
                 catch (IOException e)
@@ -444,7 +444,8 @@
     {
         ByteBuffer bbuf=extractByteBuffer(buffer);
         final SSLEngineResult result;
-
+        int encrypted_produced = 0;
+        int decrypted_consumed = 0;
         synchronized(bbuf)
         {
             _outbound.compact();
@@ -455,8 +456,12 @@
                 {
                     bbuf.position(buffer.getIndex());
                     bbuf.limit(buffer.putIndex());
+                    int decrypted_position = bbuf.position();
+
                     out_buffer.position(_outbound.putIndex());
                     out_buffer.limit(out_buffer.capacity());
+                    int encrypted_position = out_buffer.position();
+
                     result=_engine.wrap(bbuf,out_buffer);
                     if (_logger.isDebugEnabled())
                         _logger.debug("{} wrap {} {} consumed={} produced={}",
@@ -466,9 +471,11 @@
                             result.bytesConsumed(),
                             result.bytesProduced());
 
+                    decrypted_consumed = bbuf.position() - decrypted_position;
+                    buffer.skip(decrypted_consumed);
 
-                    buffer.skip(result.bytesConsumed());
-                    _outbound.setPutIndex(_outbound.putIndex()+result.bytesProduced());
+                    encrypted_produced = out_buffer.position() - encrypted_position;
+                    _outbound.setPutIndex(_outbound.putIndex() + encrypted_produced);
                 }
                 catch(SSLException e)
                 {
@@ -476,6 +483,14 @@
                     _endp.close();
                     throw e;
                 }
+                catch (IOException x)
+                {
+                    throw x;
+                }
+                catch (Exception x)
+                {
+                    throw new IOException(x);
+                }
                 finally
                 {
                     out_buffer.position(0);
@@ -510,7 +525,7 @@
             throw new IOException(result.toString());
         }
 
-        return result.bytesConsumed()>0 || result.bytesProduced()>0;
+        return decrypted_consumed > 0 || encrypted_produced > 0;
     }
 
     private synchronized boolean unwrap(final Buffer buffer) throws IOException
@@ -520,7 +535,8 @@
 
         ByteBuffer bbuf=extractByteBuffer(buffer);
         final SSLEngineResult result;
-
+        int encrypted_consumed = 0;
+        int decrypted_produced = 0;
         synchronized(bbuf)
         {
             ByteBuffer in_buffer=_inbound.getByteBuffer();
@@ -530,8 +546,11 @@
                 {
                     bbuf.position(buffer.putIndex());
                     bbuf.limit(buffer.capacity());
+                    int decrypted_position = bbuf.position();
+
                     in_buffer.position(_inbound.getIndex());
                     in_buffer.limit(_inbound.putIndex());
+                    int encrypted_position = in_buffer.position();
 
                     result=_engine.unwrap(in_buffer,bbuf);
                     if (_logger.isDebugEnabled())
@@ -542,9 +561,12 @@
                             result.bytesConsumed(),
                             result.bytesProduced());
 
-                    _inbound.skip(result.bytesConsumed());
+                    encrypted_consumed = in_buffer.position() - encrypted_position;
+                    _inbound.skip(encrypted_consumed);
                     _inbound.compact();
-                    buffer.setPutIndex(buffer.putIndex()+result.bytesProduced());
+
+                    decrypted_produced = bbuf.position() - decrypted_position;
+                    buffer.setPutIndex(buffer.putIndex() + decrypted_produced);
                 }
                 catch(SSLException e)
                 {
@@ -552,6 +574,14 @@
                     _endp.close();
                     throw e;
                 }
+                catch (IOException x)
+                {
+                    throw x;
+                }
+                catch (Exception x)
+                {
+                    throw new IOException(x);
+                }
                 finally
                 {
                     in_buffer.position(0);
@@ -592,7 +622,7 @@
         //if (LOG.isDebugEnabled() && result.bytesProduced()>0)
         //    LOG.debug("{} unwrapped '{}'",_session,buffer);
 
-        return result.bytesConsumed()>0 || result.bytesProduced()>0;
+        return encrypted_consumed > 0 || decrypted_produced > 0;
     }
 
 
@@ -634,9 +664,16 @@
         {
             synchronized (SslConnection.this)
             {
-                _logger.debug("{} ssl endp.oshut {}",_session,this);
-                _engine.closeOutbound();
-                _oshut=true;
+                try
+                {
+                    _logger.debug("{} ssl endp.oshut {}",_session,this);
+                    _oshut=true;
+                    _engine.closeOutbound();
+                }
+                catch (Exception x)
+                {
+                    throw new IOException(x);
+                }
             }
             flush();
         }
diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml
index 05f58e0..e91985b 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jaspi</artifactId>
@@ -23,6 +23,12 @@
             <goals>
               <goal>manifest</goal>
             </goals>
+            <configuration>
+              <instructions>
+                <Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
+                <Export-Package>org.eclipse.jetty.security.jaspi.*;version="${parsedVersion.osgiVersion}"</Export-Package>
+              </instructions>
+            </configuration>
           </execution>
         </executions>
       </plugin>
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 bcb88be..ba43830 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
@@ -31,6 +31,8 @@
 import javax.security.auth.message.config.ServerAuthContext;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
 import org.eclipse.jetty.security.Authenticator;
 import org.eclipse.jetty.security.IdentityService;
@@ -38,15 +40,21 @@
 import org.eclipse.jetty.security.UserAuthentication;
 import org.eclipse.jetty.security.authentication.DeferredAuthentication;
 import org.eclipse.jetty.security.authentication.LoginAuthenticator;
+import org.eclipse.jetty.security.authentication.SessionAuthentication;
+import org.eclipse.jetty.security.jaspi.modules.BaseAuthModule;
 import org.eclipse.jetty.server.Authentication;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.server.Authentication.User;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 
 /**
  * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
  */
 public class JaspiAuthenticator extends LoginAuthenticator
 {
+    private static final Logger LOG = Log.getLogger(JaspiAuthenticator.class.getName());
+    
     private final ServerAuthConfig _authConfig;
 
     private final Map _authProperties;
@@ -107,6 +115,28 @@
     }
 
 
+    /** 
+     * @see org.eclipse.jetty.security.authentication.LoginAuthenticator#login(java.lang.String, java.lang.Object, javax.servlet.ServletRequest)
+     */
+    @Override
+    public UserIdentity login(String username, Object password, ServletRequest request)
+    { 
+        UserIdentity user = _loginService.login(username, password);
+        if (user != null)
+        {
+            renewSession((HttpServletRequest)request, null);
+            HttpSession session = ((HttpServletRequest)request).getSession(true);
+            if (session != null)
+            {
+                SessionAuthentication sessionAuth = new SessionAuthentication(getAuthMethod(), user, password);
+                session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, sessionAuth);
+            }
+        }
+        return user;
+    }
+
+    
+
     public Authentication validateRequest(JaspiMessageInfo messageInfo) throws ServerAuthException
     {
         try
@@ -151,6 +181,12 @@
                     String[] groups = groupPrincipalCallback == null ? null : groupPrincipalCallback.getGroups();
                     userIdentity = _identityService.newUserIdentity(clientSubject, principal, groups);
                 }
+                
+                HttpSession session = ((HttpServletRequest)messageInfo.getRequestMessage()).getSession(false);
+                Authentication cached = (session == null?null:(SessionAuthentication)session.getAttribute(SessionAuthentication.__J_AUTHENTICATED));
+                if (cached != null)
+                    return cached;
+                
                 return new UserAuthentication(getAuthMethod(), userIdentity);
             }
             if (authStatus == AuthStatus.SEND_SUCCESS)
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 d6897b8..204a282 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
@@ -70,7 +70,7 @@
         return true;
     }
 
-    public void refresh()
+    public void refresh() 
     {
     }
 }
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 af2be3c..9de5370 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
@@ -43,7 +43,10 @@
 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;
+import org.eclipse.jetty.security.jaspi.callback.CredentialValidationCallback;
 import org.eclipse.jetty.server.Authentication;
+import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.log.Log;
@@ -214,21 +217,22 @@
             
             
             // Check if the session is already authenticated.
-            FormCredential form_cred = (FormCredential) session.getAttribute(__J_AUTHENTICATED);
-            if (form_cred != null)
+            SessionAuthentication sessionAuth = (SessionAuthentication)session.getAttribute(SessionAuthentication.__J_AUTHENTICATED);
+            if (sessionAuth != null)
             {                
                 //TODO: ideally we would like the form auth module to be able to invoke the 
                 //loginservice.validate() method to check the previously authed user, but it is not visible
                 //to FormAuthModule
-                if (form_cred._subject == null)
+                if (sessionAuth.getUserIdentity().getSubject() == null)
                     return AuthStatus.SEND_FAILURE;
-                Set<Object> credentials = form_cred._subject.getPrivateCredentials();
+
+                Set<Object> credentials = sessionAuth.getUserIdentity().getSubject().getPrivateCredentials();
                 if (credentials == null || credentials.isEmpty())
                     return AuthStatus.SEND_FAILURE; //if no private credentials, assume it cannot be authenticated
 
                 clientSubject.getPrivateCredentials().addAll(credentials);
+                clientSubject.getPrivateCredentials().add(sessionAuth.getUserIdentity());
 
-                //boolean success = tryLogin(messageInfo, clientSubject, response, session, form_cred._jUserName, new Password(new String(form_cred._jPassword)));
                 return AuthStatus.SUCCESS;  
             }
             else if (ssoSource != null)
@@ -300,8 +304,14 @@
             if (!loginCallbacks.isEmpty())
             {
                 LoginCallbackImpl loginCallback = loginCallbacks.iterator().next();
-                FormCredential form_cred = new FormCredential(username, pwdChars, loginCallback.getUserPrincipal(), loginCallback.getSubject());
-                session.setAttribute(__J_AUTHENTICATED, form_cred);
+                Set<UserIdentity> userIdentities = clientSubject.getPrivateCredentials(UserIdentity.class);
+                if (!userIdentities.isEmpty())
+                {
+                    UserIdentity userIdentity = userIdentities.iterator().next();
+                   
+                SessionAuthentication sessionAuth = new SessionAuthentication(Constraint.__FORM_AUTH, userIdentity, password);
+                session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, sessionAuth);
+                }
             }
 
             // Sign-on to SSO mechanism
@@ -320,61 +330,4 @@
         return pathInContext != null && (pathInContext.equals(_formErrorPath) || pathInContext.equals(_formLoginPath));
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * FORM Authentication credential holder.
-     */
-    private static class FormCredential implements Serializable, HttpSessionBindingListener
-    {
-        String _jUserName;
-
-        char[] _jPassword;
-
-        transient Principal _userPrincipal;
-        
-        transient Subject _subject;
-
-        private FormCredential(String _jUserName, char[] _jPassword, Principal _userPrincipal, Subject subject)
-        {
-            this._jUserName = _jUserName;
-            this._jPassword = _jPassword;
-            this._userPrincipal = _userPrincipal;
-            this._subject = subject;
-        }
-
-        public void valueBound(HttpSessionBindingEvent event)
-        {
-        }
-
-        public void valueUnbound(HttpSessionBindingEvent event)
-        {
-            if (LOG.isDebugEnabled()) LOG.debug("Logout " + _jUserName);
-
-            // TODO jaspi call cleanSubject()
-            // if (_realm instanceof SSORealm)
-            // ((SSORealm) _realm).clearSingleSignOn(_jUserName);
-            //
-            // if (_realm != null && _userPrincipal != null)
-            // _realm.logout(_userPrincipal);
-        }
-
-        public int hashCode()
-        {
-            return _jUserName.hashCode() + _jPassword.hashCode();
-        }
-
-        public boolean equals(Object o)
-        {
-            if (!(o instanceof FormCredential)) return false;
-            FormCredential fc = (FormCredential) o;
-            return _jUserName.equals(fc._jUserName) && Arrays.equals(_jPassword, fc._jPassword);
-        }
-
-        public String toString()
-        {
-            return "Cred[" + _jUserName + "]";
-        }
-
-    }
-
 }
diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml
index 8d9c2db..adc9675 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jmx</artifactId>
diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml
index 3bd2171..f634bab 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jndi</artifactId>
diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml
index 1c79e3d..3fc9a10 100644
--- a/jetty-jsp/pom.xml
+++ b/jetty-jsp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jsp</artifactId>
@@ -17,13 +17,13 @@
     <dependency>
       <groupId>org.eclipse.jetty.orbit</groupId>
       <artifactId>javax.servlet.jsp</artifactId>
-      <version>2.1.0.v201105211820</version>
+      <version>2.2.0.v201112011158</version>
     </dependency>
     <!-- JSP Impl -->
     <dependency>
        <groupId>org.eclipse.jetty.orbit</groupId>
        <artifactId>org.apache.jasper.glassfish</artifactId>
-       <version>2.1.0.v201110031002</version>
+       <version>2.2.2.v201112011158</version>
     </dependency>
     <!-- JSTL Api -->
     <dependency>
@@ -41,13 +41,13 @@
     <dependency>
       <groupId>org.eclipse.jetty.orbit</groupId>
       <artifactId>javax.el</artifactId>
-      <version>2.1.0.v201105211819</version>
+      <version>2.2.0.v201108011116</version>
     </dependency>
     <!-- EL Impl -->
     <dependency>
       <groupId>org.eclipse.jetty.orbit</groupId>
       <artifactId>com.sun.el</artifactId>
-      <version>1.0.0.v201105211818</version>
+      <version>2.2.0.v201108011116</version>
     </dependency>
     <!-- Eclipse Java Compiler (for JSP Compilation) -->
     <dependency>
diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml
index 69164a9..299c9fd 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-monitor</artifactId>
diff --git a/jetty-nested/pom.xml b/jetty-nested/pom.xml
index d74e1dc..644ea0f 100644
--- a/jetty-nested/pom.xml
+++ b/jetty-nested/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>jetty-nested</artifactId>
   <name>Jetty :: Nested</name>
@@ -27,7 +27,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>javax.servlet*;version="2.5.0",*</Import-Package>
+                <Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
               </instructions>
             </configuration>
            </execution>
diff --git a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java b/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java
index 345b9ab..69a66c7 100644
--- a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java
+++ b/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.util.Enumeration;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
@@ -30,7 +31,6 @@
 import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.server.AbstractHttpConnection;
-import org.eclipse.jetty.server.DispatcherType;
 
 
 public class NestedConnection extends AbstractHttpConnection
diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml
index da6db62..13cbdbc 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-nosql</artifactId>
@@ -29,7 +29,7 @@
         <artifactId>maven-bundle-plugin</artifactId>
         <configuration>
           <instructions>
-            <Import-Package>javax.servlet.*;version="[2.5,3.0)",org.eclipse.jetty.server.session.jmx;version="[7.5,8)";resolution:=optional,,org.eclipse.jetty.*;version="[7.5,8)",*</Import-Package>
+            <Import-Package>javax.servlet.*;version="2.6.0",org.eclipse.jetty.server.session.jmx;version="8.0.0";resolution:=optional,,org.eclipse.jetty.*;version="8.0.0",*</Import-Package>
           </instructions>
         </configuration>
         <extensions>true</extensions>
diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml
index fce28ce..2153ac8 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -94,28 +94,27 @@
  com.sun.el.lang;resolution:=optional,
  com.sun.el.parser;resolution:=optional,
  com.sun.el.util;resolution:=optional,
- com.sun.org.apache.commons.logging;split=glassfish;version="[2.1,3)";resolution:=optional,
- javax.el;version="1.0.0";resolution:=optional,
- javax.servlet;version="2.5.0",
- javax.servlet.jsp;version="2.1.0",
- javax.servlet.jsp.el;version="2.1.0",
+ javax.el;version="2.2.0";resolution:=optional,
+ javax.servlet;version="2.6.0",
+ javax.servlet.jsp;version="2.2.0",
+ javax.servlet.jsp.el;version="2.2.0",
  javax.servlet.jsp.jstl.core;version="1.2.0";resolution:=optional,
  javax.servlet.jsp.jstl.fmt;version="1.2.0";resolution:=optional,
  javax.servlet.jsp.jstl.sql;version="1.2.0";resolution:=optional,
  javax.servlet.jsp.jstl.tlv;version="1.2.0";resolution:=optional,
- javax.servlet.jsp.resources;version="2.1.0",
- javax.servlet.jsp.tagext;version="2.1.0",
- javax.servlet.resources;version="2.5.0",
- org.apache.jasper;version="6.0.0";resolution:=optional,
- org.apache.jasper.compiler;version="6.0.0";resolution:=optional,
- org.apache.jasper.compiler.tagplugin;version="6.0.0";resolution:=optional,
- org.apache.jasper.runtime;version="6.0.0";resolution:=optional,
- org.apache.jasper.security;version="6.0.0";resolution:=optional,
- org.apache.jasper.servlet;version="6.0.0";resolution:=optional,
- org.apache.jasper.tagplugins.jstl;version="6.0.0";resolution:=optional,
- org.apache.jasper.util;version="6.0.0";resolution:=optional,
- org.apache.jasper.xmlparser;version="6.0.0";resolution:=optional,
- org.glassfish.jsp.api;version="2.1.3";resolution:=optional,
+ javax.servlet.jsp.resources;version="2.2.0",
+ javax.servlet.jsp.tagext;version="2.2.0",
+ javax.servlet.resources;version="2.6.0",
+ org.apache.jasper;version="2.2.2";resolution:=optional,
+ org.apache.jasper.compiler;version="2.2.2";resolution:=optional,
+ org.apache.jasper.compiler.tagplugin;version="2.2.2";resolution:=optional,
+ org.apache.jasper.runtime;version="2.2.2";resolution:=optional,
+ org.apache.jasper.security;version="2.2.2";resolution:=optional,
+ org.apache.jasper.servlet;version="2.2.2";resolution:=optional,
+ org.apache.jasper.tagplugins.jstl;version="2.2.2";resolution:=optional,
+ org.apache.jasper.util;version="2.2.2";resolution:=optional,
+ org.apache.jasper.xmlparser;version="2.2.2";resolution:=optional,
+ org.glassfish.jsp.api;version="2.2.2";resolution:=optional,
  org.apache.taglibs.standard;version="1.2.0";resolution:=optional,
  org.apache.taglibs.standard.extra.spath;version="1.2.0";resolution:=optional,
  org.apache.taglibs.standard.functions;version="1.2.0";resolution:=optional,
@@ -139,13 +138,13 @@
  org.apache.taglibs.standard.tag.rt.xml;version="1.2.0";resolution:=optional,
  org.apache.taglibs.standard.tei;version="1.2.0";resolution:=optional,
  org.apache.taglibs.standard.tlv;version="1.2.0";resolution:=optional,
- org.eclipse.jetty.jsp;version="[7.0,8.0)";resolution:=optional,
  !org.osgi.*,
  !org.xml.*,
  !org.eclipse.jetty.*,
  *
                 </Import-Package>
                 <_nouses>true</_nouses>
+                <!-- DynamicImport-Package>org.apache.jasper.*;version="2.2.2"</DynamicImport-Package -->
               </instructions>
           </configuration>
       </plugin>
diff --git a/jetty-osgi/jetty-osgi-boot-logback/META-INF/readme.txt b/jetty-osgi/jetty-osgi-boot-logback/META-INF/readme.txt
deleted file mode 100644
index 20960b4..0000000
--- a/jetty-osgi/jetty-osgi-boot-logback/META-INF/readme.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This bundle is made to inject the logback dependencies along with the slf4j dependencies to support log4j and commons-logging.
-It will read the configuration in the jettyhome/resources/logback-test.xml or jettyhome/resources/logback.xml folder. 
-
-
-It was tested with these bundles:
-#this provides lg4j and commons-logging via slf4j
-SLF4J = group("com.springsource.slf4j.api", "com.springsource.slf4j.org.apache.log4j", "com.springsource.slf4j.org.apache.commons.logging",
-          :under=>"org.slf4j", :version=>"1.5.6")
-
-#logback is not exporting enough packages for us to be able to configure logback classic programatically.. on the springsource version they are fine...
-LOGBACK = group("com.springsource.ch.qos.logback.core", "com.springsource.ch.qos.logback.classic",
-          :under=>"ch.qos.logback", :version=>"0.9.15")
\ No newline at end of file
diff --git a/jetty-osgi/jetty-osgi-boot-logback/build.properties b/jetty-osgi/jetty-osgi-boot-logback/build.properties
deleted file mode 100644
index 6d10c98..0000000
--- a/jetty-osgi/jetty-osgi-boot-logback/build.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-source.. = src/main/java/
-output.. = target/classes/
-bin.includes = META-INF/,\
-               .
-src.includes = META-INF/
diff --git a/jetty-osgi/jetty-osgi-boot-logback/pom.xml b/jetty-osgi/jetty-osgi-boot-logback/pom.xml
index 26c2c00..83a619f 100644
--- a/jetty-osgi/jetty-osgi-boot-logback/pom.xml
+++ b/jetty-osgi/jetty-osgi-boot-logback/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.18-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml
index 9a5e356..066c364 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -80,6 +80,4 @@
       </plugin>
     </plugins>
   </build>
-
-
 </project>
diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho
deleted file mode 100644
index b30ae7a..0000000
--- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <artifactId>jetty-osgi</artifactId>
-    <version>7.0.1-SNAPSHOT</version>
-    <groupId>org.eclipse.jetty.osgi</groupId>
-  </parent>
-  <groupId>org.eclipse.jetty.osgi</groupId>
-  <artifactId>org.eclipse.jetty.osgi.boot.warurl</artifactId>
-  <version>7.0.1.qualifier</version>
-  <packaging>eclipse-plugin</packaging>
-</project>
diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml
index 1d555e1..913daf0 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -16,6 +16,10 @@
   <dependencies>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
+        <artifactId>jetty-annotations</artifactId>
+      </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-webapp</artifactId>
     </dependency>
     <dependency>
@@ -115,10 +119,12 @@
  javax.mail.internet;version="1.4.0";resolution:=optional,
  javax.mail.search;version="1.4.0";resolution:=optional,
  javax.mail.util;version="1.4.0";resolution:=optional,
- javax.servlet;version="2.5.0",
- javax.servlet.http;version="2.5.0",
+ javax.servlet;version="2.6.0",
+ javax.servlet.http;version="2.6.0",
  javax.transaction;version="1.1.0";resolution:=optional,
  javax.transaction.xa;version="1.1.0";resolution:=optional,
+ org.eclipse.jetty.nested;version="[8.1,9)";resolution:=optional,
+ org.eclipse.jetty.annotations;version="[8.1,9)";resolution:=optional,
  org.osgi.framework,
  org.osgi.service.cm;version="1.2.0",
  org.osgi.service.packageadmin,
@@ -130,12 +136,11 @@
  org.slf4j.helpers;resolution:=optional,
  org.xml.sax,
  org.xml.sax.helpers,
- org.eclipse.jetty.nested;resolution:=optional,
  *
                         </Import-Package>
-                        <DynamicImport-Package>org.eclipse.jetty.*;version="[7.6,8)"</DynamicImport-Package>
+                        <DynamicImport-Package>org.eclipse.jetty.*;version="[8.1,9)"</DynamicImport-Package>
                         <!--Require-Bundle/-->
-                        <!-- Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment --> 
+                        <!-- Bundle-RequiredExecutionEnvironment>JavaSE-1.6</Bundle-RequiredExecutionEnvironment--> 
                     </instructions>
                 </configuration>
             </plugin>
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
new file mode 100644
index 0000000..945b235
--- /dev/null
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java
@@ -0,0 +1,210 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      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.annotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
+import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
+import org.eclipse.jetty.annotations.ClassNameResolver;
+import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
+import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.webapp.DiscoveredAnnotation;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+/**
+ * Extend the AnnotationConfiguration to support OSGi:
+ * Look for annotations inside WEB-INF/lib and also in the fragments and required bundles.
+ * Discover them using a scanner adapted to OSGi instead of the jarscanner. 
+ */
+public class AnnotationConfiguration extends org.eclipse.jetty.annotations.AnnotationConfiguration
+{
+
+    /**
+     * This parser scans the bundles using the OSGi APIs instead of assuming a jar.
+     */
+    @Override
+    protected org.eclipse.jetty.annotations.AnnotationParser createAnnotationParser()
+    {
+        return new AnnotationParser();
+    }
+    
+    /**
+     * Here is the order in which jars and osgi artifacts are scanned for discoverable annotations.
+     * <ol>
+     * <li>The container jars are scanned.</li>
+     * <li>The WEB-INF/classes are scanned</li>
+     * <li>The osgi fragment to the web bundle are parsed.</li>
+     * <li>The WEB-INF/lib are scanned</li>
+     * <li>The required bundles are parsed</li>
+     * </ol>
+     */
+    @Override
+    public void parseWebInfLib (WebAppContext context, org.eclipse.jetty.annotations.AnnotationParser parser)
+    throws Exception
+    {
+        AnnotationParser oparser = (AnnotationParser)parser;
+        
+        Bundle webbundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
+        Bundle[] fragAndRequiredBundles = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(webbundle);
+        if (fragAndRequiredBundles != null)
+        {
+            //index:
+            for (Bundle bundle : fragAndRequiredBundles)
+            {
+                Resource bundleRes = oparser.indexBundle(bundle);
+                if (!context.getMetaData().getWebInfJars().contains(bundleRes))
+                {
+                    context.getMetaData().addWebInfJar(bundleRes);
+                }
+            }
+        
+            //scan the fragments
+            for (Bundle fragmentBundle : fragAndRequiredBundles)
+            {
+                if (fragmentBundle.getHeaders().get(Constants.FRAGMENT_HOST) != null)
+                {
+                    //a fragment indeed:
+                    parseFragmentBundle(context,oparser,webbundle,fragmentBundle);
+                }
+            }
+        }
+        //scan ourselves
+        parseWebBundle(context,oparser,webbundle);
+        
+        //scan the WEB-INF/lib
+        super.parseWebInfLib(context,parser);
+        if (fragAndRequiredBundles != null)
+        {
+            //scan the required bundles
+            for (Bundle requiredBundle : fragAndRequiredBundles)
+            {
+                if (requiredBundle.getHeaders().get(Constants.FRAGMENT_HOST) == null)
+                {
+                    //a bundle indeed:
+                    parseRequiredBundle(context,oparser,webbundle,requiredBundle);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Scan a fragment bundle for servlet annotations
+     * @param context The webapp context
+     * @param parser The parser
+     * @param webbundle The current webbundle
+     * @param fragmentBundle The OSGi fragment bundle to scan
+     * @throws Exception
+     */
+    protected void parseFragmentBundle(WebAppContext context, AnnotationParser parser,
+            Bundle webbundle, Bundle fragmentBundle) throws Exception
+    {
+        parseBundle(context,parser,webbundle,fragmentBundle);
+    }
+    
+    /**
+     * Scan a bundle required by the webbundle for servlet annotations
+     * @param context The webapp context
+     * @param parser The parser
+     * @param webbundle The current webbundle
+     * @param fragmentBundle The OSGi required bundle to scan
+     * @throws Exception
+     */
+    protected void parseWebBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle)
+    throws Exception
+    {
+        parseBundle(context,parser,webbundle,webbundle);
+    }
+    
+    /**
+     * Scan a bundle required by the webbundle for servlet annotations
+     * @param context The webapp context
+     * @param parser The parser
+     * @param webbundle The current webbundle
+     * @param fragmentBundle The OSGi required bundle to scan
+     * @throws Exception
+     */
+    protected void parseRequiredBundle(WebAppContext context, AnnotationParser parser,
+            Bundle webbundle, Bundle requiredBundle) throws Exception
+    {
+        parseBundle(context,parser,webbundle,requiredBundle);
+    }
+    
+    protected void parseBundle(WebAppContext context, AnnotationParser parser,
+            Bundle webbundle, Bundle bundle) throws Exception
+    {
+        
+        Resource bundleRes = parser.getResource(bundle);
+        
+        parser.clearHandlers();
+        for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
+        {
+            if (h instanceof AbstractDiscoverableAnnotationHandler)
+            {
+                if (webbundle == bundle)                    
+                ((AbstractDiscoverableAnnotationHandler)h).setResource(null); 
+                else
+                    ((AbstractDiscoverableAnnotationHandler)h).setResource(bundleRes);  
+            }
+        }
+        parser.registerHandlers(_discoverableAnnotationHandlers);
+        parser.registerHandler(_classInheritanceHandler);
+        parser.registerHandlers(_containerInitializerAnnotationHandlers);
+      
+        parser.parse(bundle,createClassNameResolver(context));
+    }
+    
+    /**
+     * Returns the same classname resolver than for the webInfjar scanner
+     * @param context
+     * @return
+     */
+    protected ClassNameResolver createClassNameResolver(final WebAppContext context)
+    {
+        return createClassNameResolver(context,true,false,false,false);
+    }
+    
+    protected ClassNameResolver createClassNameResolver(final WebAppContext context,
+            final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse,
+            final boolean overrideIsParenLoaderIsPriority)
+    {
+        return new ClassNameResolver ()
+        {
+            public boolean isExcluded (String name)
+            {
+                if (context.isSystemClass(name)) return excludeSysClass;
+                if (context.isServerClass(name)) return excludeServerClass;
+                return excludeEverythingElse;
+            }
+
+            public boolean shouldOverride (String name)
+            { 
+                //looking at system classpath
+                if (context.isParentLoaderPriority())
+                    return overrideIsParenLoaderIsPriority;
+                return !overrideIsParenLoaderIsPriority;
+            }
+        };
+    }
+
+}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java
new file mode 100644
index 0000000..4fc274d
--- /dev/null
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.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.osgi.annotations;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import org.eclipse.jetty.annotations.ClassNameResolver;
+import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
+import org.eclipse.jetty.util.resource.Resource;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+/**
+ * 
+ */
+public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationParser
+{
+    private Set<URI> _alreadyParsed = new HashSet<URI>();
+    
+    private Map<URI,Bundle> _uriToBundle = new HashMap<URI, Bundle>();
+    private Map<Bundle,Resource> _resourceToBundle = new HashMap<Bundle,Resource>();
+    private Map<Bundle,URI> _bundleToUri = new HashMap<Bundle, URI>();
+    
+    /**
+     * Keep track of a jetty URI Resource and its associated OSGi bundle.
+     * @param uri
+     * @param bundle
+     * @throws Exception 
+     */
+    protected Resource indexBundle(Bundle bundle) throws Exception
+    {
+        File bundleFile = BundleFileLocatorHelper.DEFAULT.getBundleInstallLocation(bundle);
+        Resource resource = Resource.newResource(bundleFile.toURI());
+        URI uri = resource.getURI();
+        _uriToBundle.put(uri,bundle);
+        _bundleToUri.put(bundle,uri);
+        _resourceToBundle.put(bundle,resource);
+        return resource;
+    }
+    protected URI getURI(Bundle bundle)
+    {
+        return _bundleToUri.get(bundle);
+    }
+    protected Resource getResource(Bundle bundle)
+    {
+        return _resourceToBundle.get(bundle);
+    }
+    /**
+     * 
+     */
+    @Override
+    public void parse (URI[] uris, ClassNameResolver resolver)
+    throws Exception
+    {
+        for (URI uri : uris)
+        {
+            Bundle associatedBundle = _uriToBundle.get(uri);
+            if (associatedBundle == null)
+            {
+                if (!_alreadyParsed.add(uri))
+                {
+                    continue;
+                }
+                //a jar in WEB-INF/lib or the WEB-INF/classes
+                //use the behavior of the super class for a standard jar.
+                super.parse(new URI[] {uri},resolver);
+            }
+            else
+            {
+                parse(associatedBundle,resolver);
+            }
+        }
+    }
+    
+    protected void parse(Bundle bundle, ClassNameResolver resolver)
+    throws Exception
+    {
+        URI uri = _bundleToUri.get(bundle);
+        if (!_alreadyParsed.add(uri))
+        {
+            return;
+        }
+        
+        String bundleClasspath = (String)bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH);
+        if (bundleClasspath == null)
+        {
+            bundleClasspath = ".";
+        }
+        //order the paths first by the number of tokens in the path second alphabetically.
+        TreeSet<String> paths = new TreeSet<String>(
+                new Comparator<String>()
+                {
+                    public int compare(String o1, String o2)
+                    {
+                        int paths1 = new StringTokenizer(o1,"/",false).countTokens();
+                        int paths2 = new StringTokenizer(o2,"/",false).countTokens();
+                        if (paths1 == paths2)
+                        {
+                            return o1.compareTo(o2);
+                        }
+                        return paths2 - paths1;
+                    }
+                });
+        boolean hasDotPath = false;
+        StringTokenizer tokenizer = new StringTokenizer(bundleClasspath, ",;", false);
+        while (tokenizer.hasMoreTokens())
+        {
+            String token = tokenizer.nextToken().trim();
+            if (!token.startsWith("/"))
+            {
+                token = "/" + token;
+            }
+            if (token.equals("/."))
+            {
+                hasDotPath = true;
+            }
+            else if (!token.endsWith(".jar") && !token.endsWith("/"))
+            {
+                paths.add(token+"/");
+            }
+            else
+            {
+                paths.add(token);
+            }
+        }
+        //support the development environment: maybe the classes are inside bin or target/classes
+        //this is certainly not useful in production.
+        //however it makes our life so much easier during development.
+        if (bundle.getEntry("/.classpath") != null)
+        {
+            if (bundle.getEntry("/bin/") != null)
+            {
+                paths.add("/bin/");
+            }
+            else if (bundle.getEntry("/target/classes/") != null)
+            {
+                paths.add("/target/classes/");
+            }
+        }
+        Enumeration classes = bundle.findEntries("/","*.class",true);
+        if (classes == null)
+        {
+            return;
+        }
+        while (classes.hasMoreElements())
+        {
+            URL classUrl = (URL) classes.nextElement();
+            String path = classUrl.getPath();
+            //remove the longest path possible:
+            String name = null;
+            for (String prefixPath : paths)
+            {
+                if (path.startsWith(prefixPath))
+                {
+                    name = path.substring(prefixPath.length());
+                    break;
+                }
+            }
+            if (name == null && hasDotPath)
+            {
+                //remove the starting '/'
+                name = path.substring(1);
+            }
+            //transform into a classname to pass to the resolver
+            String shortName =  name.replace('/', '.').substring(0,name.length()-6);
+            if ((resolver == null)|| (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
+                scanClass(classUrl.openStream());
+        }
+    }
+    
+}
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 bfc2295..ce430ef 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
@@ -105,8 +105,9 @@
         DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context);
 
         // track Bundles and deploy those that represent webapps to one of the known Servers
-        _webBundleTracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer());
-        _webBundleTracker.open();
+        WebBundleTrackerCustomizer customizer = new WebBundleTrackerCustomizer();
+        _webBundleTracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STOPPING, customizer);
+        customizer.setAndOpenWebBundleTracker(_webBundleTracker);
     }
 
     /**
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloader.java
index 73564b0..3100423 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloader.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloader.java
@@ -48,4 +48,18 @@
     {
         return _jarsWithTldsInside;
     }
+
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder();
+
+        if (_jarsWithTldsInside != null)
+        {
+            for (URL u:_jarsWithTldsInside)
+                builder.append(" "+u.toString());
+            return builder.toString();
+        }
+        else
+            return super.toString();
+    }
 }
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 bb965f6..22de401 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
@@ -232,7 +232,7 @@
                 // can define their own configuration.
                 if ((enUrls == null || !enUrls.hasMoreElements()))
                 {
-                    String tmp = DEFAULT_JETTYHOME+etcFile;
+                    String tmp = DEFAULT_JETTYHOME+(DEFAULT_JETTYHOME.endsWith("/")?"":"/")+etcFile;
                     enUrls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(configurationBundle, tmp);                    
                     LOG.info("Configuring jetty from bundle: "
                                        + configurationBundle.getSymbolicName()
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 c811839..40fbd2b 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
@@ -26,6 +26,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -109,7 +110,7 @@
             for (File f : jettyResources.listFiles())
             {
                 jettyResFiles.put(f.getName(), f);
-                if (f.getName().toLowerCase().startsWith("readme"))
+                if (f.getName().toLowerCase(Locale.ENGLISH).startsWith("readme"))
                 {
                     continue;
                 }
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java
index 7022757..50e5614 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java
@@ -30,6 +30,7 @@
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
 import org.osgi.util.tracker.BundleTracker;
 import org.osgi.util.tracker.BundleTrackerCustomizer;
 import org.osgi.util.tracker.ServiceTracker;
@@ -56,7 +57,7 @@
                                           "("+OSGiServerConstants.MANAGED_JETTY_SERVER_NAME+"="+OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME+"))";
 
     private ServiceTracker _serviceTracker;
-    
+    private BundleTracker _bundleTracker;
     
     /* ------------------------------------------------------------ */
     /**
@@ -68,8 +69,16 @@
         Bundle myBundle = FrameworkUtil.getBundle(this.getClass());
         
         //track all instances of deployers of webapps/contexts as bundles       
-        _serviceTracker = new ServiceTracker(myBundle.getBundleContext(), FrameworkUtil.createFilter(FILTER),null);
+        _serviceTracker = new ServiceTracker(myBundle.getBundleContext(), FrameworkUtil.createFilter(FILTER),null) {
+            public Object addingService(ServiceReference reference) {
+                Object object = super.addingService(reference);
+                LOG.debug("Deployer registered {}", reference);
+                openBundleTracker();
+                return object;
+            }
+        };
         _serviceTracker.open();
+
     }
     
     
@@ -98,7 +107,7 @@
     {
         if (bundle.getState() == Bundle.ACTIVE)
         {
-           register(bundle);          
+            register(bundle);          
         }
         else if (bundle.getState() == Bundle.STOPPING)
         {
@@ -221,4 +230,21 @@
             }
         }
     }
+
+    public void setAndOpenWebBundleTracker(BundleTracker bundleTracker) {
+        if(_bundleTracker == null) {
+            _bundleTracker = bundleTracker;
+            LOG.debug("Bundle tracker is set");
+            openBundleTracker();
+        }
+    }
+
+    private void openBundleTracker() {
+        if(_bundleTracker != null && _serviceTracker.getServices() != null &&
+                _serviceTracker.getServices().length > 0) {
+            _bundleTracker.open();
+            LOG.debug("Bundle tracker has been opened");
+        }
+    }
+
 }
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 89b2bfd..a5b5079 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
@@ -380,3 +380,4 @@
     }
 
 }
+
diff --git a/jetty-osgi/jetty-osgi-equinoxtools/build.properties b/jetty-osgi/jetty-osgi-equinoxtools/build.properties
deleted file mode 100644
index 05786b0..0000000
--- a/jetty-osgi/jetty-osgi-equinoxtools/build.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               equinoxconsole/,\
-               .
diff --git a/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/index.html b/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/index.html
deleted file mode 100644
index 4deba32..0000000
--- a/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/index.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<html><head>
-    <title>Async Equinox Console</title>
-    <script type='text/javascript'>
-      function $() { return document.getElementById(arguments[0]); }
-      function $F() { return document.getElementById(arguments[0]).value; }
-      function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; } 
-      function xhr(method,uri,body,handler) {
-        var req=(window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');
-        req.onreadystatechange=function() { if (req.readyState==4 && handler) { eval('var o='+req.responseText);handler(o);} }
-        req.open(method,uri,true);
-        req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
-        req.send(body);
-      };
-      function send(action,user,message,handler){
-        if (message) message=message.replace('%','%25').replace('&','%26').replace('=','%3D');
-        if (user) user=user.replace('%','%25').replace('&','%26').replace('=','%3D');
-        xhr('POST','chat','action='+action+'&user='+user+'&message='+message,handler);
-      };
-      
-      var room = {
-        join: function(name) {
-          this._username=name;
-          $('join').className='hidden';
-          $('joined').className='';
-          $('phrase').focus();
-          send('join', room._username,null);
-          send('chat', room._username,'has joined!');
-          send('poll', room._username,null, room._poll);
-        },
-        chat: function(text) {
-          if (text != null && text.length>0 )
-              send('chat',room._username,text);
-        },
-        _poll: function(m) {
-          //console.debug(m);
-          if (m.chat){
-            var chat=document.getElementById('chat');
-            var spanFrom = document.createElement('span');
-            spanFrom.className='from';
-            spanFrom.innerHTML=m.from+'&nbsp;';
-            var spanText = document.createElement('span');
-            spanText.className='text';
-            spanText.innerHTML=m.chat;
-            var lineBreak = document.createElement('br');
-            chat.appendChild(spanFrom);
-            chat.appendChild(spanText);
-            chat.appendChild(lineBreak);
-            chat.scrollTop = chat.scrollHeight - chat.clientHeight;   
-          }
-          if (m.action=='poll')
-            send('poll', room._username,null, room._poll);
-        },
-        _end:''
-      };
-    </script>
-    <style type='text/css'>
-    div { border: 0px solid black; }
-    div#chat { clear: both; width: 40em; height: 20ex; overflow: auto; background-color: #f0f0f0; padding: 4px; border: 1px solid black; }
-    div#input { clear: both; width: 40em; padding: 4px; background-color: #e0e0e0; border: 1px solid black; border-top: 0px }
-    input#phrase { width:30em; background-color: #e0f0f0; }
-    input#username { width:14em; background-color: #e0f0f0; }
-    div.hidden { display: none; }
-    span.from { font-weight: bold; }
-    span.alert { font-style: italic; }
-    </style>
-</head><body>
-<div id='chat'></div>
-<div id='input'>
-  <div id='join' >
-    Username:&nbsp;<input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join' value='Join'/>
-  </div>
-  <div id='joined' class='hidden'>
-    OSGi:&nbsp;<input id='phrase' type='text'/>
-    <input id='sendB' class='button' type='submit' name='join' value='Send'/>
-  </div>
-</div>
-<script type='text/javascript'>
-$('username').setAttribute('autocomplete','OFF');
-$('username').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.join($F('username')); return false; } return true; } ;        
-$('joinB').onclick = function(event) { room.join($F('username')); return false; };
-$('phrase').setAttribute('autocomplete','OFF');
-$('phrase').onkeyup = function(ev) {   var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.chat($F('phrase')); $('phrase').value=''; return false; } return true; };
-$('sendB').onclick = function(event) { room.chat($F('phrase')); $('phrase').value=''; return false; };
-</script>
-</body></html>
diff --git a/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/ws/index.html b/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/ws/index.html
deleted file mode 100644
index 4d5acc9..0000000
--- a/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/ws/index.html
+++ /dev/null
@@ -1,109 +0,0 @@
-<html><head>
-    <title>Equinox Console (WebSocket)</title>
-    <script type='text/javascript'>
-    
-      if (!window.WebSocket)
-        alert("WebSocket not supported by this browser");
-    
-      function $() { return document.getElementById(arguments[0]); }
-      function $F() { return document.getElementById(arguments[0]).value; }
-      
-      function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; } 
-      
-      var room = {
-        join: function(name) {
-          this._username=name;
-          var location = document.location.toString().replace('http://','ws://').replace('https://','wss://').replace('/index.html','');
-          this._ws=new WebSocket(location);
-          this._ws.onopen=this._onopen;
-          this._ws.onmessage=this._onmessage;
-          this._ws.onclose=this._onclose;
-        },
-        
-        _onopen: function(){
-          $('join').className='hidden';
-          $('joined').className='';
-          $('phrase').focus();
-          room._send(room._username,'has joined!');
-        },
-        
-        _send: function(user,message){
-          user=user.replace(':','_');
-          if (this._ws)
-            this._ws.send(user+':'+message);
-        },
-      
-        chat: function(text) {
-          if (text != null && text.length>0 )
-              room._send(room._username,text);
-        },
-        
-        _onmessage: function(m) {
-          if (m.data){
-            var c=m.data.indexOf(':');
-            var from=m.data.substring(0,c).replace('<','&lt;').replace('>','&gt;');
-            var text=m.data.substring(c+1).replace('<','&lt;').replace('>','&gt;');
-            
-            var chat=$('chat');
-            var spanFrom = document.createElement('span');
-            spanFrom.className='from';
-            spanFrom.innerHTML=from+':&nbsp;';
-            var spanText = document.createElement('span');
-            spanText.className='text';
-            spanText.innerHTML=text;
-            var lineBreak = document.createElement('br');
-            chat.appendChild(spanFrom);
-            chat.appendChild(spanText);
-            chat.appendChild(lineBreak);
-            chat.scrollTop = chat.scrollHeight - chat.clientHeight;   
-          }
-        },
-        
-        _onclose: function(m) {
-          this._ws=null;
-          $('join').className='';
-          $('joined').className='hidden';
-          $('username').focus();
-          $('chat').innerHTML='';
-        }
-        
-      };
-      
-    </script>
-    <style type='text/css'>
-    div { border: 0px solid black; }
-    div#chat { clear: both; width: 40em; height: 20ex; overflow: auto; background-color: #f0f0f0; padding: 4px; border: 1px solid black; }
-    div#input { clear: both; width: 40em; padding: 4px; background-color: #e0e0e0; border: 1px solid black; border-top: 0px }
-    input#phrase { width:30em; background-color: #e0f0f0; }
-    input#username { width:14em; background-color: #e0f0f0; }
-    div.hidden { display: none; }
-    span.from { font-weight: bold; }
-    span.alert { font-style: italic; }
-    </style>
-</head><body>
-<div id='chat'></div>
-<div id='input'>
-  <div id='join' >
-    Username:&nbsp;<input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join' value='Join'/>
-  </div>
-  <div id='joined' class='hidden'>
-    Chat:&nbsp;<input id='phrase' type='text'/>
-    <input id='sendB' class='button' type='submit' name='join' value='Send'/>
-  </div>
-</div>
-<script type='text/javascript'>
-$('username').setAttribute('autocomplete','OFF');
-$('username').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.join($F('username')); return false; } return true; } ;        
-$('joinB').onclick = function(event) { room.join($F('username')); return false; };
-$('phrase').setAttribute('autocomplete','OFF');
-$('phrase').onkeyup = function(ev) {   var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.chat($F('phrase')); $('phrase').value=''; return false; } return true; };
-$('sendB').onclick = function(event) { room.chat($F('phrase')); $('phrase').value=''; return false; };
-</script>
-
-<p>
-This is a demonstration of the Jetty websocket server.
-</p>
-</body></html>
-        
-        
-        
diff --git a/jetty-osgi/jetty-osgi-equinoxtools/pom.xml b/jetty-osgi/jetty-osgi-equinoxtools/pom.xml
index cf84d89..e661375 100644
--- a/jetty-osgi/jetty-osgi-equinoxtools/pom.xml
+++ b/jetty-osgi/jetty-osgi-equinoxtools/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.18-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml
index 95757f6..211a8e8 100644
--- a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml
+++ b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"  encoding="ISO-8859-1"?>
 <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
 <!--
- Copyright (c) 2009 Intalio, Inc.
+ Copyright (c) 2009-2011 Intalio, Inc.
 
  All rights reserved. This program and the accompanying materials
  are made available under the terms of the Eclipse Public License v1.0
@@ -29,4 +29,4 @@
   <Set name="ErrorHandler">
     <New class="org.eclipse.jetty.osgi.httpservice.HttpServiceErrorPageErrorHandler"/>
   </Set>
-</Configure>
\ No newline at end of file
+</Configure>
diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml
index 44ab9a9..1d86a32 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -97,8 +97,8 @@
                 <Bundle-SymbolicName>org.eclipse.jetty.osgi.httpservice</Bundle-SymbolicName>
                 <Bundle-Name>OSGi HttpService</Bundle-Name>
                 <Jetty-ContextFilePath>contexts/httpservice.xml</Jetty-ContextFilePath>
-                <Import-Package>org.eclipse.jetty.server.handler;version="[7.6,8)",
-org.eclipse.jetty.util.component;version="[7.6,8)",
+                <Import-Package>org.eclipse.jetty.server.handler;version="[8.1,9)",
+org.eclipse.jetty.util.component;version="[8.1,9)",
 org.eclipse.equinox.http.servlet,
 *
                  </Import-Package>
@@ -115,6 +115,4 @@
       </plugin>
     </plugins>
   </build>
-
-
 </project>
diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml.tycho b/jetty-osgi/jetty-osgi-httpservice/pom.xml.tycho
deleted file mode 100644
index c6efbeb..0000000
--- a/jetty-osgi/jetty-osgi-httpservice/pom.xml.tycho
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <artifactId>jetty-osgi</artifactId>
-    <groupId>org.eclipse.jetty.osgi</groupId>
-    <version>7.0.1-SNAPSHOT</version>
-  </parent>
-  <artifactId>org.eclipse.jetty.osgi.httpservice</artifactId>
-  <packaging>eclipse-plugin</packaging>
-</project>
diff --git a/jetty-osgi/jetty-osgi-servletbridge/pom.xml b/jetty-osgi/jetty-osgi-servletbridge/pom.xml
deleted file mode 100644
index 4da36c2..0000000
--- a/jetty-osgi/jetty-osgi-servletbridge/pom.xml
+++ /dev/null
@@ -1,54 +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>7.6.5-SNAPSHOT</version>
-    <relativePath>../pom.xml</relativePath>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.eclipse.jetty.osgi</groupId>
-  <artifactId>jetty-osgi-servletbridge</artifactId>
-  <name>Jetty :: OSGi :: Servletbridge</name>
-  <description>Jetty OSGi Servletbridge webapp</description>
-  <url>http://www.eclipse.org/jetty</url>
-  <packaging>war</packaging>
-  <properties><eclipse.pde>false</eclipse.pde></properties>
-  <dependencies>
-    <dependency>
-      <groupId>org.eclipse.equinox</groupId>
-      <artifactId>org.eclipse.equinox.servletbridge</artifactId>
-      <version>1.2.0.v20100503</version>
-    </dependency>
-    <dependency>
-      <groupId>javax.servlet</groupId>
-      <artifactId>servlet-api</artifactId>
-      <version>2.5</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.osgi</groupId>
-      <artifactId>org.eclipse.osgi</artifactId>
-      <version>3.6.0.v20100517</version>
-      <scope>provided</scope>
-    </dependency>
-  </dependencies>
-  <repositories>
-    <!-- can't find equinox servlet bridge jar on maven central.
-    uploaded it to intalio.org for now. -->
-    <repository>
-     <id>intalio-org</id>
-     <url>http://intalio.org/public/maven2</url>
-   </repository>
-  </repositories>
-  
-  <build>
-    <plugins><plugin>
-     <groupId>org.apache.maven.plugins</groupId>
-     <artifactId>maven-eclipse-plugin</artifactId>
-     <configuration>
-       <pde>false</pde>
-     </configuration>
-   </plugin></plugins>
- </build>
-  
-</project>
diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/nested/Dump.java b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/nested/Dump.java
deleted file mode 100644
index 02434a7..0000000
--- a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/nested/Dump.java
+++ /dev/null
@@ -1,1017 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.nested;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.Statement;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.Locale;
-import java.util.Map.Entry;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletRequestWrapper;
-import javax.servlet.ServletResponse;
-import javax.servlet.ServletResponseWrapper;
-import javax.servlet.UnavailableException;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-import javax.sql.DataSource;
-
-/* ------------------------------------------------------------ */
-/**
- * Dump Servlet Request.
- * 
- * Copied from test-jetty-webapp's Dump servlet.
- */
-public class Dump extends HttpServlet
-{
-    boolean fixed;
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public void init(ServletConfig config) throws ServletException
-    {
-        super.init(config);
-
-        if (config.getInitParameter("unavailable") != null && !fixed)
-        {
-
-            fixed = true;
-            throw new UnavailableException("Unavailable test", Integer.parseInt(config.getInitParameter("unavailable")));
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        doGet(request, response);
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
-    {
-        // Handle a dump of data
-        final String data = request.getParameter("data");
-        final String chars = request.getParameter("chars");
-        final String block = request.getParameter("block");
-        final String dribble = request.getParameter("dribble");
-        final boolean flush = request.getParameter("flush") != null ? Boolean.parseBoolean(request.getParameter("flush")) : false;
-
-        if (request.getPathInfo() != null && request.getPathInfo().toLowerCase().indexOf("script") != -1)
-        {
-            response.sendRedirect(response.encodeRedirectURL(getServletContext().getContextPath() + "/dump/info"));
-            return;
-        }
-
-        request.setCharacterEncoding("UTF-8");
-
-        if (request.getParameter("empty") != null)
-        {
-            response.setStatus(200);
-            response.flushBuffer();
-            return;
-        }
-
-        request.setAttribute("Dump", this);
-        getServletContext().setAttribute("Dump", this);
-
-        // Force a content length response
-        String length = request.getParameter("length");
-        if (length != null && length.length() > 0)
-        {
-            response.setContentLength(Integer.parseInt(length));
-        }
-
-        // Handle a dump of data
-        if (dump(response, data, chars, block, dribble, flush)) return;
-
-        // handle an exception
-        String info = request.getPathInfo();
-        if (info != null && info.endsWith("Exception"))
-        {
-            try
-            {
-                throw (Throwable) Thread.currentThread().getContextClassLoader().loadClass(info.substring(1)).newInstance();
-            }
-            catch (Throwable th)
-            {
-                throw new ServletException(th);
-            }
-        }
-
-        // test a reset
-        String reset = request.getParameter("reset");
-        if (reset != null && reset.length() > 0)
-        {
-            response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
-            response.setHeader("SHOULD_NOT", "BE SEEN");
-            response.reset();
-        }
-
-        // handle an redirect
-        String redirect = request.getParameter("redirect");
-        if (redirect != null && redirect.length() > 0)
-        {
-            response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
-            response.sendRedirect(response.encodeRedirectURL(redirect));
-            try
-            {
-                response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
-            }
-            catch (IOException e)
-            {
-                // ignored as stream is closed.
-            }
-            return;
-        }
-
-        // handle an error
-        String error = request.getParameter("error");
-        if (error != null && error.length() > 0 && request.getAttribute("javax.servlet.error.status_code") == null)
-        {
-            response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
-            response.sendError(Integer.parseInt(error));
-            try
-            {
-                response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
-            }
-            catch (IllegalStateException e)
-            {
-                try
-                {
-                    response.getWriter().println("NOR THIS!!");
-                }
-                catch (IOException e2)
-                {
-                }
-            }
-            catch (IOException e)
-            {
-            }
-            return;
-        }
-
-        // Handle a extra headers
-        String headers = request.getParameter("headers");
-        if (headers != null && headers.length() > 0)
-        {
-            long h = Long.parseLong(headers);
-            for (int i = 0; i < h; i++)
-                response.addHeader("Header" + i, "Value" + i);
-        }
-
-        String buffer = request.getParameter("buffer");
-        if (buffer != null && buffer.length() > 0) response.setBufferSize(Integer.parseInt(buffer));
-
-        String charset = request.getParameter("charset");
-        if (charset == null) charset = "UTF-8";
-        response.setCharacterEncoding(charset);
-        response.setContentType("text/html");
-
-        if (info != null && info.indexOf("Locale/") >= 0)
-        {
-            try
-            {
-                String locale_name = info.substring(info.indexOf("Locale/") + 7);
-                Field f = java.util.Locale.class.getField(locale_name);
-                response.setLocale((Locale) f.get(null));
-            }
-            catch (Exception e)
-            {
-                e.printStackTrace();
-                response.setLocale(Locale.getDefault());
-            }
-        }
-
-        String cn = request.getParameter("cookie");
-        String cv = request.getParameter("cookiev");
-        if (cn != null && cv != null)
-        {
-            Cookie cookie = new Cookie(cn, cv);
-            if (request.getParameter("version") != null) cookie.setVersion(Integer.parseInt(request.getParameter("version")));
-            cookie.setComment("Cookie from dump servlet");
-            response.addCookie(cookie);
-        }
-
-        String pi = request.getPathInfo();
-        if (pi != null && pi.startsWith("/ex"))
-        {
-            OutputStream out = response.getOutputStream();
-            out.write("</H1>This text should be reset</H1>".getBytes());
-            if ("/ex0".equals(pi))
-                throw new ServletException("test ex0", new Throwable());
-            else if ("/ex1".equals(pi))
-                throw new IOException("test ex1");
-            else if ("/ex2".equals(pi))
-                throw new UnavailableException("test ex2");
-            else if (pi.startsWith("/ex3/")) throw new UnavailableException("test ex3", Integer.parseInt(pi.substring(5)));
-            throw new RuntimeException("test");
-        }
-
-        if ("true".equals(request.getParameter("close"))) response.setHeader("Connection", "close");
-
-        String buffered = request.getParameter("buffered");
-
-        PrintWriter pout = null;
-
-        try
-        {
-            pout = response.getWriter();
-        }
-        catch (IllegalStateException e)
-        {
-            pout = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), charset));
-        }
-        if (buffered != null) pout = new PrintWriter(new BufferedWriter(pout, Integer.parseInt(buffered)));
-
-        try
-        {
-            pout.write("<html>\n<body>\n");
-            pout.write("<h1>Dump Servlet</h1>\n");
-            pout.write("<table width=\"95%\">");
-            pout.write("<tr>\n");
-            pout.write("<th align=\"right\">getMethod:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getMethod()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getContentLength:&nbsp;</th>");
-            pout.write("<td>" + Integer.toString(request.getContentLength()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getContentType:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getContentType()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getRequestURI:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getRequestURI()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getRequestURL:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getRequestURL().toString()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getContextPath:&nbsp;</th>");
-            pout.write("<td>" + request.getContextPath() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getServletPath:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getServletPath()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getPathInfo:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getPathInfo()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getPathTranslated:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getPathTranslated()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getQueryString:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getQueryString()) + "</td>");
-            pout.write("</tr><tr>\n");
-
-            pout.write("<th align=\"right\">getProtocol:&nbsp;</th>");
-            pout.write("<td>" + request.getProtocol() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getScheme:&nbsp;</th>");
-            pout.write("<td>" + request.getScheme() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getServerName:&nbsp;</th>");
-            pout.write("<td>" + notag(request.getServerName()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getServerPort:&nbsp;</th>");
-            pout.write("<td>" + Integer.toString(request.getServerPort()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getLocalName:&nbsp;</th>");
-            pout.write("<td>" + request.getLocalName() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getLocalAddr:&nbsp;</th>");
-            pout.write("<td>" + request.getLocalAddr() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getLocalPort:&nbsp;</th>");
-            pout.write("<td>" + Integer.toString(request.getLocalPort()) + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getRemoteUser:&nbsp;</th>");
-            pout.write("<td>" + request.getRemoteUser() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getUserPrincipal:&nbsp;</th>");
-            pout.write("<td>" + request.getUserPrincipal() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getRemoteAddr:&nbsp;</th>");
-            pout.write("<td>" + request.getRemoteAddr() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getRemoteHost:&nbsp;</th>");
-            pout.write("<td>" + request.getRemoteHost() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getRemotePort:&nbsp;</th>");
-            pout.write("<td>" + request.getRemotePort() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getRequestedSessionId:&nbsp;</th>");
-            pout.write("<td>" + request.getRequestedSessionId() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">isSecure():&nbsp;</th>");
-            pout.write("<td>" + request.isSecure() + "</td>");
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">isUserInRole(admin):&nbsp;</th>");
-            pout.write("<td>" + request.isUserInRole("admin") + "</td>");
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\">getLocale:&nbsp;</th>");
-            pout.write("<td>" + request.getLocale() + "</td>");
-
-            Enumeration locales = request.getLocales();
-            while (locales.hasMoreElements())
-            {
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">getLocales:&nbsp;</th>");
-                pout.write("<td>" + locales.nextElement() + "</td>");
-            }
-            pout.write("</tr><tr>\n");
-
-            pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Other HTTP Headers:</big></th>");
-            Enumeration h = request.getHeaderNames();
-            String name;
-            while (h.hasMoreElements())
-            {
-                name = (String) h.nextElement();
-
-                Enumeration h2 = request.getHeaders(name);
-                while (h2.hasMoreElements())
-                {
-                    String hv = (String) h2.nextElement();
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">" + notag(name) + ":&nbsp;</th>");
-                    pout.write("<td>" + notag(hv) + "</td>");
-                }
-            }
-
-            // Test the system properties
-            if ("true".equals(request.getParameter("env")))
-            {
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Environment:&nbsp;</big></th>");
-                for (Entry e : System.getenv().entrySet())
-                {
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">" + notag(String.valueOf(e.getKey())) + ":&nbsp;</th>");
-                    pout.write("<td>" + notag(String.valueOf(e.getValue())) + "</td>");
-                }
-
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"left\" colspan=\"2\"><big><br/>System-Properties:&nbsp;</big></th>");
-
-                for (Entry<Object, Object> e : System.getProperties().entrySet())
-                {
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">" + notag(String.valueOf(e.getKey())) + ":&nbsp;</th>");
-                    pout.write("<td>" + notag(String.valueOf(e.getValue())) + "</td>");
-                }
-            }
-
-            // handle testing jdbc connections:
-            String jdbcUrl = request.getParameter("jdbc-url");
-            String jdbcDriver = request.getParameter("jdbc-driver");
-            if (jdbcUrl != null)
-            {
-                Connection con = null;
-                try
-                {
-                    String user = request.getParameter("jdbc-user");
-                    String pass = request.getParameter("jdbc-pass");
-                    String query = request.getParameter("jdbc-query");
-                    if (user.length() == 0) user = null;
-                    if (pass.length() == 0) pass = null;
-                    if (query == null || query.length() == 0) query = "show tables;";
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"left\" colspan=\"2\"><big><br/>JDBC test:&nbsp;</big></th>");
-
-                    Class driver = Thread.currentThread().getContextClassLoader().loadClass(jdbcDriver);
-
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">Driver class:&nbsp;</th>");
-                    pout.write("<td>" + driver.getName() + " loaded by " + driver.getClassLoader() + "</td>");
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">Connection url:&nbsp;</th>");
-                    pout.write("<td>" + jdbcUrl + "</td>");
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">User (optional):&nbsp;</th>");
-                    pout.write("<td>" + user + "</td>");
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">Is there a password (optional):&nbsp;</th>");
-                    pout.write("<td>" + (pass != null ? "yes" : "no") + "</td>");
-
-                    con = user != null ? DriverManager.getConnection(jdbcUrl, user, pass) : DriverManager.getConnection(jdbcUrl);
-
-                    Statement statement = con.createStatement();
-                    boolean success = statement.execute(query);
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">Query:&nbsp;</th>");
-                    pout.write("<td>" + query + "</td>");
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">Successful query:&nbsp;</th>");
-                    pout.write("<td>" + success + "</td>");
-
-                }
-                catch (Throwable t)
-                {
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">JDBC test error:&nbsp;</th>");
-                    pout.write("<td>" + t + "</td>");
-                }
-                finally
-                {
-                    if (con != null)
-                    {
-                        try
-                        {
-                            con.close();
-                        }
-                        catch (Throwable ee)
-                        {
-                        }
-                    }
-                }
-            }
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Request Parameters:</big></th>");
-            h = request.getParameterNames();
-            while (h.hasMoreElements())
-            {
-                name = (String) h.nextElement();
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">" + notag(name) + ":&nbsp;</th>");
-                pout.write("<td>" + notag(request.getParameter(name)) + "</td>");
-                String[] values = request.getParameterValues(name);
-                if (values == null)
-                {
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">" + notag(name) + " Values:&nbsp;</th>");
-                    pout.write("<td>" + "NULL!" + "</td>");
-                }
-                else if (values.length > 1)
-                {
-                    for (int i = 0; i < values.length; i++)
-                    {
-                        pout.write("</tr><tr>\n");
-                        pout.write("<th align=\"right\">" + notag(name) + "[" + i + "]:&nbsp;</th>");
-                        pout.write("<td>" + notag(values[i]) + "</td>");
-                    }
-                }
-            }
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Cookies:</big></th>");
-            Cookie[] cookies = request.getCookies();
-            for (int i = 0; cookies != null && i < cookies.length; i++)
-            {
-                Cookie cookie = cookies[i];
-
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">" + notag(cookie.getName()) + ":&nbsp;</th>");
-                pout.write("<td>" + notag(cookie.getValue()) + "</td>");
-            }
-
-            String content_type = request.getContentType();
-            if (content_type != null && !content_type.startsWith("application/x-www-form-urlencoded") && !content_type.startsWith("multipart/form-data"))
-            {
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"left\" valign=\"top\" colspan=\"2\"><big><br/>Content:</big></th>");
-                pout.write("</tr><tr>\n");
-                pout.write("<td><pre>");
-                char[] content = new char[4096];
-                int len;
-                try
-                {
-                    Reader in = request.getReader();
-
-                    while ((len = in.read(content)) >= 0)
-                        pout.write(notag(new String(content, 0, len)));
-                }
-                catch (IOException e)
-                {
-                    pout.write(e.toString());
-                }
-
-                pout.write("</pre></td>");
-            }
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Request Attributes:</big></th>");
-            Enumeration a = request.getAttributeNames();
-            while (a.hasMoreElements())
-            {
-                name = (String) a.nextElement();
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", " .") + ":&nbsp;</th>");
-                Object value = request.getAttribute(name);
-                if (value instanceof File)
-                {
-                    File file = (File) value;
-                    pout.write("<td>" + "<pre>" + file.getName() + " (" + file.length() + " " + new Date(file.lastModified()) + ")</pre>" + "</td>");
-                }
-                else
-                    pout.write("<td>" + "<pre>" + toString(request.getAttribute(name)) + "</pre>" + "</td>");
-            }
-            request.setAttribute("org.eclipse.jetty.servlet.MultiPartFilter.files", null);
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Servlet InitParameters:</big></th>");
-            a = getInitParameterNames();
-            while (a.hasMoreElements())
-            {
-                name = (String) a.nextElement();
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">" + name + ":&nbsp;</th>");
-                pout.write("<td>" + toString(getInitParameter(name)) + "</td>");
-            }
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"left\" colspan=\"2\"><big><br/>ServletContext Misc:</big></th>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\" valign=\"top\">" + "servletContext.getContextPath()" + ":&nbsp;</th>");
-            pout.write("<td>" + getServletContext().getContextPath() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\" valign=\"top\">" + "getServletContext().getRealPath(\"/WEB-INF/\")" + ":&nbsp;</th>");
-            pout.write("<td>" + getServletContext().getRealPath("/WEB-INF/") + "</td>");
-
-            String webinfRealPath = getServletContext().getRealPath("/WEB-INF/");
-            if (webinfRealPath != null)
-            {
-                try
-                {
-                    File webInfRealPathFile = new File(webinfRealPath);
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\" valign=\"top\">" + "new File(getServletContext().getRealPath(\"/WEB-INF/\"))" + ":&nbsp;</th>");
-                    pout.write("<td>exists()=" + webInfRealPathFile.exists()
-                               + "; isFile()="
-                               + webInfRealPathFile.isFile()
-                               + "; isDirectory()="
-                               + webInfRealPathFile.isDirectory()
-                               + "; isAbsolute()="
-                               + webInfRealPathFile.isAbsolute()
-                               + "; canRead()="
-                               + webInfRealPathFile.canRead()
-                               + "; canWrite()="
-                               + webInfRealPathFile.canWrite()
-                               + "</td>");
-                    if (webInfRealPathFile.exists() && webInfRealPathFile.isDirectory())
-                    {
-                        File webxml = new File(webInfRealPathFile, "web.xml");
-                        pout.write("</tr><tr>\n");
-                        pout.write("<th align=\"right\" valign=\"top\">" + "new File(getServletContext().getRealPath(\"/WEB-INF/web.xml\"))" + ":&nbsp;</th>");
-                        pout.write("<td>exists()=" + webxml.exists()
-                                   + "; isFile()="
-                                   + webxml.isFile()
-                                   + "; isDirectory()="
-                                   + webxml.isDirectory()
-                                   + "; isAbsolute()="
-                                   + webxml.isAbsolute()
-                                   + "; canRead()="
-                                   + webxml.canRead()
-                                   + "; canWrite()="
-                                   + webxml.canWrite()
-                                   + "</td>");
-                    }
-                }
-                catch (Throwable t)
-                {
-                    pout.write("<th align=\"right\" valign=\"top\">" + "Error probing the java.io.File(getServletContext().getRealPath(\"/WEB-INF/\"))"
-                               + ":&nbsp;</th>");
-                    pout.write("<td>" + t + "</td>");
-                }
-            }
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\" valign=\"top\">" + "getServletContext().getServerInfo()" + ":&nbsp;</th>");
-            pout.write("<td>" + getServletContext().getServerInfo() + "</td>");
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"right\" valign=\"top\">" + "getServletContext().getServletContextName()" + ":&nbsp;</th>");
-            pout.write("<td>" + getServletContext().getServletContextName() + "</td>");
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Context InitParameters:</big></th>");
-            a = getServletContext().getInitParameterNames();
-            while (a.hasMoreElements())
-            {
-                name = (String) a.nextElement();
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", " .") + ":&nbsp;</th>");
-                pout.write("<td>" + toString(getServletContext().getInitParameter(name)) + "</td>");
-            }
-
-            pout.write("</tr><tr>\n");
-            pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Context Attributes:</big></th>");
-            a = getServletContext().getAttributeNames();
-            while (a.hasMoreElements())
-            {
-                name = (String) a.nextElement();
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", " .") + ":&nbsp;</th>");
-                pout.write("<td>" + "<pre>" + toString(getServletContext().getAttribute(name)) + "</pre>" + "</td>");
-            }
-
-            String res = request.getParameter("resource");
-            if (res != null && res.length() > 0)
-            {
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Get Resource: \"" + res + "\"</big></th>");
-
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">getServletContext().getContext(...):&nbsp;</th>");
-
-                ServletContext context = getServletContext().getContext(res);
-                pout.write("<td>" + context + "</td>");
-
-                if (context != null)
-                {
-                    String cp = context.getContextPath();
-                    if (cp == null || "/".equals(cp)) cp = "";
-                    pout.write("</tr><tr>\n");
-                    pout.write("<th align=\"right\">getServletContext().getContext(...),getRequestDispatcher(...):&nbsp;</th>");
-                    pout.write("<td>" + getServletContext().getContext(res).getRequestDispatcher(res.substring(cp.length())) + "</td>");
-                }
-
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">this.getClass().getResource(...):&nbsp;</th>");
-                pout.write("<td>" + this.getClass().getResource(res) + "</td>");
-
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">this.getClass().getClassLoader().getResource(...):&nbsp;</th>");
-                pout.write("<td>" + this.getClass().getClassLoader().getResource(res) + "</td>");
-
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">Thread.currentThread().getContextClassLoader().getResource(...):&nbsp;</th>");
-                pout.write("<td>" + Thread.currentThread().getContextClassLoader().getResource(res) + "</td>");
-
-                pout.write("</tr><tr>\n");
-                pout.write("<th align=\"right\">getServletContext().getResource(...):&nbsp;</th>");
-                try
-                {
-                    pout.write("<td>" + getServletContext().getResource(res) + "</td>");
-                }
-                catch (Exception e)
-                {
-                    pout.write("<td>" + "" + e + "</td>");
-                }
-            }
-
-            pout.write("</tr></table>\n");
-
-            /* ------------------------------------------------------------ */
-            pout.write("<h2>Request Wrappers</h2>\n");
-            ServletRequest rw = request;
-            int w = 0;
-            while (rw != null)
-            {
-                pout.write((w++) + ": " + rw.getClass().getName() + "<br/>");
-                if (rw instanceof HttpServletRequestWrapper)
-                    rw = ((HttpServletRequestWrapper) rw).getRequest();
-                else if (rw instanceof ServletRequestWrapper)
-                    rw = ((ServletRequestWrapper) rw).getRequest();
-                else
-                    rw = null;
-            }
-
-            /* ------------------------------------------------------------ */
-            pout.write("<h2>Response Wrappers</h2>\n");
-            ServletResponse rsw = response;
-            w = 0;
-            while (rsw != null)
-            {
-                pout.write((w++) + ": " + rsw.getClass().getName() + "<br/>");
-                if (rsw instanceof HttpServletResponseWrapper)
-                    rsw = ((HttpServletResponseWrapper) rsw).getResponse();
-                else if (rsw instanceof ServletResponseWrapper)
-                    rsw = ((ServletResponseWrapper) rsw).getResponse();
-                else
-                    rsw = null;
-            }
-
-            pout.write("<br/>");
-            pout.write("<h2>International Characters (UTF-8)</h2>");
-            pout.write("LATIN LETTER SMALL CAPITAL AE<br/>\n");
-            pout.write("Directly uni encoded(\\u1d01): \u1d01<br/>");
-            pout.write("HTML reference (&amp;AElig;): &AElig;<br/>");
-            pout.write("Decimal (&amp;#7425;): &#7425;<br/>");
-            pout.write("Javascript unicode (\\u1d01) : <script language='javascript'>document.write(\"\u1d01\");</script><br/>");
-            pout.write("<br/>");
-            pout.write("<h2>Form to generate GET content</h2>");
-            pout.write("<form method=\"GET\" action=\"" + response.encodeURL(getURI(request)) + "\">");
-            pout.write("TextField: <input type=\"text\" name=\"TextField\" value=\"value\"/><br/>\n");
-            pout.write("<input type=\"submit\" name=\"Action\" value=\"Submit\">");
-            pout.write("</form>");
-
-            pout.write("<br/>");
-
-            pout.write("<h2>Form to generate POST content</h2>");
-            pout.write("<form method=\"POST\" accept-charset=\"utf-8\" action=\"" + response.encodeURL(getURI(request)) + "\">");
-            pout.write("TextField: <input type=\"text\" name=\"TextField\" value=\"value\"/><br/>\n");
-            pout.write("Select: <select multiple name=\"Select\">\n");
-            pout.write("<option>ValueA</option>");
-            pout.write("<option>ValueB1,ValueB2</option>");
-            pout.write("<option>ValueC</option>");
-            pout.write("</select><br/>");
-            pout.write("<input type=\"submit\" name=\"Action\" value=\"Submit\"><br/>");
-            pout.write("</form>");
-            pout.write("<br/>");
-
-            pout.write("<h2>Form to generate UPLOAD content</h2>");
-            pout.write("<form method=\"POST\" enctype=\"multipart/form-data\" accept-charset=\"utf-8\" action=\"" + response.encodeURL(getURI(request))
-                       + (request.getQueryString() == null ? "" : ("?" + request.getQueryString()))
-                       + "\">");
-            pout.write("TextField: <input type=\"text\" name=\"TextField\" value=\"comment\"/><br/>\n");
-            pout.write("File 1: <input type=\"file\" name=\"file1\" /><br/>\n");
-            pout.write("File 2: <input type=\"file\" name=\"file2\" /><br/>\n");
-            pout.write("<input type=\"submit\" name=\"Action\" value=\"Submit\"><br/>");
-            pout.write("</form>");
-
-            pout.write("<h2>Form to set Cookie</h2>");
-            pout.write("<form method=\"POST\" action=\"" + response.encodeURL(getURI(request)) + "\">");
-            pout.write("cookie: <input type=\"text\" name=\"cookie\" /><br/>\n");
-            pout.write("value: <input type=\"text\" name=\"cookiev\" /><br/>\n");
-            pout.write("<input type=\"submit\" name=\"Action\" value=\"setCookie\">");
-            pout.write("</form>\n");
-
-            pout.write("<h2>Form to get Resource</h2>");
-            pout.write("<form method=\"POST\" action=\"" + response.encodeURL(getURI(request)) + "\">");
-            pout.write("resource: <input type=\"text\" name=\"resource\" /><br/>\n");
-            pout.write("<input type=\"submit\" name=\"Action\" value=\"getResource\">");
-            pout.write("</form>\n");
-
-            pout.write("<h2>Form to test a JDBC connection URL</h2>");
-            String jdbcUser = request.getParameter("jdbc-user");
-            if (jdbcUser == null || jdbcUser.length() == 0) jdbcUser = "root";
-            String jdbcPass = request.getParameter("jdbc-pass");
-            if (jdbcPass == null) jdbcPass = "";
-            String jdbcDriverr = request.getParameter("jdbc-driver");
-            if (jdbcDriverr == null || jdbcDriverr.length() == 0) jdbcDriverr = "com.mysql.jdbc.Driver";
-            String jdbcQuery = request.getParameter("jdbc-query");
-            if (jdbcQuery == null || jdbcQuery.length() == 0) jdbcQuery = "show tables;";
-            String jdbcUrll = request.getParameter("jdbc-url");
-            if (jdbcUrll == null || jdbcUrll.length() == 0) jdbcUrll = "jdbc:mysql://127.0.0.1:3306/example";
-            pout.write("<form method=\"POST\" accept-charset=\"utf-8\" action=\"" + response.encodeURL(getURI(request)) + "\">");
-            pout.write("JDBC Driver class: <input type=\"text\" name=\"jdbc-driver\" value=\"" + jdbcDriverr + "\"/><br/>\n");
-            pout.write("JDBC URL: <input type=\"text\" name=\"jdbc-url\" value=\"" + jdbcUrll + "\"/><br/>\n");
-            pout.write("JDBC Username: <input type=\"text\" name=\"jdbc-user\" value=\"" + jdbcUser + "\"/><br/>\n");
-            pout.write("JDBC Password: <input type=\"text\" name=\"jdbc-pass\" value=\"" + jdbcPass + "\"/><br/>\n");
-            pout.write("JDBC Query: <input type=\"text\" name=\"jdbc-query\" value=\"" + jdbcQuery + "\"/><br/>\n");
-            pout.write("<input type=\"submit\" name=\"Action\" value=\"Submit\"><br/>");
-            pout.write("</form>");
-            pout.write("<br/>");
-
-        }
-        catch (Exception e)
-        {
-            getServletContext().log("dump", e);
-        }
-
-        String lines = request.getParameter("lines");
-        if (lines != null)
-        {
-            char[] line = "<span>A line of characters. Blah blah blah blah.  blooble blooble</span></br>\n".toCharArray();
-            for (int l = Integer.parseInt(lines); l-- > 0;)
-            {
-                pout.write("<span>" + l + " </span>");
-                pout.write(line);
-            }
-        }
-
-        pout.write("</body>\n</html>\n");
-
-        pout.close();
-
-        if (pi != null)
-        {
-            if ("/ex4".equals(pi)) throw new ServletException("test ex4", new Throwable());
-            if ("/ex5".equals(pi)) throw new IOException("test ex5");
-            if ("/ex6".equals(pi)) throw new UnavailableException("test ex6");
-        }
-
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public String getServletInfo()
-    {
-        return "Dump Servlet";
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public synchronized void destroy()
-    {
-    }
-
-    /* ------------------------------------------------------------ */
-    private String getURI(HttpServletRequest request)
-    {
-        String uri = (String) request.getAttribute("javax.servlet.forward.request_uri");
-        if (uri == null) uri = request.getRequestURI();
-        return uri;
-    }
-
-    /* ------------------------------------------------------------ */
-    private static String toString(Object o)
-    {
-        if (o == null) return null;
-
-        try
-        {
-            if (o.getClass().isArray())
-            {
-                StringBuffer sb = new StringBuffer();
-                if (!o.getClass().getComponentType().isPrimitive())
-                {
-                    Object[] array = (Object[]) o;
-                    for (int i = 0; i < array.length; i++)
-                    {
-                        if (i > 0) sb.append("\n");
-                        sb.append(array.getClass().getComponentType().getName());
-                        sb.append("[");
-                        sb.append(i);
-                        sb.append("]=");
-                        sb.append(toString(array[i]));
-                    }
-                    return sb.toString();
-                }
-                else
-                {
-                    int length = Array.getLength(o);
-                    for (int i = 0; i < length; i++)
-                    {
-                        if (i > 0) sb.append("\n");
-                        sb.append(o.getClass().getComponentType().getName());
-                        sb.append("[");
-                        sb.append(i);
-                        sb.append("]=");
-                        sb.append(toString(Array.get(o, i)));
-                    }
-                    return sb.toString();
-                }
-            }
-            else
-                return o.toString();
-        }
-        catch (Exception e)
-        {
-            return e.toString();
-        }
-    }
-
-    private boolean dump(HttpServletResponse response, String data, String chars, String block, String dribble, boolean flush) throws IOException
-    {
-        if (data != null && data.length() > 0)
-        {
-            long d = Long.parseLong(data);
-            int b = (block != null && block.length() > 0) ? Integer.parseInt(block) : 50;
-            byte[] buf = new byte[b];
-            for (int i = 0; i < b; i++)
-            {
-
-                buf[i] = (byte) ('0' + (i % 10));
-                if (i % 10 == 9) buf[i] = (byte) '\n';
-            }
-            buf[0] = 'o';
-            OutputStream out = response.getOutputStream();
-            response.setContentType("text/plain");
-            while (d > 0)
-            {
-                if (b == 1)
-                {
-                    out.write(d % 80 == 0 ? '\n' : '.');
-                    d--;
-                }
-                else if (d >= b)
-                {
-                    out.write(buf);
-                    d = d - b;
-                }
-                else
-                {
-                    out.write(buf, 0, (int) d);
-                    d = 0;
-                }
-
-                if (dribble != null)
-                {
-                    out.flush();
-                    try
-                    {
-                        Thread.sleep(Long.parseLong(dribble));
-                    }
-                    catch (Exception e)
-                    {
-                        e.printStackTrace();
-                        break;
-                    }
-                }
-
-            }
-
-            if (flush) out.flush();
-
-            return true;
-        }
-
-        // Handle a dump of data
-        if (chars != null && chars.length() > 0)
-        {
-            long d = Long.parseLong(chars);
-            int b = (block != null && block.length() > 0) ? Integer.parseInt(block) : 50;
-            char[] buf = new char[b];
-            for (int i = 0; i < b; i++)
-            {
-                buf[i] = (char) ('0' + (i % 10));
-                if (i % 10 == 9) buf[i] = '\n';
-            }
-            buf[0] = 'o';
-            response.setContentType("text/plain");
-            PrintWriter out = response.getWriter();
-            while (d > 0 && !out.checkError())
-            {
-                if (b == 1)
-                {
-                    out.write(d % 80 == 0 ? '\n' : '.');
-                    d--;
-                }
-                else if (d >= b)
-                {
-                    out.write(buf);
-                    d = d - b;
-                }
-                else
-                {
-                    out.write(buf, 0, (int) d);
-                    d = 0;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private String notag(String s)
-    {
-        if (s == null) return "null";
-        s = replace(s, "&", "&amp;");
-        s = replace(s, "<", "&lt;");
-        s = replace(s, ">", "&gt;");
-        return s;
-    }
-
-    /**
-     * replace substrings within string.
-     */
-    public static String replace(String s, String sub, String with)
-    {
-        int c = 0;
-        int i = s.indexOf(sub, c);
-        if (i == -1) return s;
-
-        StringBuffer buf = new StringBuffer(s.length() + with.length());
-
-        synchronized (buf)
-        {
-            do
-            {
-                buf.append(s.substring(c, i));
-                buf.append(with);
-                c = i + sub.length();
-            }
-            while ((i = s.indexOf(sub, c)) != -1);
-
-            if (c < s.length()) buf.append(s.substring(c, s.length()));
-
-            return buf.toString();
-        }
-    }
-}
diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/BridgeServletExtended.java b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/BridgeServletExtended.java
deleted file mode 100644
index 99cabf6..0000000
--- a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/BridgeServletExtended.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.
-//  ========================================================================
-//
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.equinox.servletbridge.BridgeServlet;
-
-/**
- * Override the BridgeServlet to report on whether equinox is actually started
- * or not in case it is started asynchronously.
- * 
- * @author hmalphettes
- */
-public class BridgeServletExtended extends BridgeServlet
-{
-
-    @Override
-    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
-    {
-        if (FrameworkLauncherExtended.ASYNCH_START_IN_PROGRESS != null && req.getMethod().equals("GET"))
-        {
-            if (FrameworkLauncherExtended.ASYNCH_START_IN_PROGRESS)
-            {
-                resp.getWriter().append("Equinox is currently starting...\n");
-                return;
-            }
-            else if (FrameworkLauncherExtended.ASYNCH_START_FAILURE != null)
-            {
-                resp.getWriter().append("Equinox failed to start:\n");
-                FrameworkLauncherExtended.ASYNCH_START_FAILURE.printStackTrace(resp.getWriter());
-                return;
-            }
-        }
-        super.service(req, resp);
-    }
-
-}
diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/FrameworkLauncherExtended.java b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/FrameworkLauncherExtended.java
deleted file mode 100644
index e35f414..0000000
--- a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/FrameworkLauncherExtended.java
+++ /dev/null
@@ -1,716 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.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.BufferedReader;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Properties;
-import java.util.TreeMap;
-import java.util.jar.Attributes;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-
-import org.eclipse.equinox.servletbridge.FrameworkLauncher;
-
-/**
- * Extend the servletbridge FrameworkLauncher to support launching an equinox
- * installation made by p2director.
- */
-public class FrameworkLauncherExtended extends FrameworkLauncher
-{
-
-    /**
-     * if the OSGI_INSTALL_AREA installed area is specified as a sytem property
-     * and matches a Folder on the file system, we don't copy the whole eclipse
-     * installation instead we use that folder as it is
-     */
-    private static final String DEPLOY_IN_PLACE_WHEN_INSTALL_AREA_IS_FOLDER = "org.eclipse.equinox.servletbridge.deployinplace"; //$NON-NLS-1$
-
-    public static final String FRAMEWORK_BOOTDELEGATION = "org.osgi.framework.bootdelegation";
-
-    private boolean deployedInPlace = false;
-
-    private URL resourceBaseAsURL = null;
-
-    protected static Boolean ASYNCH_START_IN_PROGRESS;
-
-    protected static Throwable ASYNCH_START_FAILURE = null;
-
-    /**
-     * If the start is asynch we do it in a different thread and return
-     * immediately.
-     */
-    @Override
-    public synchronized void start()
-    {
-        if (ASYNCH_START_IN_PROGRESS == null && "true".equals(super.config.getInitParameter("asyncStart")))
-        {
-            final ClassLoader webappCl = Thread.currentThread().getContextClassLoader();
-            Thread th = new Thread()
-            {
-                public void run()
-                {
-                    Thread.currentThread().setContextClassLoader(webappCl);
-                    System.out.println("Jetty-Nested: Starting equinox asynchronously.");
-                    FrameworkLauncherExtended.this.start();
-                    System.out.println("Jetty-Nested: Finished starting equinox asynchronously.");
-                }
-            };
-            ASYNCH_START_IN_PROGRESS = true;
-            try
-            {
-                th.start();
-            }
-            catch (Throwable t)
-            {
-                ASYNCH_START_FAILURE = t;
-                if (t instanceof RuntimeException)
-                {
-                    throw (RuntimeException) t;
-                }
-                else
-                {
-                    throw new RuntimeException("Equinox failed to start", t);
-                }
-            }
-            finally
-            {
-                ASYNCH_START_IN_PROGRESS = false;
-            }
-        }
-        else
-        {
-            System.out.println("Jetty-Nested: Starting equinox synchronously.");
-            super.start();
-            System.out.println("Jetty-Nested: Finished starting equinox synchronously.");
-        }
-    }
-
-    /**
-     * try to find the resource base for this webapp by looking for the launcher
-     * initialization file.
-     */
-    protected void initResourceBase()
-    {
-        try
-        {
-            String resourceBaseStr = System.getProperty(OSGI_INSTALL_AREA);
-            if (resourceBaseStr == null || resourceBaseStr.length() == 0)
-            {
-                resourceBaseStr = config.getInitParameter(OSGI_INSTALL_AREA);
-            }
-            if (resourceBaseStr != null && resourceBaseStr.length() != 0)
-            {
-                // If the path starts with a reference to a system property,
-                // resolve it.
-                resourceBaseStr = resolveSystemProperty(resourceBaseStr);
-                if (resourceBaseStr.startsWith("/WEB-INF/"))
-                {
-                    String rpath = context.getRealPath(resourceBaseStr);
-                    if (rpath != null)
-                    {
-                        File rpathFile = new File(rpath);
-                        if (rpathFile.exists() && rpathFile.isDirectory() && rpathFile.canWrite())
-                        {
-                            resourceBaseStr = rpath;
-                        }
-                    }
-                }
-
-                if (resourceBaseStr.startsWith("file://"))
-                {
-                    resourceBaseAsURL = new URL(resourceBaseStr.replace(" ", "%20")); //$NON-NLS-1$ //$NON-NLS-2$
-                }
-                else if (new File(resourceBaseStr).exists())
-                {
-                    resourceBaseAsURL = new URL("file://" + new File(resourceBaseStr).getCanonicalPath().replace(" ", "%20")); //$NON-NLS-1$ //$NON-NLS-2$
-                }
-                else
-                {
-                    resourceBaseAsURL = context.getResource(resourceBaseStr);
-                }
-            }
-            else
-            {
-                if (context.getResource(RESOURCE_BASE + ECLIPSE) != null)
-                {
-                    resourceBase = RESOURCE_BASE + ECLIPSE;
-                }
-                else
-                {
-                    super.initResourceBase();
-                }
-                resourceBaseAsURL = context.getResource(resourceBase);
-            }
-        }
-        catch (MalformedURLException e)
-        {
-            // ignore
-        }
-        catch (IOException e)
-        {
-            // ignore
-        }
-        if (resourceBaseAsURL != null && resourceBaseAsURL.getProtocol().equals("file"))
-        {
-            File resBase = new File(resourceBaseAsURL.getPath());
-            if (resBase.exists() && resBase.isDirectory()
-                    && !Boolean.FALSE.toString().equalsIgnoreCase(System.getProperty(DEPLOY_IN_PLACE_WHEN_INSTALL_AREA_IS_FOLDER)))
-            {
-                __setPlatformDirectory(resBase);
-                deployedInPlace = true;
-            }
-        }
-    }
-
-    /**
-     * Override this method to be able to set default system properties computed
-     * on the fly depending on the environment where equinox and jetty-osgi are
-     * deployed.
-     * 
-     * @param resource - The target to read properties from
-     * @return the properties
-     */
-    protected Properties loadProperties(String resource)
-    {
-        Properties props = super.loadProperties(resource);
-        if (resource.equals(resourceBase + LAUNCH_INI) && deployedInPlace)
-        {
-            String osgiInstall = props.getProperty(OSGI_INSTALL_AREA);
-            if (osgiInstall == null)
-            {
-                // compute the osgi install dynamically.
-                props.put(OSGI_INSTALL_AREA, getPlatformDirectory().getAbsolutePath());
-            }
-            String osgiFramework = props.getProperty(OSGI_FRAMEWORK);
-            File pluginsFolder = null;
-            if (osgiFramework == null && getPlatformDirectory() != null)
-            {
-                File osgiFrameworkF = findOsgiFramework(getPlatformDirectory());
-                pluginsFolder = osgiFrameworkF.getParentFile();
-                props.put(OSGI_FRAMEWORK, osgiFrameworkF.getAbsoluteFile().getAbsolutePath());
-            }
-            String osgiFrameworkExtensions = props.getProperty(OSGI_FRAMEWORK_EXTENSIONS);
-            if (osgiFrameworkExtensions == null)
-            {
-                // this bundle will make the javax.servlet and
-                // javax.servlet.http packages passed from
-                // the bootstrap classloader into equinox
-                osgiFrameworkExtensions = "org.eclipse.equinox.servletbridge.extensionbundle";
-            }
-            File configIni = new File(getPlatformDirectory(), "configuration/config.ini");
-            Properties configIniProps = new Properties();
-            if (configIni.exists())
-            {
-                System.out.println("Got the " + configIni.getAbsolutePath());
-                InputStream configIniStream = null;
-                try
-                {
-                    configIniStream = new FileInputStream(configIni);
-                    configIniProps.load(configIniStream);
-                }
-                catch (IOException ioe)
-                {
-
-                }
-                finally
-                {
-                    try
-                    {
-                        configIniStream.close();
-                    }
-                    catch (IOException ioe2)
-                    {
-                    }
-                }
-                String confIniFrameworkExt = configIniProps.getProperty(OSGI_FRAMEWORK_EXTENSIONS);
-                if (confIniFrameworkExt != null)
-                {
-                    osgiFrameworkExtensions = osgiFrameworkExtensions + "," + confIniFrameworkExt;
-                }
-            }
-            else
-            {
-                System.out.println("Unable to locate the " + configIni.getAbsolutePath());
-            }
-            props.setProperty(OSGI_FRAMEWORK_EXTENSIONS, osgiFrameworkExtensions);
-            // __deployExtensionBundle(pluginsFolder);
-            deployExtensionBundle(pluginsFolder, true);
-
-            String bootDeleg = props.getProperty(FRAMEWORK_BOOTDELEGATION);
-            if (bootDeleg == null)
-            {
-                bootDeleg = configIniProps.getProperty(FRAMEWORK_BOOTDELEGATION);
-            }
-            if (bootDeleg == null || bootDeleg.indexOf("javax.servlet.http") == -1)
-            {
-                String add = "javax.servlet,javax.servlet.http,javax.servlet.resources";
-                if (bootDeleg != null)
-                {
-                    bootDeleg += add;
-                }
-                else
-                {
-                    bootDeleg = add;
-                }
-                props.setProperty(FRAMEWORK_BOOTDELEGATION, bootDeleg);
-            }
-
-            String jettyHome = System.getProperty("jetty.home");
-            if (jettyHome == null)
-            {
-                jettyHome = getPlatformDirectory().getAbsolutePath();
-                System.setProperty("jetty.home", jettyHome);
-                props.setProperty("jetty.home", jettyHome);
-            }
-            else
-            {
-                jettyHome = resolveSystemProperty(jettyHome);
-            }
-            String etcJettyXml = System.getProperty("jetty.etc.config.urls");
-            if (etcJettyXml == null)
-            {
-                etcJettyXml = "etc/jetty.xml";
-                if (new File(jettyHome, "etc/jetty-nested.xml").exists())
-                {
-                    etcJettyXml += ",etc/jetty-nested.xml";
-                }
-                System.setProperty("jetty.etc.config.urls", etcJettyXml);
-                props.setProperty("jetty.etc.config.urls", etcJettyXml);
-            }
-            String startLevel = System.getProperty("osgi.startLevel");
-            if (startLevel == null)
-            {
-                startLevel = props.getProperty("osgi.startLevel");
-                if (startLevel == null)
-                {
-                    startLevel = configIniProps.getProperty("osgi.startLevel");
-                }
-                if (startLevel != null)
-                {
-                    props.setProperty("osgi.startLevel", startLevel);
-                    System.setProperty("osgi.startLevel", startLevel);
-                }
-            }
-            String logback = System.getProperty("logback.configurationFile");
-            if (logback == null)
-            {
-                File etcLogback = new File(jettyHome, "etc/logback-nested.xml");
-                if (!etcLogback.exists())
-                {
-                    etcLogback = new File(jettyHome, "etc/logback.xml");
-                }
-                if (etcLogback.exists())
-                {
-                    System.setProperty("logback.configurationFile", etcLogback.getAbsolutePath());
-                    props.setProperty("logback.configurationFile", etcLogback.getAbsolutePath());
-                }
-            }
-            else
-            {
-                logback = resolveSystemProperty(logback);
-            }
-            System.out.println("sysout: logback.configurationFile=" + System.getProperty("logback.configurationFile"));
-        }
-        return props;
-    }
-
-    /**
-     * Look for the eclipse.ini file. or any *.ini Search for the argument
-     * -startup The next line is a relative path to the launcher osgi bundle:
-     * ../bundlepool/plugins/org.eclipse.equinox.launcher_1.1.0.v20100507.jar
-     * Get that file, get the parent folder. This is where the plugins are
-     * located. In that folder look for the
-     * 
-     * @param installFolder
-     * @return The osgi framework bundle.
-     */
-    private File findOsgiFramework(File installFolder)
-    {
-        File[] fs = installFolder.listFiles();
-        for (int i = 0; i < fs.length; i++)
-        {
-            File f = fs[i];
-            if (f.isFile() && f.getName().endsWith(".ini") && !f.getName().equals(LAUNCH_INI))
-            {
-                BufferedReader br = null;
-                try
-                {
-                    br = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
-                    String line = null;
-                    String pathToLauncherJar = null;
-                    boolean gotStartArg = false;
-                    while ((line = br.readLine()) != null)
-                    {
-                        if (gotStartArg)
-                        {
-                            pathToLauncherJar = line.trim();
-                            if (pathToLauncherJar.length() == 0)
-                            {
-                                continue;
-                            }
-                            break;
-                        }
-                        else if (line.trim().equals("-startup"))
-                        {
-                            gotStartArg = true;
-                        }
-                    }
-                    if (pathToLauncherJar != null)
-                    {
-                        File currFolder = getPlatformDirectory();
-                        String oriStartup = pathToLauncherJar;
-                        while (pathToLauncherJar.startsWith("../"))
-                        {
-                            currFolder = currFolder.getParentFile();
-                            pathToLauncherJar = pathToLauncherJar.substring(3);
-                        }
-                        File pluginsfolder = new File(currFolder, pathToLauncherJar).getParentFile();
-                        // System.err.println("Got the pluginsfolder " +
-                        // pluginsfolder);
-                        if (!pluginsfolder.exists()) { throw new IllegalStateException("The -startup argument in " + f.getPath()
-                                                                                       + " is "
-                                                                                       + oriStartup
-                                                                                       + ". It points to "
-                                                                                       + pluginsfolder.getPath()
-                                                                                       + " plugins directory that does not exists."); }
-                        TreeMap osgis = new TreeMap();
-                        File[] plugins = pluginsfolder.listFiles();
-                        for (int j = 0; j < plugins.length; j++)
-                        {
-                            File b = plugins[j];
-                            if (b.isFile() && b.getName().startsWith(FRAMEWORK_BUNDLE_NAME + "_") && b.getName().endsWith(".jar"))
-                            {
-                                osgis.put(b.getName(), b);
-                            }
-                        }
-                        if (osgis.isEmpty()) { throw new IllegalStateException("The -startup argument in " + f.getPath()
-                                                                               + " is "
-                                                                               + oriStartup
-                                                                               + ". It points to "
-                                                                               + pluginsfolder.getPath()
-                                                                               + " plugins directory but there is no org.eclipse.osgi.*.jar files there."); }
-                        File osgiFramework = (File) osgis.values().iterator().next();
-                        String path = osgiFramework.getPath();
-                        System.err.println("Using " + path + " for the osgi framework.");
-                        return osgiFramework;
-                    }
-                }
-                catch (IOException ioe)
-                {
-                    //
-                }
-                finally
-                {
-                    if (br != null) try
-                    {
-                        br.close();
-                    }
-                    catch (IOException ii)
-                    {
-                    }
-                }
-
-            }
-        }
-        return null;
-    }
-
-    /**
-     * recursively substitute the ${sysprop} by their actual system property.
-     * ${sysprop,defaultvalue} will use 'defaultvalue' 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
-     */
-    public static String resolveSystemProperty(String value)
-    {
-        int ind = value.indexOf("${");
-        if (ind == -1) { return value; }
-        int ind2 = value.indexOf('}', ind);
-        if (ind2 == -1) { return value; }
-        String sysprop = value.substring(ind + 2, ind2);
-        String defaultValue = null;
-        int comma = sysprop.indexOf(',');
-        if (comma != -1 && comma + 1 != sysprop.length())
-        {
-            defaultValue = sysprop.substring(comma + 1);
-            defaultValue = resolveSystemProperty(defaultValue);
-            sysprop = sysprop.substring(0, comma);
-        }
-        else
-        {
-            defaultValue = "${" + sysprop + "}";
-        }
-
-        String v = System.getProperty(sysprop);
-
-        String reminder = value.length() > ind2 + 1 ? value.substring(ind2 + 1) : "";
-        reminder = resolveSystemProperty(reminder);
-        if (v != null)
-        {
-            return value.substring(0, ind) + v + reminder;
-        }
-        else
-        {
-            return value.substring(0, ind) + defaultValue + reminder;
-        }
-    }
-
-    // introspection trick to be able to set the private field platformDirectory
-    private static Field _field;
-
-    void __setPlatformDirectory(File platformDirectory)
-    {
-        try
-        {
-            if (_field == null)
-            {
-                _field = org.eclipse.equinox.servletbridge.FrameworkLauncher.class.getDeclaredField("platformDirectory");
-                _field.setAccessible(true);
-            }
-            _field.set(this, platformDirectory);
-        }
-        catch (SecurityException e)
-        {
-            e.printStackTrace();
-        }
-        catch (NoSuchFieldException e)
-        {
-            e.printStackTrace();
-        }
-        catch (IllegalArgumentException e)
-        {
-            e.printStackTrace();
-        }
-        catch (IllegalAccessException e)
-        {
-            e.printStackTrace();
-        }
-    }
-
-    // introspection trick to invoke the generateExtensionBundle method
-    private static Method _deployExtensionBundleMethod;
-
-    private void __deployExtensionBundle(File plugins)
-    {
-        // look for the extensionbundle
-        // if it is already there no need to do something:
-        for (String file : plugins.list())
-        {
-            if (file.startsWith("org.eclipse.equinox.servletbridge.extensionbundle"))// EXTENSIONBUNDLE_DEFAULT_BSN
-            { return; }
-        }
-
-        try
-        {
-            // invoke deployExtensionBundle(File plugins)
-            if (_deployExtensionBundleMethod == null)
-            { 
-                _deployExtensionBundleMethod = FrameworkLauncher.class.getDeclaredMethod("deployExtensionBundle", File.class);
-                _deployExtensionBundleMethod.setAccessible(true);
-            }
-            _deployExtensionBundleMethod.invoke(this, plugins);
-        }
-        catch (Throwable t)
-        {
-            t.printStackTrace();
-        }
-    }
-
-    // --end of introspection to invoke deployExtensionBundle
-
-    // from Framework with support for the equinox hook
-    private static final String EXTENSIONBUNDLE_DEFAULT_BSN = "org.eclipse.equinox.servletbridge.extensionbundle"; //$NON-NLS-1$
-
-    private static final String EXTENSIONBUNDLE_DEFAULT_VERSION = "1.2.0"; //$NON-NLS-1$
-
-    private static final String MANIFEST_VERSION = "Manifest-Version"; //$NON-NLS-1$
-
-    private static final String BUNDLE_MANIFEST_VERSION = "Bundle-ManifestVersion"; //$NON-NLS-1$
-
-    private static final String BUNDLE_NAME = "Bundle-Name"; //$NON-NLS-1$
-
-    private static final String BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName"; //$NON-NLS-1$
-
-    private static final String BUNDLE_VERSION = "Bundle-Version"; //$NON-NLS-1$
-
-    private static final String FRAGMENT_HOST = "Fragment-Host"; //$NON-NLS-1$
-
-    private static final String EXPORT_PACKAGE = "Export-Package"; //$NON-NLS-1$
-
-    private static final String CONFIG_EXTENDED_FRAMEWORK_EXPORTS = "extendedFrameworkExports"; //$NON-NLS-1$
-
-    private void deployExtensionBundle(File plugins, boolean configureEquinoxHook)
-    {
-        // we might want to parameterize the extension bundle BSN in the future
-        final String extensionBundleBSN = EXTENSIONBUNDLE_DEFAULT_BSN;
-        File extensionBundleFile = findExtensionBundleFile(plugins, extensionBundleBSN);
-
-        if (extensionBundleFile == null)
-            generateExtensionBundle(plugins, extensionBundleBSN, EXTENSIONBUNDLE_DEFAULT_VERSION, configureEquinoxHook);
-        else
-            /*
-             * if (Boolean.valueOf(config.getInitParameter(
-             * CONFIG_OVERRIDE_AND_REPLACE_EXTENSION_BUNDLE)).booleanValue())
-             */{
-            String extensionBundleVersion = findExtensionBundleVersion(extensionBundleFile, extensionBundleBSN);
-            if (extensionBundleFile.isDirectory())
-            {
-                deleteDirectory(extensionBundleFile);
-            }
-            else
-            {
-                extensionBundleFile.delete();
-            }
-            generateExtensionBundle(plugins, extensionBundleBSN, extensionBundleVersion, true);
-            // } else {
-            // processExtensionBundle(extensionBundleFile);
-        }
-    }
-
-    private File findExtensionBundleFile(File plugins, final String extensionBundleBSN)
-    {
-        FileFilter extensionBundleFilter = new FileFilter()
-        {
-            public boolean accept(File candidate)
-            {
-                return candidate.getName().startsWith(extensionBundleBSN + "_"); //$NON-NLS-1$
-            }
-        };
-        File[] extensionBundles = plugins.listFiles(extensionBundleFilter);
-        if (extensionBundles.length == 0) return null;
-
-        if (extensionBundles.length > 1)
-        {
-            for (int i = 1; i < extensionBundles.length; i++)
-            {
-                if (extensionBundles[i].isDirectory())
-                {
-                    deleteDirectory(extensionBundles[i]);
-                }
-                else
-                {
-                    extensionBundles[i].delete();
-                }
-            }
-        }
-        return extensionBundles[0];
-    }
-
-    private String findExtensionBundleVersion(File extensionBundleFile, String extensionBundleBSN)
-    {
-        String fileName = extensionBundleFile.getName();
-        if (fileName.endsWith(".jar")) { return fileName.substring(extensionBundleBSN.length() + 1, fileName.length() - ".jar".length()); }
-        return fileName.substring(extensionBundleBSN.length() + 1);
-    }
-
-    private void generateExtensionBundle(File plugins, String extensionBundleBSN, String extensionBundleVersion, boolean configureEquinoxHook)
-    {
-        Manifest mf = new Manifest();
-        Attributes attribs = mf.getMainAttributes();
-        attribs.putValue(MANIFEST_VERSION, "1.0"); //$NON-NLS-1$
-        attribs.putValue(BUNDLE_MANIFEST_VERSION, "2"); //$NON-NLS-1$
-        attribs.putValue(BUNDLE_NAME, "Servletbridge Extension Bundle"); //$NON-NLS-1$
-        attribs.putValue(BUNDLE_SYMBOLIC_NAME, extensionBundleBSN);
-        attribs.putValue(BUNDLE_VERSION, extensionBundleVersion);
-        attribs.putValue(FRAGMENT_HOST, "system.bundle; extension:=framework"); //$NON-NLS-1$
-
-        String servletVersion = context.getMajorVersion() + "." + context.getMinorVersion(); //$NON-NLS-1$
-        String packageExports = "org.eclipse.equinox.servletbridge; version=1.1"
-                                 + ", javax.servlet; version="
-                                 + servletVersion
-                                 + ", javax.servlet.http; version="
-                                 + servletVersion
-                                 + ", javax.servlet.resources; version="
-                                 + servletVersion; 
-
-        String extendedExports = config.getInitParameter(CONFIG_EXTENDED_FRAMEWORK_EXPORTS);
-        if (extendedExports != null && extendedExports.trim().length() != 0) packageExports += ", " + extendedExports; //$NON-NLS-1$
-
-        attribs.putValue(EXPORT_PACKAGE, packageExports);
-        writeJarFile(new File(plugins, extensionBundleBSN + "_" + extensionBundleVersion + ".jar"), mf, configureEquinoxHook); //$NON-NLS-1$
-    }
-
-    private void writeJarFile(File jarFile, Manifest mf, boolean configureEquinoxHook)
-    {
-        try
-        {
-            JarOutputStream jos = null;
-            try
-            {
-                jos = new JarOutputStream(new FileOutputStream(jarFile), mf);
-
-                if (configureEquinoxHook)
-                {
-                    // hook configurator properties:
-                    ZipEntry e = new ZipEntry("hookconfigurators.properties");
-                    jos.putNextEntry(e);
-                    Properties props = new Properties();
-                    props.put("hook.configurators", "org.eclipse.jetty.osgi.servletbridge.hook.ServletBridgeClassLoaderDelegateHook");
-                    props.store(jos, "");
-                    jos.closeEntry();
-
-                    // the hook class
-                    e = new ZipEntry("org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.class");
-                    jos.putNextEntry(e);
-                    InputStream in = getClass().getResourceAsStream("/org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.class");
-
-                    byte[] buffer = new byte[512];
-                    try
-                    {
-                        int n;
-                        while ((n = in.read(buffer)) != -1)
-                        {
-                            jos.write(buffer, 0, n);
-                        }
-                    }
-                    finally
-                    {
-                        in.close();
-                    }
-                    jos.closeEntry();
-                }
-
-                jos.finish();
-            }
-            finally
-            {
-                if (jos != null) jos.close();
-            }
-        }
-        catch (IOException e)
-        {
-            context.log("Error writing extension bundle", e); //$NON-NLS-1$
-        }
-    }
-    // --from Framework with support for the equinox hook
-
-}
diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.java b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.java
deleted file mode 100644
index 523240c..0000000
--- a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.java
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.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.FileNotFoundException;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.eclipse.core.runtime.adaptor.EclipseStarter;
-import org.eclipse.osgi.baseadaptor.HookConfigurator;
-import org.eclipse.osgi.baseadaptor.HookRegistry;
-import org.eclipse.osgi.framework.adaptor.BundleClassLoader;
-import org.eclipse.osgi.framework.adaptor.BundleData;
-import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegateHook;
-import org.eclipse.osgi.internal.loader.BundleLoader;
-
-/**
- * With some complex osgi products, experience shows that using a system bundle
- * extension to pass certain packages from the bootstrapping server to equinox
- * fails. The bundles keep loading javax.servlet.http from the javax.servlet
- * bundle. This class is in fact copied into the servletbridge.extensionbundle;
- * it is not loaded by the webapp.
- */
-public class ServletBridgeClassLoaderDelegateHook implements ClassLoaderDelegateHook, HookConfigurator
-{
-
-    private static Set<String> packagesInBootstrapClassLoader = new HashSet<String>();
-    static
-    {
-        packagesInBootstrapClassLoader.add("javax.servlet");
-        packagesInBootstrapClassLoader.add("javax.servlet.http");
-    }
-
-    public void addHooks(HookRegistry hookRegistry)
-    {
-        hookRegistry.addClassLoaderDelegateHook(this);
-    }
-
-    public Class preFindClass(String name, BundleClassLoader classLoader, BundleData data) throws ClassNotFoundException
-    {
-        String pkgName = BundleLoader.getPackageName(name);
-        if (packagesInBootstrapClassLoader.contains(pkgName)) { return EclipseStarter.class.getClassLoader().loadClass(name); }
-        return null;
-    }
-
-    public Class postFindClass(String name, BundleClassLoader classLoader, BundleData data) throws ClassNotFoundException
-    {
-        return null;
-    }
-
-    public URL preFindResource(String name, BundleClassLoader classLoader, BundleData data) throws FileNotFoundException
-    {
-        return null;
-    }
-
-    public URL postFindResource(String name, BundleClassLoader classLoader, BundleData data) throws FileNotFoundException
-    {
-        return null;
-    }
-
-    public Enumeration preFindResources(String name, BundleClassLoader classLoader, BundleData data) throws FileNotFoundException
-    {
-        return null;
-    }
-
-    public Enumeration postFindResources(String name, BundleClassLoader classLoader, BundleData data) throws FileNotFoundException
-    {
-        return null;
-    }
-
-    public String preFindLibrary(String name, BundleClassLoader classLoader, BundleData data) throws FileNotFoundException
-    {
-        return null;
-    }
-
-    public String postFindLibrary(String name, BundleClassLoader classLoader, BundleData data)
-    {
-        return null;
-    }
-
-}
diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml b/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml
deleted file mode 100644
index c61dee5..0000000
--- a/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?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>jettyservletbridge</display-name>
-	<servlet id="proxy">
-	    <servlet-name>proxy</servlet-name>
-	    <display-name>Transparent Proxy Servlet and Equinox Framework Controller</display-name>
-	    <description>Transparent Proxy Servlet and Equinox Framework Controller</description>
-	    <servlet-class>org.eclipse.jetty.osgi.servletbridge.BridgeServletExtended</servlet-class>
-	    <!-- Point to a folder where an equinox installation exists.
-	         When this parameter is defined, that equinox installation is launched in place.
-             The parameter can also be passed as a system property. -->
-	    <init-param>
-	        <param-name>osgi.install.area</param-name>
-            <param-value>/WEB-INF/eclipse</param-value>
-	    </init-param>
-	    <!-- Start equinox in a different thread and display a simple
-	         a simple status message until it is started. -->
-	    <init-param>
-	        <param-name>asyncStart</param-name>
-	        <param-value>true</param-value>
-	    </init-param>
-		<init-param>
-			<param-name>commandline</param-name>
-			<param-value>-console</param-value>			
-		</init-param>
-		<init-param>
-			<param-name>enableFrameworkControls</param-name>
-			<param-value>true</param-value>			
-		</init-param>
-		<!--
-		  org.eclipse.equinox.servletbridge and the Servlet API are exported automatically to the underlying OSGi framework.
-		  The extendedFrameworkExports parameter allows the specification of additional java package exports.
-		  The format is a comma separated list of exports as specified by the "Export-Package" bundle manifest header.
-		  For example: com.mycompany.exports; version=1.0.0, com.mycompany.otherexports; version=1.0.0
-		  -->
-		<init-param>
-			<param-name>extendedFrameworkExports</param-name>
-			<param-value></param-value>			
-		</init-param>
-	
-		<!-- 
-		  You can specify your own framework launcher here.
-		  The default is: org.eclipse.equinox.servletbridge.FrameworkLauncher -->
-		<init-param>
-			<param-name>frameworkLauncherClass</param-name>
-			<param-value>org.eclipse.jetty.osgi.servletbridge.FrameworkLauncherExtended</param-value>
-			<!--param-value>org.eclipse.equinox.servletbridge.FrameworkLauncher</param-value-->
-		</init-param>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-    
-    <servlet>
-      <servlet-name>dump</servlet-name>
-      <servlet-class>org.eclipse.jetty.nested.Dump</servlet-class>
-      <load-on-startup>1</load-on-startup>
-    </servlet>
-
-    <servlet-mapping>
-      <servlet-name>dump</servlet-name>
-      <url-pattern>/dump/*</url-pattern>
-    </servlet-mapping>
-	<servlet-mapping>
-		<servlet-name>proxy</servlet-name>
-		<url-pattern>/*</url-pattern>
-	</servlet-mapping>
-	
-</web-app>
\ No newline at end of file
diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml
index 6dc3e22..65c947e 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.eclipse.jetty.osgi</groupId>
@@ -22,10 +22,8 @@
   <modules>
     <module>jetty-osgi-boot</module>
     <module>jetty-osgi-boot-jsp</module>
-    <module>jetty-osgi-boot-logback</module>
     <module>jetty-osgi-boot-warurl</module>
     <module>jetty-osgi-httpservice</module>
-    <module>jetty-osgi-equinoxtools</module>
     <module>test-jetty-osgi-webapp</module>
     <module>test-jetty-osgi-context</module>
     <module>test-jetty-osgi</module>
@@ -60,6 +58,13 @@
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <skipTests>true</skipTests>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-eclipse-plugin</artifactId>
         <version>2.8</version>
         <configuration>
@@ -77,7 +82,7 @@
     <dependencies>
       <dependency>
         <groupId>org.eclipse.jetty</groupId>
-        <artifactId>jetty-server</artifactId>
+        <artifactId>jetty-annotations</artifactId>
         <version>${project.version}</version>
       </dependency>
       <dependency>
@@ -145,6 +150,23 @@
         <artifactId>servletbridge</artifactId>
         <version>${equinox-servletbridge-version}</version>
       </dependency-->
+      <!-- not ready <dependency>
+        <groupId>org.mortbay.jetty</groupId>
+        <artifactId>jsp-impl</artifactId>
+        <version>${jsp-impl-2.2-glassfish-version}</version>
+      </dependency-->
+<!--
+      <dependency>
+        <groupId>org.mortbay.jetty</groupId>
+        <artifactId>jsp-2.1-glassfish</artifactId>
+        <version>${jsp-2.1-glassfish-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.mortbay.jetty</groupId>
+        <artifactId>jsp-api-2.1-glassfish</artifactId>
+        <version>${jsp-2.1-glassfish-version}</version>
+      </dependency>
+-->
       <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml
index a1d2cb5..095f6ae 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -17,6 +17,7 @@
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-server</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
     	<groupId>org.eclipse.osgi</groupId>
@@ -108,8 +109,8 @@
                         compilation time. --> 
                         <_nouses>true</_nouses>
                         <Import-Package>
- javax.servlet;version="2.5.0",
- javax.servlet.resources;version="2.5.0",
+ javax.servlet;version="2.6.0",
+ javax.servlet.resources;version="2.6.0",
  org.osgi.framework,
  org.osgi.service.cm;version="1.2.0",
  org.osgi.service.packageadmin,
@@ -123,7 +124,7 @@
  org.xml.sax.helpers,
  *
                         </Import-Package>
-                        <DynamicImport-Package>org.eclipse.jetty.*;version="[7.6,8)"</DynamicImport-Package>
+                        <DynamicImport-Package>org.eclipse.jetty.*;version="[8.1,9)"</DynamicImport-Package>
                         <!--Require-Bundle/-->
                         <!-- Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment --> 
                     </instructions>
diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml
index 5eb44cb..09f0f83 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -118,7 +118,7 @@
  org.xml.sax.helpers,
  *
                         </Import-Package>
-                        <DynamicImport-Package>org.eclipse.jetty.*;version="[7.6,8)"</DynamicImport-Package>
+                        <DynamicImport-Package>org.eclipse.jetty.*;version="[8.1,9)"</DynamicImport-Package>
                         <!--Require-Bundle/-->
                         <!-- Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment --> 
                     </instructions>
diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml
index 39bd34e..934161e 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -12,6 +12,7 @@
   <url>http://www.eclipse.org/jetty</url>
   <properties>
     <bundle-symbolic-name>${project.groupId}.boot.test</bundle-symbolic-name>
+    <jetty-orbit-url>http://download.eclipse.org/jetty/orbit/</jetty-orbit-url>
     <assembly-directory>target/distribution</assembly-directory>
     <paxexam-version>1.2.0</paxexam-version>
   </properties>
@@ -224,7 +225,7 @@
                   <version>${orbit-servlet-api-version}</version>
                   <overWrite>true</overWrite>
                   <outputDirectory>${assembly-directory}/lib</outputDirectory>
-                  <destFileName>servlet-api-2.5.jar</destFileName>
+                  <destFileName>servlet-api-3.0.jar</destFileName>
                 </artifactItem>
               </artifactItems>
             </configuration>
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWebAppAsService.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWebAppAsService.java
index ca8c1c6..d4fdec4 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWebAppAsService.java
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWebAppAsService.java
@@ -39,6 +39,7 @@
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.CoreOptions;
 import org.ops4j.pax.exam.Inject;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.container.def.PaxRunnerOptions;
@@ -72,7 +73,8 @@
     {
     	ArrayList<Option> options = new ArrayList<Option>();
     	options.addAll(TestJettyOSGiBootCore.provisionCoreJetty());
-    	
+        options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*",
+                                                       "org.w3c.*", "javax.xml.*"));
     	   File base = MavenTestingUtils.getBasedir();
            File src = new File (base, "src");
            File tst = new File (src, "test");
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWithJsp.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWithJsp.java
index e7dd40d..0c26ade 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWithJsp.java
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWithJsp.java
@@ -134,14 +134,13 @@
      * plus your testcase, wrapped into a bundle called pax-exam-probe
      */
     @Test
-    
     public void listBundles() throws Exception
     {
     	Map<String,Bundle> bundlesIndexedBySymbolicName = new HashMap<String, Bundle>();
         for( Bundle b : bundleContext.getBundles() )
         {
         	bundlesIndexedBySymbolicName.put(b.getSymbolicName(), b);
-        	System.err.println("Got " + b.getSymbolicName() + " " + b.getVersion().toString() + " " + b.getState());
+        	System.err.println("Got " + b.getSymbolicName());
         }
         
         Bundle osgiBoot = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.osgi.boot");
@@ -150,11 +149,11 @@
         
         Bundle osgiBootJsp = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.osgi.boot.jsp");
         Assert.assertNotNull("Could not find the org.eclipse.jetty.osgi.boot.jsp bundle", osgiBootJsp);
-        Assert.assertTrue("The fragment jsp is not correctly resolved " + osgiBootJsp.getState(), osgiBootJsp.getState() == Bundle.RESOLVED);
+        Assert.assertTrue("The fragment jsp is not correctly resolved", osgiBootJsp.getState() == Bundle.RESOLVED);
         
         Bundle testWebBundle = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.test-jetty-webapp");
-        Assert.assertNotNull("Could not find the org.eclipse.jetty.test-jetty-webapp bundle", osgiBootJsp);
-        Assert.assertTrue("The bundle org.eclipse.jetty.test-jetty-webapp is not correctly resolved", testWebBundle.getState() == Bundle.ACTIVE);
+        Assert.assertNotNull("Could not find the test-jetty-webapp bundle", testWebBundle);
+        Assert.assertTrue("The test-jetty-webapp bundle is not correctly resolved", testWebBundle.getState() == Bundle.ACTIVE);
         
         //now test the jsp/dump.jsp
         HttpClient client = new HttpClient();
diff --git a/jetty-overlay-deployer/pom.xml b/jetty-overlay-deployer/pom.xml
index 469db75..443d880 100644
--- a/jetty-overlay-deployer/pom.xml
+++ b/jetty-overlay-deployer/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-overlay-deployer</artifactId>
diff --git a/jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java b/jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java
index fa1c9b8..eb4b1f4 100644
--- a/jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java
+++ b/jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java
@@ -32,6 +32,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -389,7 +390,7 @@
                 List<URL> libs = new ArrayList<URL>();
                 for (String jar :instance_lib.list())
                 {
-                    if (!jar.toLowerCase().endsWith(".jar"))
+                    if (!jar.toLowerCase(Locale.ENGLISH).endsWith(".jar"))
                         continue;
                     libs.add(instance_lib.addPath(jar).getURL());
                 }
@@ -610,7 +611,7 @@
         {
             for (String jar :lib.list())
             {
-                if (!jar.toLowerCase().endsWith(".jar"))
+                if (!jar.toLowerCase(Locale.ENGLISH).endsWith(".jar"))
                     continue;
                 libs.add(lib.addPath(jar).getURL());
             }
@@ -832,12 +833,12 @@
                 File origin = new File(new URI(_scanDir.toURI()+ruri));
                 String name=origin.getName();
                 
-                Monitor monitor = Monitor.valueOf(origin.getParentFile().getName().toUpperCase());
+                Monitor monitor = Monitor.valueOf(origin.getParentFile().getName().toUpperCase(Locale.ENGLISH));
                 
                 String ext=".war";
                 
                 // check directory vs archive 
-                if (origin.isDirectory() || !origin.exists() && !ruri.toLowerCase().endsWith(ext))
+                if (origin.isDirectory() || !origin.exists() && !ruri.toLowerCase(Locale.ENGLISH).endsWith(ext))
                 {
                     // directories have priority over archives
                     directory=origin;
@@ -846,7 +847,7 @@
                 else
                 {
                     // check extension name
-                    if (!ruri.toLowerCase().endsWith(ext))
+                    if (!ruri.toLowerCase(Locale.ENGLISH).endsWith(ext))
                         continue;
 
                     name=name.substring(0,name.length()-4);
diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml
index c688b05..58ff98b 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-plus</artifactId>
@@ -29,7 +29,7 @@
             <configuration>
               <instructions>
                <_versionpolicy> </_versionpolicy>
-               <Import-Package>javax.sql.*,javax.security.*,javax.naming.*,javax.servlet.*;version="[2.5,3.0)",javax.transaction.*;version="[1.1,1.2)",*</Import-Package>
+               <Import-Package>javax.sql.*,javax.security.*,javax.naming.*,javax.servlet.*;version="2.6.0",javax.transaction.*;version="[1.1,1.2)",*</Import-Package>
               </instructions>
             </configuration>
           </execution>
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
new file mode 100644
index 0000000..7ed4ead
--- /dev/null
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.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.plus.annotation;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.ServletContext;
+
+import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+public class ContainerInitializer
+{
+    protected ServletContainerInitializer _target;
+    protected Class[] _interestedTypes;
+    protected Set<String> _applicableTypeNames;
+    protected Set<String> _annotatedTypeNames;
+
+    
+    public void setTarget (ServletContainerInitializer target)
+    {
+        _target = target;
+    }
+    
+    public ServletContainerInitializer getTarget ()
+    {
+        return _target;
+    }
+
+    public Class[] getInterestedTypes ()
+    {
+        return _interestedTypes;
+    }
+    
+    public void setInterestedTypes (Class[] interestedTypes)
+    {
+        _interestedTypes = interestedTypes;
+    }
+    
+    /**
+     * A class has been found that has an annotation of interest 
+     * to this initializer.
+     * @param className
+     */
+    public void addAnnotatedTypeName (String className)
+    {
+        if (_annotatedTypeNames == null)
+            _annotatedTypeNames = new HashSet<String>();
+        _annotatedTypeNames.add(className);
+    }
+    
+    public Set<String> getAnnotatedTypeNames ()
+    {
+        return _annotatedTypeNames;
+    }
+    
+    public void addApplicableTypeName (String className)
+    {
+        if (_applicableTypeNames == null)
+            _applicableTypeNames = new HashSet<String>();
+        _applicableTypeNames.add(className);
+    }
+    
+    public Set<String> getApplicableTypeNames ()
+    {
+        return _applicableTypeNames;
+    }
+    
+    
+    public void callStartup(WebAppContext context)
+    throws Exception
+    {
+        if (_target != null)
+        {
+            Set<Class<?>> classes = new HashSet<Class<?>>();
+          
+            ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader(context.getClassLoader());
+
+            try
+            {
+                if (_applicableTypeNames != null)
+                {
+                    for (String s : _applicableTypeNames)
+                        classes.add(Loader.loadClass(context.getClass(), s));
+                }
+
+                _target.onStartup(classes, context.getServletContext());
+            }
+            finally
+            {
+                Thread.currentThread().setContextClassLoader(oldLoader);
+            }
+        }
+    }
+}
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
new file mode 100644
index 0000000..df208ed
--- /dev/null
+++ b/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessorTest.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.plus.webapp;
+
+
+
+
+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.net.URL;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.eclipse.jetty.webapp.Descriptor;
+import org.eclipse.jetty.webapp.FragmentDescriptor;
+import org.eclipse.jetty.webapp.Origin;
+import org.eclipse.jetty.webapp.WebAppClassLoader;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.webapp.WebDescriptor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * PlusDescriptorProcessorTest
+ *
+ *
+ */
+public class PlusDescriptorProcessorTest
+{
+    protected WebDescriptor webDescriptor;
+    protected FragmentDescriptor fragDescriptor1;
+    protected FragmentDescriptor fragDescriptor2;    
+    protected FragmentDescriptor fragDescriptor3;
+    protected WebAppContext context;
+    /**
+     * @throws java.lang.Exception
+     */
+    @Before
+    public void setUp() throws Exception
+    {
+        context = new WebAppContext();
+        context.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), context));
+        ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(context.getClassLoader());
+        Context icontext = new InitialContext();
+        Context compCtx =  (Context)icontext.lookup ("java:comp");
+        compCtx.createSubcontext("env");
+        Thread.currentThread().setContextClassLoader(oldLoader);
+        
+        org.eclipse.jetty.plus.jndi.Resource ds = new org.eclipse.jetty.plus.jndi.Resource (context, "jdbc/mydatasource", new Object());
+        
+        URL webXml = Thread.currentThread().getContextClassLoader().getResource("web.xml");
+        webDescriptor = new WebDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(webXml));
+        webDescriptor.parse();
+        
+        URL frag1Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-1.xml");
+        fragDescriptor1 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag1Xml));
+        fragDescriptor1.parse();
+        URL frag2Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-2.xml");
+        fragDescriptor2 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag2Xml));
+        fragDescriptor2.parse();
+        URL frag3Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-3.xml");
+        fragDescriptor3 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag3Xml));
+        fragDescriptor3.parse();
+    }
+    
+    @After
+    public void tearDown() throws Exception
+    {       
+        ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(context.getClassLoader());
+        Context ic = new InitialContext();
+        Context compCtx =  (Context)ic.lookup ("java:comp");
+        compCtx.destroySubcontext("env");
+        Thread.currentThread().setContextClassLoader(oldLoader);
+    }
+
+    @Test
+    public void testWebXmlResourceDeclarations()
+    throws Exception 
+    { 
+        //if declared in web.xml, fragment declarations ignored
+        ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(context.getClassLoader());
+        try
+        {
+            PlusDescriptorProcessor pdp = new PlusDescriptorProcessor();
+            pdp.process(context, webDescriptor);
+            Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref.jdbc/mydatasource");
+            assertNotNull(d);
+            assertTrue(d == webDescriptor);
+            
+            pdp.process(context, fragDescriptor1);
+            pdp.process(context, fragDescriptor2);
+        }
+        finally
+        {
+            Thread.currentThread().setContextClassLoader(oldLoader);
+        }
+    }
+ 
+    
+    @Test
+    public void testMismatchedFragmentResourceDeclarations ()
+    throws Exception
+    { 
+        //if declared in more than 1 fragment, declarations must be the same
+        ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(context.getClassLoader());
+        try
+        {
+            PlusDescriptorProcessor pdp = new PlusDescriptorProcessor();
+            pdp.process(context, fragDescriptor1);
+            Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref.jdbc/mydatasource");
+            assertNotNull(d);
+            assertTrue(d == fragDescriptor1);
+            assertEquals(Origin.WebFragment, context.getMetaData().getOrigin("resource-ref.jdbc/mydatasource"));
+            
+            pdp.process(context, fragDescriptor2);
+            fail("Expected conflicting resource-ref declaration");
+        }
+        catch (Exception e)
+        {
+            //expected
+        }
+        finally
+        {
+            Thread.currentThread().setContextClassLoader(oldLoader);
+        }
+    }
+    
+    @Test
+    public void testMatchingFragmentResourceDeclarations ()
+    throws Exception
+    {
+        //if declared in more than 1 fragment, declarations must be the same
+        ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(context.getClassLoader());
+        try
+        {
+            PlusDescriptorProcessor pdp = new PlusDescriptorProcessor();
+            pdp.process(context, fragDescriptor1);
+            Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref.jdbc/mydatasource");
+            assertNotNull(d);
+            assertTrue(d == fragDescriptor1);
+            assertEquals(Origin.WebFragment, context.getMetaData().getOrigin("resource-ref.jdbc/mydatasource"));
+            pdp.process(context, fragDescriptor3);
+        }
+       
+        finally
+        {
+            Thread.currentThread().setContextClassLoader(oldLoader);
+        }
+    }
+}
diff --git a/jetty-plus/src/test/resources/web-fragment-1.xml b/jetty-plus/src/test/resources/web-fragment-1.xml
new file mode 100644
index 0000000..b213172
--- /dev/null
+++ b/jetty-plus/src/test/resources/web-fragment-1.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<web-fragment 
+   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-fragment_3_0.xsd" 
+   version="3.0"> 
+
+  <name>Fragment1</name>
+  
+  <ordering>
+    <after>others</after>
+  </ordering>
+
+  <resource-ref>
+    <res-ref-name>jdbc/mydatasource</res-ref-name>
+    <res-type>javax.sql.DataSource</res-type>
+    <res-auth>Container</res-auth>
+<!--
+    <injection-target>
+      <injection-target-class>com.acme.Bar</injection-target-class>
+      <injection-target-name>myDatasource</injection-target-name>
+    </injection-target>
+-->
+  </resource-ref>
+
+</web-fragment>
diff --git a/jetty-plus/src/test/resources/web-fragment-2.xml b/jetty-plus/src/test/resources/web-fragment-2.xml
new file mode 100644
index 0000000..e2fff67
--- /dev/null
+++ b/jetty-plus/src/test/resources/web-fragment-2.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<web-fragment 
+   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-fragment_3_0.xsd" 
+   version="3.0"> 
+
+  <name>Fragment2</name>
+  
+  <ordering>
+    <after>others</after>
+  </ordering>
+
+  <resource-ref>
+    <res-ref-name>jdbc/mydatasource</res-ref-name>
+    <res-type>javax.sql.DataSource</res-type>
+    <res-auth>User</res-auth>
+<!--
+    <injection-target>
+      <injection-target-class>com.acme.Bar</injection-target-class>
+      <injection-target-name>myDatasource</injection-target-name>
+    </injection-target>
+-->
+  </resource-ref>
+
+</web-fragment>
diff --git a/jetty-plus/src/test/resources/web-fragment-3.xml b/jetty-plus/src/test/resources/web-fragment-3.xml
new file mode 100644
index 0000000..da1f3d5
--- /dev/null
+++ b/jetty-plus/src/test/resources/web-fragment-3.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<web-fragment 
+   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-fragment_3_0.xsd" 
+   version="3.0"> 
+
+  <name>Fragment3</name>
+  
+  <ordering>
+    <after>others</after>
+  </ordering>
+
+  <resource-ref>
+    <res-ref-name>jdbc/mydatasource</res-ref-name>
+    <res-type>javax.sql.DataSource</res-type>
+    <res-auth>Container</res-auth>
+<!--
+    <injection-target>
+      <injection-target-class>com.acme.Bar</injection-target-class>
+      <injection-target-name>myDatasource</injection-target-name>
+    </injection-target>
+-->
+  </resource-ref>
+
+</web-fragment>
diff --git a/jetty-plus/src/test/resources/web.xml b/jetty-plus/src/test/resources/web.xml
new file mode 100644
index 0000000..aa40eb3
--- /dev/null
+++ b/jetty-plus/src/test/resources/web.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<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"
+   metadata-complete="false"
+   version="3.0"> 
+
+  <display-name>Test  WebApp</display-name>
+
+  <resource-ref>
+    <res-ref-name>jdbc/mydatasource</res-ref-name>
+    <res-type>javax.sql.DataSource</res-type>
+    <res-auth>Container</res-auth>
+<!--
+    <injection-target>
+      <injection-target-class>com.acme.JNDITest</injection-target-class>
+      <injection-target-name>myDatasource</injection-target-name>
+    </injection-target>
+-->
+  </resource-ref>
+
+</web-app>
diff --git a/jetty-policy/pom.xml b/jetty-policy/pom.xml
index e6ea883..1ab08ec 100644
--- a/jetty-policy/pom.xml
+++ b/jetty-policy/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>jetty-policy</artifactId>
   <name>Jetty :: Policy Tool</name>
diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml
index 332dfd1..f7653f9 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-rewrite</artifactId>
@@ -23,6 +23,11 @@
             <goals>
               <goal>manifest</goal>
             </goals>
+            <configuration>
+              <instructions>
+                <Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
+              </instructions>
+            </configuration>
            </execution>
         </executions>
       </plugin>
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java
index 93cafdc..c9b7cee 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java
@@ -371,7 +371,7 @@
         {
             // TODO could be better than this!
             String hdr = (String)enm.nextElement();
-            String lhdr = hdr.toLowerCase();
+            String lhdr = hdr.toLowerCase(Locale.ENGLISH);
 
             if (_DontProxyHeaders.contains(lhdr))
                 continue;
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 975d67b..6a5c740 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
@@ -26,6 +26,7 @@
 import org.eclipse.jetty.server.AbstractHttpConnection;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.util.LazyList;
+import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
@@ -38,11 +39,13 @@
 
 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;
     
@@ -172,6 +175,7 @@
     public void setOriginalPathAttribute(String originalPathAttribte)
     {
         _originalPathAttribute=originalPathAttribte;
+        _originalQueryStringAttribute = originalPathAttribte + ORIGINAL_QUERYSTRING_ATTRIBUTE_SUFFIX;
     }
     
     /**
@@ -195,18 +199,26 @@
     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)
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java
index fc5b948..4cb3473 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java
@@ -19,7 +19,7 @@
 package org.eclipse.jetty.rewrite.handler;
 
 import java.io.IOException;
-import java.util.Enumeration;
+import java.util.Iterator;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -86,11 +86,11 @@
         };
         assertHeaders(headers);
 
-        Enumeration e = _response.getHeaders("size");
+        Iterator<String> e = _response.getHeaders("size").iterator();
         int count = 0;
-        while (e.hasMoreElements())
+        while (e.hasNext())
         {
-            e.nextElement();
+            e.next();
             count++;
         }
 
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 997b15a..73692dd 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
@@ -108,7 +108,6 @@
 
         assertEquals(200,_response.getStatus());
     }
-
     
     @Test
     public void testCharacters() throws Exception
diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml
index 5454f52..339bcf3 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-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.5,3.0)",javax.security.cert,*</Import-Package>
+                <Import-Package>javax.servlet.*;version="2.6.0",javax.security.cert,*</Import-Package>
               </instructions>
             </configuration>
 
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java
index f922bd6..9b25c06 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java
@@ -23,6 +23,7 @@
 public class ConstraintMapping
 {
     String _method;
+    String[] _methodOmissions;
 
     String _pathSpec;
 
@@ -81,4 +82,19 @@
     {
         this._pathSpec = pathSpec;
     }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param omissions The http-method-omission
+     */
+    public void setMethodOmissions(String[] omissions)
+    {
+        _methodOmissions = omissions;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String[] getMethodOmissions()
+    {
+        return _methodOmissions;
+    }
 }
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 24cdc55..635eb80 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
@@ -19,17 +19,25 @@
 package org.eclipse.jetty.security;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 
 import org.eclipse.jetty.http.HttpSchemes;
+import javax.servlet.HttpConstraintElement;
+import javax.servlet.HttpMethodConstraintElement;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
+import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
+
 import org.eclipse.jetty.http.PathMap;
 import org.eclipse.jetty.server.AbstractHttpConnection;
 import org.eclipse.jetty.server.Connector;
@@ -43,18 +51,226 @@
 /* ------------------------------------------------------------ */
 /**
  * Handler to enforce SecurityConstraints. This implementation is servlet spec
- * 2.4 compliant and precomputes the constraint combinations for runtime
+ * 3.0 compliant and precomputes the constraint combinations for runtime
  * efficiency.
  *
  */
 public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
 {
+    private static final String OMISSION_SUFFIX = ".omission";
+    
     private final List<ConstraintMapping> _constraintMappings= new CopyOnWriteArrayList<ConstraintMapping>();
     private final Set<String> _roles = new CopyOnWriteArraySet<String>();
     private final PathMap _constraintMap = new PathMap();
     private boolean _strict = true;
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @return
+     */
+    public static Constraint createConstraint()
+    {
+        return new Constraint();
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param constraint
+     * @return
+     */
+    public static Constraint createConstraint(Constraint constraint)
+    {
+        try
+        {
+            return (Constraint)constraint.clone();
+        }
+        catch (CloneNotSupportedException e)
+        {
+            throw new IllegalStateException (e);
+        }
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Create a security constraint
+     * 
+     * @param name
+     * @param authenticate
+     * @param roles
+     * @param dataConstraint
+     * @return
+     */
+    public static Constraint createConstraint (String name, boolean authenticate, String[] roles, int dataConstraint)
+    {
+        Constraint constraint = createConstraint();
+        if (name != null)
+            constraint.setName(name);
+        constraint.setAuthenticate(authenticate);
+        constraint.setRoles(roles);
+        constraint.setDataConstraint(dataConstraint);
+        return constraint;
+    }
+    
 
     /* ------------------------------------------------------------ */
+    /**
+     * @param name
+     * @param element
+     * @return
+     */
+    public static Constraint createConstraint (String name, HttpConstraintElement element)
+    {
+        return createConstraint(name, element.getRolesAllowed(), element.getEmptyRoleSemantic(), element.getTransportGuarantee());     
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param name
+     * @param rolesAllowed
+     * @param permitOrDeny
+     * @param transport
+     * @return
+     */
+    public static Constraint createConstraint (String name, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
+    {
+        Constraint constraint = createConstraint();
+        
+        if (rolesAllowed == null || rolesAllowed.length==0)
+        {           
+            if (permitOrDeny.equals(EmptyRoleSemantic.DENY))
+            {
+                //Equivalent to <auth-constraint> with no roles
+                constraint.setName(name+"-Deny");
+                constraint.setAuthenticate(true);
+            }
+            else
+            {
+                //Equivalent to no <auth-constraint>
+                constraint.setName(name+"-Permit");
+                constraint.setAuthenticate(false);
+            }
+        }
+        else
+        {
+            //Equivalent to <auth-constraint> with list of <security-role-name>s
+            constraint.setAuthenticate(true);
+            constraint.setRoles(rolesAllowed);
+            constraint.setName(name+"-RolesAllowed");           
+        } 
+
+        //Equivalent to //<user-data-constraint><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint>
+        constraint.setDataConstraint((transport.equals(TransportGuarantee.CONFIDENTIAL)?Constraint.DC_CONFIDENTIAL:Constraint.DC_NONE));
+        return constraint; 
+    }
+    
+    
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param pathSpec
+     * @param constraintMappings
+     * @return
+     */
+    public static List<ConstraintMapping> getConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
+    {
+        if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
+            return Collections.emptyList();
+        
+        List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
+        for (ConstraintMapping mapping:constraintMappings)
+        {
+            if (pathSpec.equals(mapping.getPathSpec()))
+            {
+               mappings.add(mapping);
+            }
+        }
+        return mappings;
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /** Take out of the constraint mappings those that match the 
+     * given path.
+     * 
+     * @param pathSpec
+     * @param constraintMappings a new list minus the matching constraints
+     * @return
+     */
+    public static List<ConstraintMapping> removeConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
+    {
+        if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
+            return Collections.emptyList();
+        
+        List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
+        for (ConstraintMapping mapping:constraintMappings)
+        {
+            //Remove the matching mappings by only copying in non-matching mappings
+            if (!pathSpec.equals(mapping.getPathSpec()))
+            {
+               mappings.add(mapping);
+            }
+        }
+        return mappings;
+    }
+    
+    
+    
+    /* ------------------------------------------------------------ */
+    /** Generate Constraints and ContraintMappings for the given url pattern and ServletSecurityElement
+     * 
+     * @param name
+     * @param pathSpec
+     * @param securityElement
+     * @return
+     */
+    public static List<ConstraintMapping> createConstraintsWithMappingsForPath (String name, String pathSpec, ServletSecurityElement securityElement)
+    {
+        List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
+
+        //Create a constraint that will describe the default case (ie if not overridden by specific HttpMethodConstraints)
+        Constraint constraint = ConstraintSecurityHandler.createConstraint(name, securityElement);
+
+        //Create a mapping for the pathSpec for the default case
+        ConstraintMapping defaultMapping = new ConstraintMapping();
+        defaultMapping.setPathSpec(pathSpec);
+        defaultMapping.setConstraint(constraint);  
+        mappings.add(defaultMapping);
+
+
+        //See Spec 13.4.1.2 p127
+        List<String> methodOmissions = new ArrayList<String>();
+        
+        //make constraint mappings for this url for each of the HttpMethodConstraintElements
+        Collection<HttpMethodConstraintElement> methodConstraints = securityElement.getHttpMethodConstraints();
+        if (methodConstraints != null)
+        {
+            for (HttpMethodConstraintElement methodConstraint:methodConstraints)
+            {
+                //Make a Constraint that captures the <auth-constraint> and <user-data-constraint> elements supplied for the HttpMethodConstraintElement
+                Constraint mconstraint = ConstraintSecurityHandler.createConstraint(name, methodConstraint);
+                ConstraintMapping mapping = new ConstraintMapping();
+                mapping.setConstraint(mconstraint);
+                mapping.setPathSpec(pathSpec);
+                if (methodConstraint.getMethodName() != null)
+                {
+                    mapping.setMethod(methodConstraint.getMethodName());
+                    //See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
+                    methodOmissions.add(methodConstraint.getMethodName());
+                }
+                mappings.add(mapping);
+            }
+        }
+        //See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
+        if (methodOmissions.size() > 0)
+            defaultMapping.setMethodOmissions(methodOmissions.toArray(new String[methodOmissions.size()]));
+
+        return mappings;
+    }
+    
+    
+    /* ------------------------------------------------------------ */
     /** Get the strict mode.
      * @return true if the security handler is running in strict mode.
      */
@@ -137,8 +353,6 @@
      */
     public void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles)
     {
-        if (isStarted())
-            throw new IllegalStateException("Started");
         _constraintMappings.clear();
         _constraintMappings.addAll(constraintMappings);
 
@@ -157,6 +371,14 @@
             }
         }
         setRoles(roles);
+        
+        if (isStarted())
+        {
+            for (ConstraintMapping mapping : _constraintMappings)
+            {
+                processConstraintMapping(mapping);
+            }
+        }
     }
 
     /* ------------------------------------------------------------ */
@@ -169,9 +391,6 @@
      */
     public void setRoles(Set<String> roles)
     {
-        if (isStarted())
-            throw new IllegalStateException("Started");
-
         _roles.clear();
         _roles.addAll(roles);
     }
@@ -233,7 +452,9 @@
         }
         super.doStart();
     }
-
+    
+    
+    /* ------------------------------------------------------------ */
     @Override
     protected void doStop() throws Exception
     {
@@ -242,7 +463,15 @@
         _roles.clear();
         super.doStop();
     }
-
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Create and combine the constraint with the existing processed
+     * constraints.
+     * 
+     * @param mapping
+     */
     protected void processConstraintMapping(ConstraintMapping mapping)
     {
         Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.get(mapping.getPathSpec());
@@ -254,8 +483,15 @@
         RoleInfo allMethodsRoleInfo = mappings.get(null);
         if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden())
             return;
+       
+        if (mapping.getMethodOmissions() != null && mapping.getMethodOmissions().length > 0)
+        {
+           
+            processConstraintMappingWithMethodOmissions(mapping, mappings);
+            return;
+        }
 
-        String httpMethod = mapping.getMethod();
+        String httpMethod = mapping.getMethod();       
         RoleInfo roleInfo = mappings.get(httpMethod);
         if (roleInfo == null)
         {
@@ -269,10 +505,10 @@
         if (roleInfo.isForbidden())
             return;
 
-        Constraint constraint = mapping.getConstraint();
-        boolean forbidden = constraint.isForbidden();
-        roleInfo.setForbidden(forbidden);
-        if (forbidden)
+        //add in info from the constraint
+        configureRoleInfo(roleInfo, mapping);
+        
+        if (roleInfo.isForbidden())
         {
             if (httpMethod == null)
             {
@@ -282,36 +518,7 @@
         }
         else
         {
-            UserDataConstraint userDataConstraint = UserDataConstraint.get(constraint.getDataConstraint());
-            roleInfo.setUserDataConstraint(userDataConstraint);
-
-            boolean checked = constraint.getAuthenticate();
-            roleInfo.setChecked(checked);
-            if (roleInfo.isChecked())
-            {
-                if (constraint.isAnyRole())
-                {
-                    if (_strict)
-                    {
-                        // * means "all defined roles"
-                        for (String role : _roles)
-                            roleInfo.addRole(role);
-                    }
-                    else
-                        // * means any role
-                        roleInfo.setAnyRole(true);
-                }
-                else
-                {
-                    String[] newRoles = constraint.getRoles();
-                    for (String role : newRoles)
-                    {
-                        if (_strict &&!_roles.contains(role))
-                            throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
-                        roleInfo.addRole(role);
-                    }
-                }
-            }
+            //combine with any entry that covers all methods
             if (httpMethod == null)
             {
                 for (Map.Entry<String, RoleInfo> entry : mappings.entrySet())
@@ -326,6 +533,105 @@
         }
     }
 
+    /* ------------------------------------------------------------ */
+    /** Constraints that name method omissions are dealt with differently.
+     * We create an entry in the mappings with key "method.omission". This entry
+     * is only ever combined with other omissions for the same method to produce a
+     * consolidated RoleInfo. Then, when we wish to find the relevant constraints for
+     *  a given Request (in prepareConstraintInfo()), we consult 3 types of entries in 
+     * 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
+     * method.omission, where the method of the Request is not named in the omission.
+     * @param mapping
+     * @param mappings
+     */
+    protected void processConstraintMappingWithMethodOmissions (ConstraintMapping mapping, Map<String, RoleInfo> mappings)
+    {
+        String[] omissions = mapping.getMethodOmissions();
+
+        for (String omission:omissions)
+        {
+            //for each method omission, see if there is already a RoleInfo for it in mappings
+            RoleInfo ri = mappings.get(omission+OMISSION_SUFFIX);
+            if (ri == null)
+            {
+                //if not, make one
+                ri = new RoleInfo();
+                mappings.put(omission+OMISSION_SUFFIX, ri);
+            }
+
+            //initialize RoleInfo or combine from ConstraintMapping
+            configureRoleInfo(ri, mapping);
+        }
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Initialize or update the RoleInfo from the constraint
+     * @param ri
+     * @param mapping
+     */
+    protected void configureRoleInfo (RoleInfo ri, ConstraintMapping mapping)
+    {
+        Constraint constraint = mapping.getConstraint();
+        boolean forbidden = constraint.isForbidden();
+        ri.setForbidden(forbidden);
+        
+        //set up the data constraint (NOTE: must be done after setForbidden, as it nulls out the data constraint
+        //which we need in order to do combining of omissions in prepareConstraintInfo
+        UserDataConstraint userDataConstraint = UserDataConstraint.get(mapping.getConstraint().getDataConstraint());
+        ri.setUserDataConstraint(userDataConstraint);
+        
+
+        //if forbidden, no point setting up roles
+        if (!ri.isForbidden())
+        {
+            //add in the roles
+            boolean checked = mapping.getConstraint().getAuthenticate();
+            ri.setChecked(checked);
+            if (ri.isChecked())
+            {
+                if (mapping.getConstraint().isAnyRole())
+                {
+                    if (_strict)
+                    {
+                        // * means "all defined roles"
+                        for (String role : _roles)
+                            ri.addRole(role);
+                    }
+                    else
+                        // * means any role
+                        ri.setAnyRole(true);
+                }
+                else
+                {
+                    String[] newRoles = mapping.getConstraint().getRoles();
+                    for (String role : newRoles)
+                    {
+                        if (_strict &&!_roles.contains(role))
+                            throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
+                        ri.addRole(role);
+                    }
+                }
+            }
+        }
+    }
+   
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * Find constraints that apply to the given path.
+     * In order to do this, we consult 3 different types of information stored in the mappings for each path - each mapping
+     * represents a merged set of user data constraints, roles etc -:
+     * <ol>
+     * <li>A mapping of an exact method name </li>
+     * <li>A mapping will null key that matches every method name</li>
+     * <li>Mappings with keys of the form "method.omission" that indicates it will match every method name EXCEPT that given</li>
+     * </ol>
+     * 
+     * @see org.eclipse.jetty.security.SecurityHandler#prepareConstraintInfo(java.lang.String, org.eclipse.jetty.server.Request)
+     */
     protected Object prepareConstraintInfo(String pathInContext, Request request)
     {
         Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext);
@@ -335,13 +641,46 @@
             String httpMethod = request.getMethod();
             RoleInfo roleInfo = mappings.get(httpMethod);
             if (roleInfo == null)
-                roleInfo = mappings.get(null);
+            {
+                //No specific http-method names matched
+                List<RoleInfo> applicableConstraints = new ArrayList<RoleInfo>();
+
+                //Get info for constraint that matches all methods if it exists
+                RoleInfo all = mappings.get(null);
+                if (all != null)
+                    applicableConstraints.add(all);
+          
+                
+                //Get info for constraints that name method omissions where target method name is not omitted
+                //(ie matches because target method is not omitted, hence considered covered by the constraint)
+                for (Entry<String, RoleInfo> entry: mappings.entrySet())
+                {
+                    if (entry.getKey() != null && entry.getKey().contains(OMISSION_SUFFIX) && !(httpMethod+OMISSION_SUFFIX).equals(entry.getKey()))
+                        applicableConstraints.add(entry.getValue());
+                }
+                
+                if (applicableConstraints.size() == 1)
+                    roleInfo = applicableConstraints.get(0);
+                else
+                {
+                    roleInfo = new RoleInfo();
+                    roleInfo.setUserDataConstraint(UserDataConstraint.None);
+                    
+                    for (RoleInfo r:applicableConstraints)
+                        roleInfo.combine(r);
+                }
+
+            }
             return roleInfo;
         }
-
         return null;
     }
-
+    
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * @see org.eclipse.jetty.security.SecurityHandler#checkUserDataPermissions(java.lang.String, org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object)
+     */
     protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException
     {
         if (constraintInfo == null)
@@ -411,7 +750,11 @@
         }
 
     }
-
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * @see org.eclipse.jetty.security.SecurityHandler#isAuthMandatory(org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object)
+     */
     protected boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo)
     {
         if (constraintInfo == null)
@@ -420,7 +763,12 @@
         }
         return ((RoleInfo)constraintInfo).isChecked();
     }
-
+    
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * @see org.eclipse.jetty.security.SecurityHandler#checkWebResourcePermissions(java.lang.String, org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object, org.eclipse.jetty.server.UserIdentity)
+     */
     @Override
     protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo, UserIdentity userIdentity)
             throws IOException
@@ -461,4 +809,5 @@
                 getBeans(),
                 TypeUtil.asList(getHandlers()));
     }
+
 }
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 d649de0..fab701b 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
@@ -335,6 +335,7 @@
         
         if (_identityService==null)
         {
+           
             if (_loginService!=null)
                 _identityService=_loginService.getIdentityService();
 
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java
index eb65bd4..6a14613 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java
@@ -54,6 +54,8 @@
         return Constraint.__BASIC_AUTH;
     }
 
+ 
+
     /* ------------------------------------------------------------ */
     /**
      * @see org.eclipse.jetty.security.Authenticator#validateRequest(javax.servlet.ServletRequest, javax.servlet.ServletResponse, boolean)
@@ -85,10 +87,9 @@
                             String username = credentials.substring(0,i);
                             String password = credentials.substring(i+1);
 
-                            UserIdentity user = _loginService.login(username,password);
+                            UserIdentity user = login (username, password, request);
                             if (user!=null)
                             {
-                                renewSession(request,response);
                                 return new UserAuthentication(getAuthMethod(),user);
                             }
                         }
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 56132ee..c22d190 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
@@ -81,6 +81,8 @@
         return Constraint.__CERT_AUTH;
     }
     
+    
+
     /**
      * @return Authentication for request
      * @throws ServerAuthException
@@ -121,10 +123,9 @@
 
                     final char[] credential = B64Code.encode(cert.getSignature());
 
-                    UserIdentity user = _loginService.login(username,credential);
+                    UserIdentity user = login(username, credential, req);
                     if (user!=null)
                     {
-                        renewSession(request,response);
                         return new UserAuthentication(getAuthMethod(),user);
                     }
                 }
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 de193e8..1197692 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
@@ -21,12 +21,15 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Locale;
 
 import javax.servlet.ServletOutputStream;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.security.Authenticator;
@@ -71,6 +74,7 @@
                 
                 if (identity_service!=null)
                     _previousAssociation=identity_service.associate(((Authentication.User)authentication).getUserIdentity());
+                
                 return authentication;
             }
         }
@@ -78,7 +82,8 @@
         {
             LOG.debug(e);
         }
-        return Authentication.UNAUTHENTICATED;
+
+        return this;
     }
     
     /* ------------------------------------------------------------ */
@@ -101,28 +106,23 @@
         {
             LOG.debug(e);
         }
-        return Authentication.UNAUTHENTICATED;
+        return this;
     }
 
     /* ------------------------------------------------------------ */
     /**
      * @see org.eclipse.jetty.server.Authentication.Deferred#login(java.lang.String, java.lang.String)
      */
-    public Authentication login(String username, String password)
+    public Authentication login(String username, Object password, ServletRequest request)
     {
-        LoginService login_service= _authenticator.getLoginService();
-        IdentityService identity_service=login_service.getIdentityService();
-        
-        if (login_service!=null)
+        UserIdentity identity = _authenticator.login(username, password, request);
+        if (identity != null)
         {
-            UserIdentity user = login_service.login(username,password);
-            if (user!=null)
-            {
-                UserAuthentication authentication = new UserAuthentication("API",user);
-                if (identity_service!=null)
-                    _previousAssociation=identity_service.associate(user);
-                return authentication;
-            }
+            IdentityService identity_service = _authenticator.getLoginService().getIdentityService();
+            UserAuthentication authentication = new UserAuthentication("API",identity);
+            if (identity_service != null)
+                _previousAssociation=identity_service.associate(identity);
+            return authentication;
         }
         return null;
     }
@@ -288,6 +288,29 @@
         {
         }
 
+	public Collection<String> getHeaderNames()
+	{
+	    return Collections.emptyList();
+	}
+
+	@Override
+	public String getHeader(String arg0)
+	{
+	    return null;
+	}
+
+	@Override
+	public Collection<String> getHeaders(String arg0)
+	{
+            return Collections.emptyList();
+	}
+
+	@Override
+	public int getStatus()
+	{
+	    return 0;
+	}
+
     };
 
     /* ------------------------------------------------------------ */
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 d4ee800..bc9e5da 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
@@ -148,6 +148,8 @@
     {
         return true;
     }
+    
+
 
     /* ------------------------------------------------------------ */
     public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
@@ -217,10 +219,10 @@
 
                 if (n > 0)
                 {
-                    UserIdentity user = _loginService.login(digest.username,digest);
+                    //UserIdentity user = _loginService.login(digest.username,digest);
+                    UserIdentity user = login(digest.username, digest, req);
                     if (user!=null)
                     {
-                        renewSession(request,response);
                         return new UserAuthentication(getAuthMethod(),user);
                     }
                 }
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 1b8d555..506f90e 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
@@ -180,6 +180,22 @@
                 _formErrorPath = _formErrorPath.substring(0, _formErrorPath.indexOf('?'));
         }
     }
+    
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public UserIdentity login(String username, Object password, ServletRequest request)
+    {
+        
+        UserIdentity user = super.login(username,password,request);
+        if (user!=null)
+        {
+            HttpSession session = ((HttpServletRequest)request).getSession(true);
+            Authentication cached=new SessionAuthentication(getAuthMethod(),user,password);
+            session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached);
+        }
+        return user;
+    }
 
     /* ------------------------------------------------------------ */
     public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
@@ -207,11 +223,10 @@
                 final String username = request.getParameter(__J_USERNAME);
                 final String password = request.getParameter(__J_PASSWORD);
                 
-                UserIdentity user = _loginService.login(username,password);
+                UserIdentity user = login(username, password, request);
+                session = request.getSession(true);
                 if (user!=null)
-                {
-                    session=renewSession(request,response);
-                    
+                {                    
                     // Redirect to original request
                     String nuri;
                     synchronized(session)
@@ -224,9 +239,6 @@
                             if (nuri.length() == 0) 
                                 nuri = URIUtil.SLASH;
                         }
-
-                        Authentication cached=new SessionAuthentication(getAuthMethod(),user,password);
-                        session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached);
                     }
                     response.setContentLength(0);   
                     response.sendRedirect(response.encodeRedirectURL(nuri));
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 4079831..87ab6af 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
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.security.authentication;
 
+import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
@@ -25,6 +26,8 @@
 import org.eclipse.jetty.security.Authenticator;
 import org.eclipse.jetty.security.IdentityService;
 import org.eclipse.jetty.security.LoginService;
+import org.eclipse.jetty.server.Authentication;
+import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.server.session.AbstractSessionManager;
 
 public abstract class LoginAuthenticator implements Authenticator
@@ -37,6 +40,20 @@
     {
     }
 
+
+    /* ------------------------------------------------------------ */
+    public UserIdentity login(String username, Object password, ServletRequest request)
+    {
+        UserIdentity user = _loginService.login(username,password);
+        if (user!=null)
+        {
+            renewSession((HttpServletRequest)request, null);
+            return user;
+        }
+        return null;
+    }
+
+
     public void setConfiguration(AuthConfiguration configuration)
     {
         _loginService=configuration.getLoginService();
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 49ace10..0edde7d 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
@@ -98,8 +98,8 @@
     {
         if (_session!=null && _session.getAttribute(__J_AUTHENTICATED)!=null)
             _session.removeAttribute(__J_AUTHENTICATED);
-        else 
-            doLogout();
+
+        doLogout();
     }
     
     private void doLogout()
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 1fc20b4..4892b0e 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
@@ -60,6 +60,8 @@
         return _authMethod;
     }
 
+
+
     public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException
     {        
         HttpServletRequest req = (HttpServletRequest)request;
@@ -96,7 +98,7 @@
         {
             String spnegoToken = header.substring(10);
             
-            UserIdentity user = _loginService.login(null,spnegoToken);
+            UserIdentity user = login(null,spnegoToken, request);
             
             if ( user != null )
             {
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 30072ac..e70e931 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
@@ -22,10 +22,12 @@
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.security.MessageDigest;
 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.regex.Matcher;
@@ -83,6 +85,8 @@
         _loginService.putUser("user",new Password("password"));
         _loginService.putUser("user2",new Password("password"), new String[] {"user"});
         _loginService.putUser("admin",new Password("password"), new String[] {"user","administrator"});
+        _loginService.putUser("user3", new Password("password"), new String[] {"foo"});
+        
 
         _context.setContextPath("/ctx");
         _server.setHandler(_context);
@@ -203,6 +207,46 @@
     @Test
     public void testBasic() throws Exception
     {
+        
+        List<ConstraintMapping> list = new ArrayList<ConstraintMapping>(_security.getConstraintMappings());
+        
+        Constraint constraint6 = new Constraint();
+        constraint6.setAuthenticate(true);
+        constraint6.setName("omit POST and GET");
+        constraint6.setRoles(new String[]{"user"});
+        ConstraintMapping mapping6 = new ConstraintMapping();
+        mapping6.setPathSpec("/omit/*");
+        mapping6.setConstraint(constraint6);
+        mapping6.setMethodOmissions(new String[]{"GET", "HEAD"}); //requests for every method except GET and HEAD must be in role "user"
+        list.add(mapping6);
+        
+        Constraint constraint7 = new Constraint();
+        constraint7.setAuthenticate(true);
+        constraint7.setName("non-omitted GET");
+        constraint7.setRoles(new String[]{"administrator"});
+        ConstraintMapping mapping7 = new ConstraintMapping();
+        mapping7.setPathSpec("/omit/*");
+        mapping7.setConstraint(constraint7);
+        mapping7.setMethod("GET"); //requests for GET must be in role "admin"
+        list.add(mapping7);
+        
+        Constraint constraint8 = new Constraint();
+        constraint8.setAuthenticate(true);
+        constraint8.setName("non specific");
+        constraint8.setRoles(new String[]{"foo"});
+        ConstraintMapping mapping8 = new ConstraintMapping();
+        mapping8.setPathSpec("/omit/*");
+        mapping8.setConstraint(constraint8);//requests for all methods must be in role "foo"
+        list.add(mapping8);
+        
+        Set<String> knownRoles=new HashSet<String>();
+        knownRoles.add("user");
+        knownRoles.add("administrator");
+        knownRoles.add("foo");
+
+        _security.setConstraintMappings(list, knownRoles);
+        
+        
         _security.setAuthenticator(new BasicAuthenticator());
         _security.setStrict(false);
         _server.start();
@@ -210,10 +254,10 @@
         String response;
         response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
         assertTrue(response.startsWith("HTTP/1.1 200 OK"));
-
+   
         response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
         assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
-
+        
         response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
         assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
         assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
@@ -228,7 +272,7 @@
                 "Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
                 "\r\n");
         assertTrue(response.startsWith("HTTP/1.1 200 OK"));
-
+        
         // test admin
         response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
         assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
@@ -254,8 +298,32 @@
 
         response = _connector.getResponses("GET /ctx/admin/relax/info HTTP/1.0\r\n\r\n");
         assertTrue(response.startsWith("HTTP/1.1 200 OK"));
+        
+        //check GET is in role administrator 
+        response = _connector.getResponses("GET /ctx/omit/x HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
+                                           "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 200 OK"));
+        
+        //check POST is in role user
+        response = _connector.getResponses("POST /ctx/omit/x HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
+                                           "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 200 OK"));
+        
+        //check POST can be in role foo too      
+        response = _connector.getResponses("POST /ctx/omit/x HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("user3:password") + "\r\n" +
+                                           "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 200 OK"));
+        
+        //check HEAD cannot be in role user
+        response = _connector.getResponses("HEAD /ctx/omit/x HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
+                                           "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 200 OK"));
     }
-
+    
     
     private static String CNONCE="1234567890";
     private String digest(String nonce, String username,String password,String uri,String nc) throws Exception
@@ -1023,7 +1091,7 @@
         public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
         {
             baseRequest.setHandled(true);
-            if (request.getAuthType()==null || "user".equals(request.getRemoteUser()) || request.isUserInRole("user"))
+            if (request.getAuthType()==null || "user".equals(request.getRemoteUser()) || request.isUserInRole("user") || request.isUserInRole("foo"))
             {
                 response.setStatus(200);
                 response.setContentType("text/plain; charset=UTF-8");
diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/SpecExampleConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/SpecExampleConstraintTest.java
new file mode 100644
index 0000000..cee57c5
--- /dev/null
+++ b/jetty-security/src/test/java/org/eclipse/jetty/security/SpecExampleConstraintTest.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.security;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.security.authentication.BasicAuthenticator;
+import org.eclipse.jetty.server.Connector;
+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.server.session.SessionHandler;
+import org.eclipse.jetty.util.B64Code;
+import org.eclipse.jetty.util.security.Constraint;
+import org.eclipse.jetty.util.security.Password;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @version $Revision: 1441 $ $Date: 2010-04-02 12:28:17 +0200 (Fri, 02 Apr 2010) $
+ */
+public class SpecExampleConstraintTest
+{
+    private static final String TEST_REALM = "TestRealm";
+    private static Server _server;
+    private static LocalConnector _connector;
+    private static SessionHandler _session;
+    private ConstraintSecurityHandler _security;
+
+    @BeforeClass
+    public static void startServer()
+    {
+        _server = new Server();
+        _connector = new LocalConnector();
+        _server.setConnectors(new Connector[]{_connector});
+
+        ContextHandler _context = new ContextHandler();
+        _session = new SessionHandler();
+
+        HashLoginService _loginService = new HashLoginService(TEST_REALM);
+        _loginService.putUser("fred",new Password("password"));
+        _loginService.putUser("harry",new Password("password"), new String[] {"HOMEOWNER"});
+        _loginService.putUser("chris",new Password("password"), new String[] {"CONTRACTOR"});
+        _loginService.putUser("steven", new Password("password"), new String[] {"SALESCLERK"});
+        
+
+        _context.setContextPath("/ctx");
+        _server.setHandler(_context);
+        _context.setHandler(_session);
+
+        _server.addBean(_loginService);
+    }
+
+    @Before
+    public void setupSecurity()
+    {
+        _security = new ConstraintSecurityHandler();
+        _session.setHandler(_security);
+        RequestHandler _handler = new RequestHandler();
+        _security.setHandler(_handler);
+
+        
+        /*
+        
+        <security-constraint>
+        <web-resource-collection>
+        <web-resource-name>precluded methods</web-resource-name>
+        <url-pattern>/*</url-pattern>
+        <url-pattern>/acme/wholesale/*</url-pattern>
+        <url-pattern>/acme/retail/*</url-pattern>
+        <http-method-exception>GET</http-method-exception>
+        <http-method-exception>POST</http-method-exception>
+        </web-resource-collection>
+        <auth-constraint/>
+        </security-constraint>
+        */
+        
+        Constraint constraint0 = new Constraint();
+        constraint0.setAuthenticate(true);
+        constraint0.setName("precluded methods");
+        ConstraintMapping mapping0 = new ConstraintMapping();
+        mapping0.setPathSpec("/*");
+        mapping0.setConstraint(constraint0);
+        mapping0.setMethodOmissions(new String[]{"GET", "POST"});
+        
+        ConstraintMapping mapping1 = new ConstraintMapping();
+        mapping1.setPathSpec("/acme/wholesale/*");
+        mapping1.setConstraint(constraint0);
+        mapping1.setMethodOmissions(new String[]{"GET", "POST"});
+        
+        ConstraintMapping mapping2 = new ConstraintMapping();
+        mapping2.setPathSpec("/acme/retail/*");
+        mapping2.setConstraint(constraint0);
+        mapping2.setMethodOmissions(new String[]{"GET", "POST"});
+        
+        /*
+        
+        <security-constraint>
+        <web-resource-collection>
+        <web-resource-name>wholesale</web-resource-name>
+        <url-pattern>/acme/wholesale/*</url-pattern>
+        <http-method>GET</http-method>
+        <http-method>PUT</http-method>
+        </web-resource-collection>
+        <auth-constraint>
+        <role-name>SALESCLERK</role-name>
+        </auth-constraint>
+        </security-constraint>
+        */
+        Constraint constraint1 = new Constraint();
+        constraint1.setAuthenticate(true);
+        constraint1.setName("wholesale");
+        constraint1.setRoles(new String[]{"SALESCLERK"});
+        ConstraintMapping mapping3 = new ConstraintMapping();
+        mapping3.setPathSpec("/acme/wholesale/*");
+        mapping3.setConstraint(constraint1);
+        mapping3.setMethod("GET");
+        ConstraintMapping mapping4 = new ConstraintMapping();
+        mapping4.setPathSpec("/acme/wholesale/*");
+        mapping4.setConstraint(constraint1);
+        mapping4.setMethod("PUT");
+
+        /*
+        <security-constraint>
+          <web-resource-collection>
+            <web-resource-name>wholesale 2</web-resource-name>
+            <url-pattern>/acme/wholesale/*</url-pattern>
+            <http-method>GET</http-method>
+            <http-method>POST</http-method>
+          </web-resource-collection>
+          <auth-constraint>
+            <role-name>CONTRACTOR</role-name>
+          </auth-constraint>
+          <user-data-constraint>
+             <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+          </user-data-constraint>
+        </security-constraint>
+         */
+        Constraint constraint2 = new Constraint();
+        constraint2.setAuthenticate(true);
+        constraint2.setName("wholesale 2");
+        constraint2.setRoles(new String[]{"CONTRACTOR"});
+        constraint2.setDataConstraint(Constraint.DC_CONFIDENTIAL);
+        ConstraintMapping mapping5 = new ConstraintMapping();
+        mapping5.setPathSpec("/acme/wholesale/*");
+        mapping5.setMethod("GET");
+        mapping5.setConstraint(constraint2);
+        ConstraintMapping mapping6 = new ConstraintMapping();
+        mapping6.setPathSpec("/acme/wholesale/*");
+        mapping6.setMethod("POST");
+        mapping6.setConstraint(constraint2);
+        
+        /*
+<security-constraint>
+<web-resource-collection>
+<web-resource-name>retail</web-resource-name>
+<url-pattern>/acme/retail/*</url-pattern>
+<http-method>GET</http-method>
+<http-method>POST</http-method>
+</web-resource-collection>
+<auth-constraint>
+<role-name>CONTRACTOR</role-name>
+<role-name>HOMEOWNER</role-name>
+</auth-constraint>
+</security-constraint>
+*/
+        Constraint constraint4 = new Constraint();
+        constraint4.setName("retail");
+        constraint4.setAuthenticate(true);
+        constraint4.setRoles(new String[]{"CONTRACTOR", "HOMEOWNER"});
+        ConstraintMapping mapping7 = new ConstraintMapping();
+        mapping7.setPathSpec("/acme/retail/*");
+        mapping7.setMethod("GET");
+        mapping7.setConstraint(constraint4);
+        ConstraintMapping mapping8 = new ConstraintMapping();
+        mapping8.setPathSpec("/acme/retail/*");
+        mapping8.setMethod("POST");
+        mapping8.setConstraint(constraint4);
+        
+        
+        
+        
+        Set<String> knownRoles=new HashSet<String>();
+        knownRoles.add("CONTRACTOR");
+        knownRoles.add("HOMEOWNER");
+        knownRoles.add("SALESCLERK");
+        
+        _security.setConstraintMappings(Arrays.asList(new ConstraintMapping[]
+                {
+                        mapping0, mapping1, mapping2, mapping3, mapping4, mapping5, mapping6, mapping7, mapping8
+                }), knownRoles);
+    }
+
+    @After
+    public void stopServer() throws Exception
+    {
+        if (_server.isRunning())
+        {
+            _server.stop();
+            _server.join();
+        }
+    }
+
+  
+
+    @Test
+    public void testBasic() throws Exception
+    {
+        
+        _security.setAuthenticator(new BasicAuthenticator());
+        _security.setStrict(false);
+        _server.start();
+
+        String response;
+        /*
+          /star                 all methods except GET/POST forbidden
+          /acme/wholesale/star  all methods except GET/POST forbidden
+          /acme/retail/star     all methods except GET/POST forbidden
+          /acme/wholesale/star  GET must be in role CONTRACTOR or SALESCLERK
+          /acme/wholesale/star  POST must be in role CONTRACTOR and confidential transport
+          /acme/retail/star     GET must be in role CONTRACTOR or HOMEOWNER
+          /acme/retail/star     POST must be in role CONTRACTOR or HOMEOWNER
+        */
+
+        //a user in role HOMEOWNER is forbidden HEAD request
+        response = _connector.getResponses("HEAD /ctx/index.html HTTP/1.0\r\n\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
+
+        response = _connector.getResponses("HEAD /ctx/index.html HTTP/1.0\r\n" +
+                "Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
+                "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
+
+        response = _connector.getResponses("HEAD /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
+                                           "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
+        
+        response = _connector.getResponses("HEAD /ctx/acme/retail/index.html HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
+                                           "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
+        
+        //a user in role CONTRACTOR can do a GET
+        response = _connector.getResponses("GET /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("chris:password") + "\r\n" +
+                                           "\r\n");
+        
+        assertTrue(response.startsWith("HTTP/1.1 200 OK"));
+        
+        //a user in role CONTRACTOR can only do a post if confidential
+        response = _connector.getResponses("POST /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("chris:password") + "\r\n" +
+                                           "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 403 !Confidential"));
+        
+        
+        //a user in role HOMEOWNER can do a GET
+        response = _connector.getResponses("GET /ctx/acme/retail/index.html HTTP/1.0\r\n" +
+                                           "Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
+                                           "\r\n");
+        assertTrue(response.startsWith("HTTP/1.1 200 OK"));   
+    }
+    
+  
+    private class RequestHandler extends AbstractHandler
+    {
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
+        {
+            baseRequest.setHandled(true);
+
+            response.setStatus(200);
+            response.setContentType("text/plain; charset=UTF-8");
+            response.getWriter().println("URI="+request.getRequestURI());
+            String user = request.getRemoteUser();
+            response.getWriter().println("user="+user);
+            if (request.getParameter("test_parameter")!=null)
+                response.getWriter().println(request.getParameter("test_parameter"));
+        }
+    }
+
+}
diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml
index 6c87eef..cfb9819 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-server</artifactId>
@@ -26,7 +26,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>javax.servlet.*;version="[2.5,3.0)",org.eclipse.jetty.jmx.*;version="[7.3,8)";resolution:=optional,*</Import-Package>
+                <Import-Package>javax.servlet.*;version="2.6.0",org.eclipse.jetty.jmx.*;version="8.0";resolution:=optional,*</Import-Package>
               </instructions>
             </configuration>
           </execution>
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java
index f740180..ccdd878 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java
@@ -18,10 +18,45 @@
 
 package org.eclipse.jetty.server;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.eclipse.jetty.continuation.ContinuationThrowable;
-import org.eclipse.jetty.http.*;
-import org.eclipse.jetty.io.*;
+import org.eclipse.jetty.http.EncodedHttpURI;
+import org.eclipse.jetty.http.Generator;
+import org.eclipse.jetty.http.HttpBuffers;
+import org.eclipse.jetty.http.HttpContent;
+import org.eclipse.jetty.http.HttpException;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpGenerator;
+import org.eclipse.jetty.http.HttpHeaderValues;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.http.HttpParser;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersions;
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.http.Parser;
+import org.eclipse.jetty.http.PathMap;
+import org.eclipse.jetty.io.AbstractConnection;
+import org.eclipse.jetty.io.Buffer;
 import org.eclipse.jetty.io.BufferCache.CachedBuffer;
+import org.eclipse.jetty.io.Buffers;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.EofException;
+import org.eclipse.jetty.io.RuntimeIOException;
+import org.eclipse.jetty.io.UncheckedPrintWriter;
+import org.eclipse.jetty.server.handler.ErrorHandler;
 import org.eclipse.jetty.server.nio.NIOConnector;
 import org.eclipse.jetty.server.ssl.SslConnector;
 import org.eclipse.jetty.util.QuotedStringTokenizer;
@@ -31,13 +66,6 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
 
-import javax.servlet.ServletInputStream;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-
 /**
  * <p>A HttpConnection represents the connection of a HTTP client to the server
  * and is created by an instance of a {@link Connector}. It's prime function is
@@ -401,6 +429,7 @@
         boolean error = false;
 
         String threadName=null;
+        Throwable async_exception=null;
         try
         {
             if (LOG.isDebugEnabled())
@@ -419,6 +448,7 @@
             // within the call to unhandle().
 
             final Server server=_server;
+            boolean was_continuation=_request._async.isContinuation();
             boolean handling=_request._async.handling() && server!=null && server.isRunning();
             while (handling)
             {
@@ -444,7 +474,7 @@
                     info=URIUtil.canonicalPath(path);
                     if (info==null && !_request.getMethod().equals(HttpMethods.CONNECT))
                     {
-                        if (_uri.getScheme()!=null && _uri.getHost()!=null)
+                        if (path==null && _uri.getScheme()!=null && _uri.getHost()!=null)
                         {
                             info="/";
                             _request.setRequestURI("");
@@ -465,7 +495,27 @@
                     }
                     else
                     {
-                        _request.setDispatcherType(DispatcherType.ASYNC);
+                        if (_request._async.isExpired()&&!was_continuation)
+                        {
+                            async_exception = (Throwable)_request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
+                            _response.setStatus(500,async_exception==null?"Async Timeout":"Async Exception");
+                            _request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500));
+                            _request.setAttribute(RequestDispatcher.ERROR_MESSAGE, _response.getReason());
+                            _request.setDispatcherType(DispatcherType.ERROR);
+                            
+                            ErrorHandler eh = _request._async.getContextHandler().getErrorHandler();
+                            if (eh instanceof ErrorHandler.ErrorPageMapper)
+                            {
+                                String error_page=((ErrorHandler.ErrorPageMapper)eh).getErrorPage((HttpServletRequest)_request._async.getRequest());
+                                if (error_page!=null)
+                                { 
+                                    AsyncContinuation.AsyncEventState state = _request._async.getAsyncEventState();
+                                    state.setPath(error_page);
+                                }
+                            }
+                        }
+                        else
+                            _request.setDispatcherType(DispatcherType.ASYNC);
                         server.handleAsync(this);
                     }
                 }
@@ -475,6 +525,7 @@
                 }
                 catch (EofException e)
                 {
+                    async_exception=e;
                     LOG.debug(e);
                     error=true;
                     _request.setHandled(true);
@@ -483,6 +534,7 @@
                 }
                 catch (RuntimeIOException e)
                 {
+                    async_exception=e;
                     LOG.debug(e);
                     error=true;
                     _request.setHandled(true);
@@ -496,13 +548,20 @@
                 }
                 catch (Throwable e)
                 {
+                    async_exception=e;
                     LOG.warn(String.valueOf(_uri),e);
                     error=true;
                     _request.setHandled(true);
                     _generator.sendError(info==null?400:500, null, null, true);
+                    
                 }
                 finally
                 {
+                    // Complete async requests 
+                    if (error && _request.isAsyncStarted())
+                        _request.getAsyncContinuation().errorComplete();
+                        
+                    was_continuation=_request._async.isContinuation();
                     handling = !_request._async.unhandle() && server.isRunning() && _server!=null;
                 }
             }
@@ -514,7 +573,8 @@
 
             if (_request._async.isUncompleted())
             {
-                _request._async.doComplete();
+                
+                _request._async.doComplete(async_exception);
 
                 if (_expect100Continue)
                 {
@@ -844,7 +904,7 @@
             _endp.close();
             return;
         }
-
+        
         _requests++;
         _generator.setVersion(_version);
         switch (_version)
@@ -1138,12 +1198,12 @@
                     if (lml!=-1)
                         _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml);
                 }
-
+                
                 Buffer etag=httpContent.getETag();
                 if (etag!=null)
                     _responseFields.put(HttpHeaders.ETAG_BUFFER,etag);
 
-
+                
                 boolean direct=_connector instanceof NIOConnector && ((NIOConnector)_connector).getUseDirectBuffers() && !(_connector instanceof SslConnector);
                 content = direct?httpContent.getDirectBuffer():httpContent.getIndirectBuffer();
                 if (content==null)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContext.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContext.java
deleted file mode 100644
index 0a10923..0000000
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContext.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.server;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.eclipse.jetty.continuation.ContinuationListener;
-
-/* temporary interface in anticipation of servlet 3.0 */
-public interface AsyncContext 
-{
-    static final String ASYNC_REQUEST_URI = "javax.servlet.async.request_uri";
-    static final String ASYNC_CONTEXT_PATH = "javax.servlet.async.context_path";
-    static final String ASYNC_PATH_INFO = "javax.servlet.async.path_info";
-    static final String ASYNC_SERVLET_PATH = "javax.servlet.async.servlet_path";
-    static final String ASYNC_QUERY_STRING = "javax.servlet.async.query_string";
-
-    public ServletRequest getRequest();
-    public ServletResponse getResponse();
-    public boolean hasOriginalRequestAndResponse();
-    public void dispatch();
-    public void dispatch(String path);
-    public void dispatch(ServletContext context, String path);
-    public void complete();
-    public void start(Runnable run);
-    public void setTimeout(long ms);
-    public void addContinuationListener(ContinuationListener listener);
-}
-
-
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java
index 4605871..2309d95 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java
@@ -18,6 +18,12 @@
 
 package org.eclipse.jetty.server;
 
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -27,8 +33,8 @@
 import javax.servlet.http.HttpServletRequest;
 
 import org.eclipse.jetty.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationListener;
 import org.eclipse.jetty.continuation.ContinuationThrowable;
+import org.eclipse.jetty.continuation.ContinuationListener;
 import org.eclipse.jetty.io.AsyncEndPoint;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.server.handler.ContextHandler;
@@ -39,7 +45,7 @@
 import org.eclipse.jetty.util.thread.Timeout;
 
 /* ------------------------------------------------------------ */
-/** Implementation of Continuation and AsyncContext interfaces.
+/** Implementation of Continuation and AsyncContext interfaces
  * 
  */
 public class AsyncContinuation implements AsyncContext, Continuation
@@ -74,9 +80,10 @@
     private static final int __UNCOMPLETED=8;  // Request is completable
     private static final int __COMPLETED=9;    // Request is complete
     
-
     /* ------------------------------------------------------------ */
     protected AbstractHttpConnection _connection;
+    private List<AsyncListener> _lastAsyncListeners;
+    private List<AsyncListener> _asyncListeners;
     private List<ContinuationListener> _continuationListeners;
 
     /* ------------------------------------------------------------ */
@@ -87,7 +94,8 @@
     private volatile boolean _responseWrapped;
     private long _timeoutMs=DEFAULT_TIMEOUT;
     private AsyncEventState _event;
-    private volatile long _expireAt;
+    private volatile long _expireAt;    
+    private volatile boolean _continuation;
     
     /* ------------------------------------------------------------ */
     protected AsyncContinuation()
@@ -106,6 +114,29 @@
     }
 
     /* ------------------------------------------------------------ */
+    public void addListener(AsyncListener listener)
+    {
+        synchronized(this)
+        {
+            if (_asyncListeners==null)
+                _asyncListeners=new ArrayList<AsyncListener>();
+            _asyncListeners.add(listener);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public void addListener(AsyncListener listener,ServletRequest request, ServletResponse response)
+    {
+        synchronized(this)
+        {
+            // TODO handle the request/response ???
+            if (_asyncListeners==null)
+                _asyncListeners=new ArrayList<AsyncListener>();
+            _asyncListeners.add(listener);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
     public void addContinuationListener(ContinuationListener listener)
     {
         synchronized(this)
@@ -169,6 +200,11 @@
         }
     }
     
+    public boolean isContinuation()
+    {
+        return _continuation;
+    }
+    
     /* ------------------------------------------------------------ */
     /* (non-Javadoc)
      * @see javax.servlet.ServletRequest#isSuspended()
@@ -268,13 +304,22 @@
     {
         synchronized (this)
         {
-            _responseWrapped=false;
+            _continuation=false;
             
             switch(_state)
             {
                 case __IDLE:
                     _initial=true;
                     _state=__DISPATCHED;
+                    if (_lastAsyncListeners!=null)
+                        _lastAsyncListeners.clear();
+                    if (_asyncListeners!=null)
+                        _asyncListeners.clear();
+                    else
+                    {
+                        _asyncListeners=_lastAsyncListeners;
+                        _lastAsyncListeners=null;
+                    }
                     return true;
                     
                 case __COMPLETING:
@@ -311,7 +356,7 @@
                     _resumed=false;
                     _expired=false;
 
-                    if (_event==null || request!=_event.getRequest() || response != _event.getResponse() || context != _event.getServletContext())
+                    if (_event==null || request!=_event.getSuppliedRequest() || response != _event.getSuppliedResponse() || context != _event.getServletContext())
                         _event=new AsyncEventState(context,request,response);
                     else
                     {
@@ -319,12 +364,32 @@
                         _event._pathInContext=null;
                     }
                     _state=__ASYNCSTARTED;
+                    List<AsyncListener> recycle=_lastAsyncListeners;
+                    _lastAsyncListeners=_asyncListeners;
+                    _asyncListeners=recycle;
+                    if (_asyncListeners!=null)
+                        _asyncListeners.clear();
                     break;
 
                 default:
                     throw new IllegalStateException(this.getStatusString());
             }
         }
+        
+        if (_lastAsyncListeners!=null)
+        {
+            for (AsyncListener listener : _lastAsyncListeners)
+            {
+                try
+                {
+                    listener.onStartAsync(_event);
+                }
+                catch(Exception e)
+                {
+                    LOG.warn(e);
+                }
+            }
+        }
     }
 
     /* ------------------------------------------------------------ */
@@ -339,8 +404,6 @@
     {
         synchronized (this)
         {
-            List<ContinuationListener> listeners=_continuationListeners;
-            
             switch(_state)
             {
                 case __REDISPATCHED:
@@ -361,7 +424,7 @@
                     {
                         _state=__UNCOMPLETED;
                         return true;
-                    }
+                    }         
                     _initial=false;
                     _state=__REDISPATCHED;
                     return false; 
@@ -419,27 +482,45 @@
     /* ------------------------------------------------------------ */
     protected void expired()
     {
-        final List<ContinuationListener> listeners;
+        final List<ContinuationListener> cListeners;
+        final List<AsyncListener> aListeners;
         synchronized (this)
         {
             switch(_state)
             {
                 case __ASYNCSTARTED:
                 case __ASYNCWAIT:
-                    listeners=_continuationListeners;
+                    cListeners=_continuationListeners;
+                    aListeners=_asyncListeners;
                     break;
                 default:
-                    listeners=null;
+                    cListeners=null;
+                    aListeners=null;
                     return;
             }
             _expired=true;
         }
         
-        if (listeners!=null)
+        if (aListeners!=null)
         {
-            for (int i=0;i<listeners.size();i++)
+            for (AsyncListener listener : aListeners)
             {
-                ContinuationListener listener=listeners.get(i);
+                try
+                {
+                    listener.onTimeout(_event);
+                }
+                catch(Exception e)
+                {
+                    LOG.debug(e);
+                    _connection.getRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
+                    break;
+                }
+            }
+        }
+        if (cListeners!=null)
+        {
+            for (ContinuationListener listener : cListeners)
+            {
                 try
                 {
                     listener.onTimeout(this);
@@ -458,6 +539,11 @@
                 case __ASYNCSTARTED:
                 case __ASYNCWAIT:
                     dispatch();
+                    break;
+                    
+                default:
+                    if (!_continuation)
+                        _expired=false;
             }
         }
 
@@ -500,37 +586,102 @@
             scheduleDispatch();
         }
     }
-
     
     /* ------------------------------------------------------------ */
     /* (non-Javadoc)
      * @see javax.servlet.ServletRequest#complete()
      */
-    protected void doComplete()
+    public void errorComplete()
     {
-        final List<ContinuationListener> listeners;
+        // just like complete except can overrule a prior dispatch call;
+        synchronized (this)
+        {
+            switch(_state)
+            {
+                case __REDISPATCHING:
+                case __ASYNCSTARTED:
+                    _state=__COMPLETING;
+                    _resumed=false;
+                    return;
+                    
+                case __COMPLETING:
+                    return;
+                    
+                default:
+                    throw new IllegalStateException(this.getStatusString());
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException 
+    {
+        try
+        {
+            // TODO inject
+            return clazz.newInstance();
+        }
+        catch(Exception e)
+        {
+            throw new ServletException(e);
+        }
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /* (non-Javadoc)
+     * @see javax.servlet.ServletRequest#complete()
+     */
+    protected void doComplete(Throwable ex)
+    {
+        final List<ContinuationListener> cListeners;
+        final List<AsyncListener> aListeners;
         synchronized (this)
         {
             switch(_state)
             {
                 case __UNCOMPLETED:
                     _state=__COMPLETED;
-                    listeners=_continuationListeners;
+                    cListeners=_continuationListeners;
+                    aListeners=_asyncListeners;
                     break;
                     
                 default:
-                    listeners=null;
+                    cListeners=null;
+                    aListeners=null;
                     throw new IllegalStateException(this.getStatusString());
             }
         }
         
-        if (listeners!=null)
+        if (aListeners!=null)
         {
-            for(int i=0;i<listeners.size();i++)
+            for (AsyncListener listener : aListeners)
             {
                 try
                 {
-                    listeners.get(i).onComplete(this);
+                    if (ex!=null)
+                    {
+                        _event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,ex);
+                        _event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_MESSAGE,ex.getMessage());
+                        listener.onError(_event);
+                    }
+                    else
+                        listener.onComplete(_event);
+                }
+                catch(Exception e)
+                {
+                    LOG.warn(e);
+                }
+            }
+        }
+        if (cListeners!=null)
+        {
+            for (ContinuationListener listener : cListeners)
+            {
+                try
+                {
+                    listener.onComplete(this);
                 }
                 catch(Exception e)
                 {
@@ -545,7 +696,6 @@
     {
         synchronized (this)
         {
-//            _history.append("r\n");
             switch(_state)
             {
                 case __DISPATCHED:
@@ -617,7 +767,7 @@
             }
             else
             {
-                ((AsyncEndPoint)endp).scheduleTimeout(_event,_timeoutMs);
+                ((AsyncEndPoint)endp).scheduleTimeout(_event._timeout,_timeoutMs);
             }
         }
     }
@@ -639,7 +789,7 @@
             final AsyncEventState event=_event;
             if (event!=null)
             {
-                ((AsyncEndPoint)endp).cancelTimeout(event);
+                ((AsyncEndPoint)endp).cancelTimeout(event._timeout);
             }
         }
     }
@@ -715,14 +865,14 @@
     public void dispatch(ServletContext context, String path)
     {
         _event._dispatchContext=context;
-        _event._pathInContext=path;
+        _event.setPath(path);
         dispatch();
     }
 
     /* ------------------------------------------------------------ */
     public void dispatch(String path)
     {
-        _event._pathInContext=path;
+        _event.setPath(path);
         dispatch();
     }
 
@@ -736,15 +886,15 @@
     public ServletRequest getRequest()
     {
         if (_event!=null)
-            return _event.getRequest();
+            return _event.getSuppliedRequest();
         return _connection.getRequest();
     }
 
     /* ------------------------------------------------------------ */
     public ServletResponse getResponse()
     {
-        if (_event!=null)
-            return _event.getResponse();
+        if (_responseWrapped && _event!=null && _event.getSuppliedResponse()!=null)
+            return _event.getSuppliedResponse();
         return _connection.getResponse();
     }
 
@@ -769,7 +919,7 @@
     {
         synchronized (this)
         {
-            return (_event!=null && _event.getRequest()==_connection._request && _event.getResponse()==_connection._response);
+            return (_event!=null && _event.getSuppliedRequest()==_connection._request && _event.getSuppliedResponse()==_connection._response);
         }
     }
 
@@ -818,7 +968,7 @@
 
 
     /* ------------------------------------------------------------ */
-    protected void suspend(final ServletContext context,
+    protected void startAsync(final ServletContext context,
             final ServletRequest request,
             final ServletResponse response)
     {
@@ -833,6 +983,14 @@
         }
     }
 
+    /* ------------------------------------------------------------ */
+    protected void startAsync()
+    {
+        _responseWrapped=false;
+        _continuation=false;
+        doSuspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());  
+    }
+
     
     /* ------------------------------------------------------------ */
     /**
@@ -840,6 +998,7 @@
      */
     public void suspend(ServletResponse response)
     {
+        _continuation=true;
         _responseWrapped=!(response instanceof Response);
         doSuspend(_connection.getRequest().getServletContext(),_connection.getRequest(),response); 
     }
@@ -851,6 +1010,7 @@
     public void suspend()
     {
         _responseWrapped=false;
+        _continuation=true;
         doSuspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());       
     }
 
@@ -860,8 +1020,8 @@
      */
     public ServletResponse getServletResponse()
     {
-        if (_responseWrapped && _event!=null && _event.getResponse()!=null)
-            return _event.getResponse();
+        if (_responseWrapped && _event!=null && _event.getSuppliedResponse()!=null)
+            return _event.getSuppliedResponse();
         return _connection.getResponse();
     }
 
@@ -910,21 +1070,34 @@
 
     /* ------------------------------------------------------------ */
     /* ------------------------------------------------------------ */
-    public class AsyncEventState extends Timeout.Task implements Runnable
+    public class AsyncTimeout extends Timeout.Task implements Runnable
+    {
+            @Override
+            public void expired()
+            {
+                AsyncContinuation.this.expired();
+            }
+
+            @Override
+            public void run()
+            {
+                AsyncContinuation.this.expired();
+            }
+    }
+
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    public class AsyncEventState extends AsyncEvent
     {
         private final ServletContext _suspendedContext;
-        private final ServletRequest _request;
-        private final ServletResponse _response;
         private ServletContext _dispatchContext;
         private String _pathInContext;
+        private Timeout.Task _timeout=  new AsyncTimeout();
         
         public AsyncEventState(ServletContext context, ServletRequest request, ServletResponse response)
         {
+            super(AsyncContinuation.this, request,response);
             _suspendedContext=context;
-            _request=request;
-            _response=response;
-            
-            
             // Get the base request So we can remember the initial paths
             Request r=_connection.getRequest();
  
@@ -935,14 +1108,14 @@
                 // they are only available after a call to AsyncContext.dispatch(...);
                 
                 // have we been forwarded before?
-                String uri=(String)r.getAttribute(Dispatcher.FORWARD_REQUEST_URI);
+                String uri=(String)r.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
                 if (uri!=null)
                 {
                     r.setAttribute(AsyncContext.ASYNC_REQUEST_URI,uri);
-                    r.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,r.getAttribute(Dispatcher.FORWARD_CONTEXT_PATH));
-                    r.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,r.getAttribute(Dispatcher.FORWARD_SERVLET_PATH));
-                    r.setAttribute(AsyncContext.ASYNC_PATH_INFO,r.getAttribute(Dispatcher.FORWARD_PATH_INFO));
-                    r.setAttribute(AsyncContext.ASYNC_QUERY_STRING,r.getAttribute(Dispatcher.FORWARD_QUERY_STRING));
+                    r.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,r.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
+                    r.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,r.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
+                    r.setAttribute(AsyncContext.ASYNC_PATH_INFO,r.getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
+                    r.setAttribute(AsyncContext.ASYNC_QUERY_STRING,r.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
                 }
                 else
                 {
@@ -969,15 +1142,10 @@
         {
             return _dispatchContext==null?_suspendedContext:_dispatchContext;
         }
-
-        public ServletRequest getRequest()
+        
+        public void setPath(String path)
         {
-            return _request;
-        }
-
-        public ServletResponse getResponse()
-        {
-            return _response;
+            _pathInContext=path;
         }
         
         /* ------------------------------------------------------------ */
@@ -988,16 +1156,5 @@
         {
             return _pathInContext;
         }
-
-        @Override
-        public void expired()
-        {
-            AsyncContinuation.this.expired();
-        }
-        
-        public void run()
-        {
-            AsyncContinuation.this.expired();  
-        }
     }
 }
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 56180ca..92df613 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
@@ -85,7 +85,7 @@
          * @param password
          * @return The new Authentication state
          */
-        Authentication login(String username,String password);
+        Authentication login(String username,Object password,ServletRequest request);
     }
 
     
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 50fff2c..fc6a4da 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
@@ -25,6 +25,7 @@
 import java.util.Iterator;
 import java.util.Map;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
@@ -45,24 +46,6 @@
  */
 public class Dispatcher implements RequestDispatcher
 {
-    public static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
-    public static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
-    public static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
-    public static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
-    public static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
-    public static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
-    public static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
-    public static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
-    public static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
-    public static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";
-
-    public static final String ERROR_EXCEPTION = "javax.servlet.error.exception";
-    public static final String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type";
-    public static final String ERROR_MESSAGE = "javax.servlet.error.message";
-    public static final String ERROR_REQUEST_URI = "javax.servlet.error.request_uri";
-    public static final String ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name";
-    public static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code";
-
     /** Dispatch include attribute names */
     public final static String __INCLUDE_PREFIX="javax.servlet.include.";
 
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/DispatcherType.java b/jetty-server/src/main/java/org/eclipse/jetty/server/DispatcherType.java
deleted file mode 100644
index a1f0162..0000000
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/DispatcherType.java
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      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;
-
-public enum DispatcherType 
-{
-    FORWARD,
-    INCLUDE,
-    REQUEST,
-    ASYNC,
-    ERROR
-}
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 d2ae982..f097c59 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
@@ -19,6 +19,8 @@
 package org.eclipse.jetty.server;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -37,16 +39,25 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
+import javax.servlet.MultipartConfigElement;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletRequestAttributeEvent;
 import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
 
 import org.eclipse.jetty.continuation.Continuation;
 import org.eclipse.jetty.continuation.ContinuationListener;
@@ -61,6 +72,7 @@
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.io.Buffer;
 import org.eclipse.jetty.io.BufferUtil;
+import org.eclipse.jetty.io.ByteArrayBuffer;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.io.nio.DirectNIOBuffer;
 import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
@@ -69,8 +81,11 @@
 import org.eclipse.jetty.server.handler.ContextHandler.Context;
 import org.eclipse.jetty.util.Attributes;
 import org.eclipse.jetty.util.AttributesMap;
+import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.LazyList;
+import org.eclipse.jetty.util.MultiException;
 import org.eclipse.jetty.util.MultiMap;
+import org.eclipse.jetty.util.MultiPartInputStream;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.UrlEncoded;
@@ -111,12 +126,51 @@
  */
 public class Request implements HttpServletRequest
 {
+    public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.multipartConfig";
+    public static final String __MULTIPART_INPUT_STREAM = "org.eclipse.multiPartInputStream";
+    public static final String __MULTIPART_CONTEXT = "org.eclipse.multiPartContext";
     private static final Logger LOG = Log.getLogger(Request.class);
 
     private static final String __ASYNC_FWD = "org.eclipse.asyncfwd";
     private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault());
     private static final int __NONE = 0, _STREAM = 1, __READER = 2;
 
+    public static class MultiPartCleanerListener implements ServletRequestListener
+    {
+
+        @Override
+        public void requestDestroyed(ServletRequestEvent sre)
+        {
+            //Clean up any tmp files created by MultiPartInputStream
+            MultiPartInputStream mpis = (MultiPartInputStream)sre.getServletRequest().getAttribute(__MULTIPART_INPUT_STREAM);
+            if (mpis != null)
+            {
+                ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(__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()
+        }
+        
+    }
+    
+    
     /* ------------------------------------------------------------ */
     public static Request getRequest(HttpServletRequest request)
     {
@@ -170,7 +224,9 @@
 
     private Buffer _timeStampBuffer;
     private HttpURI _uri;
-
+    
+    private MultiPartInputStream _multiPartInputStream; //if the request is a multi-part mime
+    
     /* ------------------------------------------------------------ */
     public Request()
     {
@@ -188,7 +244,9 @@
         if (listener instanceof ServletRequestAttributeListener)
             _requestAttributeListeners = LazyList.add(_requestAttributeListeners,listener);
         if (listener instanceof ContinuationListener)
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException(listener.getClass().toString());
+        if (listener instanceof AsyncListener)
+            throw new IllegalArgumentException(listener.getClass().toString());
     }
 
     /* ------------------------------------------------------------ */
@@ -306,6 +364,7 @@
                         }
                     }
                 }
+              
             }
 
             if (_parameters == null)
@@ -323,6 +382,28 @@
                         _parameters.add(name,LazyList.get(values,i));
                 }
             }
+
+            if (content_type != null && content_type.length()>0 && content_type.startsWith("multipart/form-data") && getAttribute(__MULTIPART_CONFIG_ELEMENT)!=null)
+            {
+                try
+                {
+                    getParts();
+                }
+                catch (IOException e)
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.warn(e);
+                    else
+                        LOG.warn(e.toString());
+                }
+                catch (ServletException e)
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.warn(e);
+                    else
+                        LOG.warn(e.toString());
+                }
+            }
         }
         finally
         {
@@ -345,7 +426,7 @@
     {
         return _async;
     }
-
+    
     /* ------------------------------------------------------------ */
     /*
      * @see javax.servlet.ServletRequest#getAttribute(java.lang.String)
@@ -401,8 +482,8 @@
     public String getAuthType()
     {
         if (_authentication instanceof Authentication.Deferred)
-            _authentication = ((Authentication.Deferred)_authentication).authenticate(this);
-
+            setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
+        
         if (_authentication instanceof Authentication.User)
             return ((Authentication.User)_authentication).getAuthMethod();
         return null;
@@ -905,6 +986,8 @@
      */
     public RequestDispatcher getRequestDispatcher(String path)
     {
+        path = URIUtil.compactPath(path);
+
         if (path == null || _context == null)
             return null;
 
@@ -1279,6 +1362,7 @@
             UserIdentity user = ((Authentication.User)_authentication).getUserIdentity();
             return user.getUserPrincipal();
         }
+        
         return null;
     }
 
@@ -1299,6 +1383,12 @@
         return _handled;
     }
 
+    public boolean isAsyncStarted()
+    {
+       return _async.isAsyncStarted();
+    }
+
+
     /* ------------------------------------------------------------ */
     public boolean isAsyncSupported()
     {
@@ -1434,7 +1524,8 @@
 
         if (_savedNewSessions != null)
             _savedNewSessions.clear();
-        _savedNewSessions = null;
+        _savedNewSessions=null;
+        _multiPartInputStream = null;
     }
 
     /* ------------------------------------------------------------ */
@@ -1915,7 +2006,7 @@
     {
         if (!_asyncSupported)
             throw new IllegalStateException("!asyncSupported");
-        _async.suspend();
+        _async.startAsync();
         return _async;
     }
 
@@ -1924,7 +2015,7 @@
     {
         if (!_asyncSupported)
             throw new IllegalStateException("!asyncSupported");
-        _async.suspend(_context,servletRequest,servletResponse);
+        _async.startAsync(_context,servletRequest,servletResponse);
         return _async;
     }
 
@@ -1936,6 +2027,103 @@
     }
 
     /* ------------------------------------------------------------ */
+    public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
+    {
+        if (_authentication instanceof Authentication.Deferred)
+        {
+            setAuthentication(((Authentication.Deferred)_authentication).authenticate(this,response));
+            return !(_authentication instanceof Authentication.ResponseSent);        
+        }
+        response.sendError(HttpStatus.UNAUTHORIZED_401);
+        return false;
+    }
+
+    /* ------------------------------------------------------------ */
+    public Part getPart(String name) throws IOException, ServletException
+    {                
+        getParts();
+        return _multiPartInputStream.getPart(name);
+    }
+
+    /* ------------------------------------------------------------ */
+    public Collection<Part> getParts() throws IOException, ServletException
+    {
+        if (getContentType() == null || !getContentType().startsWith("multipart/form-data"))
+            throw new ServletException("Content-Type != multipart/form-data");
+        
+        if (_multiPartInputStream == null)
+            _multiPartInputStream = (MultiPartInputStream)getAttribute(__MULTIPART_INPUT_STREAM);
+        
+        if (_multiPartInputStream == null)
+        {
+            MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
+            
+            if (config == null)
+                throw new IllegalStateException("No multipart config for servlet");
+            
+            _multiPartInputStream = new MultiPartInputStream(getInputStream(), 
+                                                             getContentType(), config, 
+                                                             (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
+            
+            setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream);
+            setAttribute(__MULTIPART_CONTEXT, _context);
+            Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing 
+            for (Part p:parts)
+            {
+                MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p;
+                if (mp.getContentDispositionFilename() == null)
+                {
+                    //Servlet Spec 3.0 pg 23, parts without filenames must be put into init params
+                    String charset = null;
+                    if (mp.getContentType() != null)
+                        charset = MimeTypes.getCharsetFromContentType(new ByteArrayBuffer(mp.getContentType()));
+
+                    ByteArrayOutputStream os = null;
+                    InputStream is = mp.getInputStream(); //get the bytes regardless of being in memory or in temp file
+                    try
+                    {
+                        os = new ByteArrayOutputStream();
+                        IO.copy(is, os);
+                        String content=new String(os.toByteArray(),charset==null?StringUtil.__UTF8:charset);   
+                        getParameter(""); //cause params to be evaluated
+                        getParameters().add(mp.getName(), content);
+                    }
+                    finally
+                    {
+                        IO.close(os);
+                        IO.close(is);
+                    }
+                }
+            }
+        }
+
+        return _multiPartInputStream.getParts();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void login(String username, String password) throws ServletException
+    {
+        if (_authentication instanceof Authentication.Deferred) 
+        {
+            _authentication=((Authentication.Deferred)_authentication).login(username,password,this);
+            if (_authentication == null)
+                throw new ServletException();
+        } 
+        else 
+        {
+            throw new ServletException("Authenticated as "+_authentication);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public void logout() throws ServletException
+    {
+        if (_authentication instanceof Authentication.User)
+            ((Authentication.User)_authentication).logout();
+        _authentication=Authentication.UNAUTHENTICATED;
+    }
+    
+    /* ------------------------------------------------------------ */
     /**
      * Merge in a new query string. The query string is merged with the existing parameters and {@link #setParameters(MultiMap)} and
      * {@link #setQueryString(String)} are called with the result. The merge is according to the rules of the servlet dispatch forward method.
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 936f4b0..161d051 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
@@ -20,11 +20,13 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Collection;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Locale;
 
+import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletResponse;
@@ -58,7 +60,7 @@
 public class Response implements HttpServletResponse
 {
     private static final Logger LOG = Log.getLogger(Response.class);
-
+    private final static int __MIN_BUFFER_SIZE = 1;
     
     public static final int
         NONE=0,
@@ -164,7 +166,7 @@
                 cookie.getMaxAge(),
                 comment,
                 cookie.getSecure(),
-                http_only,// || cookie.isHttpOnly(),
+                http_only || cookie.isHttpOnly(),
                 cookie.getVersion());
     }
 
@@ -211,7 +213,7 @@
             return null;
         
         // should not encode if cookies in evidence
-        if (request.isRequestedSessionIdFromCookie())
+        if ((sessionManager.isUsingCookies() && request.isRequestedSessionIdFromCookie()) || !sessionManager.isUsingURLs()) 
         {
             int prefix=url.indexOf(sessionURLPrefix);
             if (prefix!=-1)
@@ -340,10 +342,10 @@
                 error_handler = _connection.getConnector().getServer().getBean(ErrorHandler.class);
             if (error_handler!=null)
             {
-                request.setAttribute(Dispatcher.ERROR_STATUS_CODE,new Integer(code));
-                request.setAttribute(Dispatcher.ERROR_MESSAGE, message);
-                request.setAttribute(Dispatcher.ERROR_REQUEST_URI, request.getRequestURI());
-                request.setAttribute(Dispatcher.ERROR_SERVLET_NAME,request.getServletName());
+                request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(code));
+                request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
+                request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
+                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,request.getServletName());
                 error_handler.handle(null,_connection.getRequest(),_connection.getRequest(),this );
             }
             else
@@ -379,7 +381,14 @@
                 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");
+                
+                if(_connection.getServer().getSendServerVersion()) 
+                {
+                    writer.write("<hr /><i><small>Powered by Jetty:// ");
+                    writer.write(Server.getVersion());
+                    writer.write("</small></i>");
+                }
 
                 for (int i= 0; i < 20; i++)
                     writer.write("\n                                                ");
@@ -409,10 +418,18 @@
      */
     public void sendError(int sc) throws IOException
     {
-        if (sc==102)
-            sendProcessing();
-        else
-            sendError(sc,null);
+        switch (sc)
+        {
+            case -1:
+                _connection.getEndPoint().close();
+                break;
+            case 102:
+                sendProcessing();
+                break;
+            default:
+                sendError(sc,null);
+                break;
+        }
     }
 
     /* ------------------------------------------------------------ */
@@ -445,49 +462,25 @@
         {
             StringBuilder buf = _connection.getRequest().getRootURL();
             if (location.startsWith("/"))
-                buf.append(location);
+            {
+            	// absolute in context
+                location=URIUtil.canonicalPath(location);
+            }
             else
             {
+            	// relative to request
                 String path=_connection.getRequest().getRequestURI();
                 String parent=(path.endsWith("/"))?path:URIUtil.parentPath(path);
-                location=URIUtil.addPaths(parent,location);
-                if(location==null)
-                    throw new IllegalStateException("path cannot be above root");
+                location=URIUtil.canonicalPath(URIUtil.addPaths(parent,location));
                 if (!location.startsWith("/"))
                     buf.append('/');
-                buf.append(location);
             }
-
+            
+            if(location==null)
+                throw new IllegalStateException("path cannot be above root");
+            buf.append(location);
+            
             location=buf.toString();
-            HttpURI uri = new HttpURI(location);
-            String path=uri.getDecodedPath();
-            String canonical=URIUtil.canonicalPath(path);
-            if (canonical==null)
-                throw new IllegalArgumentException();
-            if (!canonical.equals(path))
-            {
-                buf = _connection.getRequest().getRootURL();
-                buf.append(URIUtil.encodePath(canonical));
-                String param=uri.getParam();
-                if (param!=null)
-                {
-                    buf.append(';');
-                    buf.append(param);
-                }
-                String query=uri.getQuery();
-                if (query!=null)
-                {
-                    buf.append('?');
-                    buf.append(query);
-                }
-                String fragment=uri.getFragment();
-                if (fragment!=null)
-                {
-                    buf.append('#');
-                    buf.append(fragment);
-                }
-                location=buf.toString();
-            }
         }
         
         resetBuffer();
@@ -545,6 +538,14 @@
         }
     }
 
+
+    /* ------------------------------------------------------------ */
+    public Collection<String> getHeaderNames()
+    {
+        final HttpFields fields=_connection.getResponseFields();
+        return fields.getFieldNamesCollection();
+    }
+    
     /* ------------------------------------------------------------ */
     /*
      */
@@ -556,12 +557,13 @@
     /* ------------------------------------------------------------ */
     /*
      */
-    public Enumeration getHeaders(String name)
+    public Collection<String> getHeaders(String name)
     {
-        Enumeration e = _connection.getResponseFields().getValues(name);
-        if (e==null)
-            return Collections.enumeration(Collections.EMPTY_LIST);
-        return e;
+        final HttpFields fields=_connection.getResponseFields();
+        Collection<String> i = fields.getValuesCollection(name);
+        if (i==null)
+            return Collections.EMPTY_LIST;
+        return i;
     }
 
     /* ------------------------------------------------------------ */
@@ -1032,6 +1034,8 @@
     {
         if (isCommitted() || getContentCount()>0)
             throw new IllegalStateException("Committed or content written");
+        if (size <= 0)
+            size = __MIN_BUFFER_SIZE;
         _connection.getGenerator().increaseContentBufferSize(size);
     }
 
@@ -1106,7 +1110,7 @@
             HttpFields response_fields=_connection.getResponseFields();
 
             ArrayList<String> cookieValues = new ArrayList<String>(5);
-            Enumeration vals = response_fields.getValues(HttpHeaders.SET_COOKIE);
+            Enumeration<String> vals = response_fields.getValues(HttpHeaders.SET_COOKIE);
             while (vals.hasMoreElements())
                 cookieValues.add((String)vals.nextElement());
 
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 eb87512..e8be712 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
@@ -22,6 +22,7 @@
 import java.net.InetSocketAddress;
 import java.util.Enumeration;
 
+import javax.servlet.AsyncContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -66,7 +67,7 @@
              Server.class.getPackage().getImplementationVersion()!=null)
             __version=Server.class.getPackage().getImplementationVersion();
         else
-            __version=System.getProperty("jetty.version","7.x.y-SNAPSHOT");
+            __version=System.getProperty("jetty.version","8.y.z-SNAPSHOT");
     }
 
     private final Container _container=new Container();
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java
index 7bcd17a..cd6dce0 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java
@@ -19,14 +19,19 @@
 
 package org.eclipse.jetty.server;
 
+import java.io.IOException;
 import java.security.Principal;
+import java.util.Collection;
 import java.util.Enumeration;
 
+import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletRequestWrapper;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
 
 /* ------------------------------------------------------------ */
 /** Class to tunnel a ServletRequest via a HttpServletRequest
@@ -163,5 +168,45 @@
         return false;
     }
 
+    /** 
+     * @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse)
+     */
+    public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
+    {
+        return false;
+    }
+
+    /** 
+     * @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String)
+     */
+    public Part getPart(String name) throws IOException, ServletException
+    {
+        return null;
+    }
+
+    /** 
+     * @see javax.servlet.http.HttpServletRequest#getParts()
+     */
+    public Collection<Part> getParts() throws IOException, ServletException
+    {
+        return null;
+    }
+
+    /** 
+     * @see javax.servlet.http.HttpServletRequest#login(java.lang.String, java.lang.String)
+     */
+    public void login(String username, String password) throws ServletException
+    {
+
+    }
+
+    /** 
+     * @see javax.servlet.http.HttpServletRequest#logout()
+     */
+    public void logout() throws ServletException
+    {
+        
+    }
+
     
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java
index 7d5c37f..1748f36 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.server;
 
 import java.io.IOException;
+import java.util.Collection;
 
 import javax.servlet.ServletResponse;
 import javax.servlet.ServletResponseWrapper;
@@ -109,4 +110,36 @@
     {        
     }
 
+    /** 
+     * @see javax.servlet.http.HttpServletResponse#getHeader(java.lang.String)
+     */
+    public String getHeader(String name)
+    {
+        return null;
+    }
+
+    /** 
+     * @see javax.servlet.http.HttpServletResponse#getHeaderNames()
+     */
+    public Collection<String> getHeaderNames()
+    {
+        return null;
+    }
+
+    /** 
+     * @see javax.servlet.http.HttpServletResponse#getHeaders(java.lang.String)
+     */
+    public Collection<String> getHeaders(String name)
+    {
+        return null;
+    }
+
+    /** 
+     * @see javax.servlet.http.HttpServletResponse#getStatus()
+     */
+    public int getStatus()
+    {
+        return 0;
+    }
+
 }
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 1ccd468..b4f042e 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
@@ -19,7 +19,10 @@
 package org.eclipse.jetty.server;
 
 import java.util.EventListener;
+import java.util.Set;
 
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
@@ -109,11 +112,6 @@
      */
     public HttpSession newHttpSession(HttpServletRequest request);
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @return true if session cookies should be secure
-     */
-    public boolean getSecureCookies();
 
     /* ------------------------------------------------------------ */
     /**
@@ -258,19 +256,6 @@
     public void complete(HttpSession session);
 
     /**
-     * Sets the session cookie name.
-     * @param cookieName the session cookie name
-     * @see #getSessionCookie()
-     */
-    public void setSessionCookie(String cookieName);
-
-    /**
-     * @return the session cookie name, by default "JSESSIONID".
-     * @see #setSessionCookie(String)
-     */
-    public String getSessionCookie();
-
-    /**
      * Sets the session id URL path parameter name.
      *
      * @param parameterName the URL path parameter name for session id URL rewriting (null or "none" for no rewriting).
@@ -293,50 +278,24 @@
     public String getSessionIdPathParameterNamePrefix();
 
     /**
-     * Sets the domain to set on the session cookie
-     * @param domain the domain to set on the session cookie
-     * @see #getSessionDomain()
-     */
-    public void setSessionDomain(String domain);
-
-    /**
-     * @return the domain to set on the session cookie
-     * @see #setSessionDomain(String)
-     */
-    public String getSessionDomain();
-
-    /**
-     * Sets the path to set on the session cookie
-     * @param path the path to set on the session cookie
-     * @see #getSessionPath()
-     */
-    public void setSessionPath(String path);
-
-    /**
-     * @return the path to set on the session cookie
-     * @see #setSessionPath(String)
-     */
-    public String getSessionPath();
-
-    /**
-     * Sets the max age to set on the session cookie, in seconds
-     * @param maxCookieAge the max age to set on the session cookie, in seconds
-     * @see #getMaxCookieAge()
-     */
-    public void setMaxCookieAge(int maxCookieAge);
-
-    /**
-     * @return the max age to set on the session cookie, in seconds
-     * @see #setMaxCookieAge(int)
-     */
-    public int getMaxCookieAge();
-
-    /**
      * @return whether the session management is handled via cookies.
      */
     public boolean isUsingCookies();
     
     /**
+     * @return whether the session management is handled via URLs.
+     */
+    public boolean isUsingURLs();
+
+    public Set<SessionTrackingMode> getDefaultSessionTrackingModes();
+
+    public Set<SessionTrackingMode> getEffectiveSessionTrackingModes();
+
+    public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes);
+
+    public SessionCookieConfig getSessionCookieConfig();
+    
+    /**
      * @return True if absolute URLs are check for remoteness before being session encoded.
      */
     public boolean isCheckingRemoteSessionIdEncoding();
@@ -345,5 +304,4 @@
      * @param remote True if absolute URLs are check for remoteness before being session encoded.
      */
     public void setCheckingRemoteSessionIdEncoding(boolean remote);
-
 }
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 d235969..fd3874f 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
@@ -24,6 +24,7 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.security.AccessController;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -38,6 +39,7 @@
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.Servlet;
 import javax.servlet.ServletContext;
@@ -46,9 +48,16 @@
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
 import javax.servlet.ServletRequestAttributeListener;
 import javax.servlet.ServletRequestEvent;
 import javax.servlet.ServletRequestListener;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
+import javax.servlet.FilterRegistration.Dynamic;
+import javax.servlet.descriptor.JspConfigDescriptor;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -57,7 +66,6 @@
 import org.eclipse.jetty.io.Buffer;
 import org.eclipse.jetty.server.AbstractHttpConnection;
 import org.eclipse.jetty.server.Dispatcher;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HandlerContainer;
 import org.eclipse.jetty.server.Request;
@@ -141,6 +149,7 @@
     private Object _contextAttributeListeners;
     private Object _requestListeners;
     private Object _requestAttributeListeners;
+    private Object _durableListeners;
     private Map<String, Object> _managedAttributes;
     private String[] _protectedTargets;
     private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>();
@@ -583,8 +592,27 @@
      */
     public void addEventListener(EventListener listener)
     {
+        //Only listeners added before the context starts last through a stop/start cycle
+        if (!(isStarted() || isStarting()))
+            _durableListeners = LazyList.add(_durableListeners, listener);
+        
         setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(),listener,EventListener.class));
     }
+    
+   
+    /**
+     * Apply any necessary restrictions on a programmatically added
+     * listener.
+     * 
+     * Superclasses should implement.
+     * 
+     * @param listener
+     */
+    public void restrictEventListener (EventListener listener)
+    {
+    }
+
+    
 
     /* ------------------------------------------------------------ */
     /**
@@ -743,14 +771,24 @@
             ServletContextEvent event = new ServletContextEvent(_scontext);
             for (int i = 0; i < LazyList.size(_contextListeners); i++)
             {
-                ((ServletContextListener)LazyList.get(_contextListeners,i)).contextInitialized(event);
+                callContextInitialized(((ServletContextListener)LazyList.get(_contextListeners, i)), event);
             }
         }
-
-        LOG.info("started {}",this);
     }
 
     /* ------------------------------------------------------------ */
+    public void callContextInitialized (ServletContextListener l, ServletContextEvent e)
+    {
+        l.contextInitialized(e);
+    }
+
+    /* ------------------------------------------------------------ */
+    public void callContextDestroyed (ServletContextListener l, ServletContextEvent e)
+    {
+        l.contextDestroyed(e);
+    }
+    
+    /* ------------------------------------------------------------ */
     /*
      * @see org.eclipse.thread.AbstractLifeCycle#doStop()
      */
@@ -785,6 +823,10 @@
                     ((ServletContextListener)LazyList.get(_contextListeners,i)).contextDestroyed(event);
                 }
             }
+            
+            //remove all non-durable listeners
+            setEventListeners((EventListener[])LazyList.toArray(_durableListeners, EventListener.class));
+            _durableListeners = null;
 
             if (_errorHandler != null)
                 _errorHandler.stop();
@@ -915,7 +957,7 @@
         if (old_context != _scontext)
         {
             // check the target.
-            if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch))
+            if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch) || (DispatcherType.ERROR.equals(dispatch) && baseRequest.getAsyncContinuation().isExpired()))
             {
                 if (_compactPath)
                     target = URIUtil.compactPath(target);
@@ -1494,6 +1536,7 @@
         _localeEncodingMap.put(locale,encoding);
     }
 
+    /* ------------------------------------------------------------ */
     public String getLocaleEncoding(String locale)
     {
         if (_localeEncodingMap == null)
@@ -1672,6 +1715,10 @@
      */
     public class Context implements ServletContext
     {
+        protected int _majorVersion = 3;
+        protected int _minorVersion = 0;
+        protected boolean _enabled = true; //whether or not the dynamic API is enabled for callers
+
         /* ------------------------------------------------------------ */
         protected Context()
         {
@@ -1688,6 +1735,7 @@
         /*
          * @see javax.servlet.ServletContext#getContext(java.lang.String)
          */
+        @Override
         public ServletContext getContext(String uripath)
         {
             List<ContextHandler> contexts = new ArrayList<ContextHandler>();
@@ -1773,15 +1821,18 @@
         /*
          * @see javax.servlet.ServletContext#getMajorVersion()
          */
+        @Override
         public int getMajorVersion()
         {
-            return 2;
+            return 3;
         }
+      
 
         /* ------------------------------------------------------------ */
         /*
          * @see javax.servlet.ServletContext#getMimeType(java.lang.String)
          */
+        @Override
         public String getMimeType(String file)
         {
             if (_mimeTypes == null)
@@ -1796,15 +1847,17 @@
         /*
          * @see javax.servlet.ServletContext#getMinorVersion()
          */
+        @Override
         public int getMinorVersion()
         {
-            return 5;
+            return 0;
         }
 
         /* ------------------------------------------------------------ */
         /*
          * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String)
          */
+        @Override
         public RequestDispatcher getNamedDispatcher(String name)
         {
             return null;
@@ -1814,6 +1867,7 @@
         /*
          * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String)
          */
+        @Override
         public RequestDispatcher getRequestDispatcher(String uriInContext)
         {
             if (uriInContext == null)
@@ -1831,13 +1885,14 @@
                     query = uriInContext.substring(q + 1);
                     uriInContext = uriInContext.substring(0,q);
                 }
-                // if ((q = uriInContext.indexOf(';')) > 0)
-                //     uriInContext = uriInContext.substring(0,q);
 
                 String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext));
-                String uri = URIUtil.addPaths(getContextPath(),uriInContext);
-                ContextHandler context = ContextHandler.this;
-                return new Dispatcher(context,uri,pathInContext,query);
+                if (pathInContext!=null)
+                {
+                    String uri = URIUtil.addPaths(getContextPath(),uriInContext);
+                    ContextHandler context = ContextHandler.this;
+                    return new Dispatcher(context,uri,pathInContext,query);
+                }
             }
             catch (Exception e)
             {
@@ -1850,6 +1905,7 @@
         /*
          * @see javax.servlet.ServletContext#getRealPath(java.lang.String)
          */
+        @Override
         public String getRealPath(String path)
         {
             if (path == null)
@@ -1878,6 +1934,7 @@
         }
 
         /* ------------------------------------------------------------ */
+        @Override
         public URL getResource(String path) throws MalformedURLException
         {
             Resource resource = ContextHandler.this.getResource(path);
@@ -1890,6 +1947,7 @@
         /*
          * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String)
          */
+        @Override
         public InputStream getResourceAsStream(String path)
         {
             try
@@ -1911,6 +1969,7 @@
         /*
          * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String)
          */
+        @Override
         public Set getResourcePaths(String path)
         {
             return ContextHandler.this.getResourcePaths(path);
@@ -1920,6 +1979,7 @@
         /*
          * @see javax.servlet.ServletContext#getServerInfo()
          */
+        @Override
         public String getServerInfo()
         {
             return "jetty/" + Server.getVersion();
@@ -1929,6 +1989,8 @@
         /*
          * @see javax.servlet.ServletContext#getServlet(java.lang.String)
          */
+        @Override
+        @Deprecated
         public Servlet getServlet(String name) throws ServletException
         {
             return null;
@@ -1939,6 +2001,8 @@
          * @see javax.servlet.ServletContext#getServletNames()
          */
         @SuppressWarnings("unchecked")
+        @Override
+        @Deprecated
         public Enumeration getServletNames()
         {
             return Collections.enumeration(Collections.EMPTY_LIST);
@@ -1949,6 +2013,8 @@
          * @see javax.servlet.ServletContext#getServlets()
          */
         @SuppressWarnings("unchecked")
+        @Override
+        @Deprecated
         public Enumeration getServlets()
         {
             return Collections.enumeration(Collections.EMPTY_LIST);
@@ -1958,6 +2024,7 @@
         /*
          * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String)
          */
+        @Override
         public void log(Exception exception, String msg)
         {
             _logger.warn(msg,exception);
@@ -1967,6 +2034,7 @@
         /*
          * @see javax.servlet.ServletContext#log(java.lang.String)
          */
+        @Override
         public void log(String msg)
         {
             _logger.info(msg);
@@ -1976,6 +2044,7 @@
         /*
          * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable)
          */
+        @Override
         public void log(String message, Throwable throwable)
         {
             _logger.warn(message,throwable);
@@ -1985,6 +2054,7 @@
         /*
          * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
          */
+        @Override
         public String getInitParameter(String name)
         {
             return ContextHandler.this.getInitParameter(name);
@@ -1995,6 +2065,7 @@
          * @see javax.servlet.ServletContext#getInitParameterNames()
          */
         @SuppressWarnings("unchecked")
+        @Override
         public Enumeration getInitParameterNames()
         {
             return ContextHandler.this.getInitParameterNames();
@@ -2004,6 +2075,7 @@
         /*
          * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
          */
+        @Override
         public synchronized Object getAttribute(String name)
         {
             Object o = ContextHandler.this.getAttribute(name);
@@ -2017,6 +2089,7 @@
          * @see javax.servlet.ServletContext#getAttributeNames()
          */
         @SuppressWarnings("unchecked")
+        @Override
         public synchronized Enumeration getAttributeNames()
         {
             HashSet<String> set = new HashSet<String>();
@@ -2037,6 +2110,7 @@
         /*
          * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
          */
+        @Override
         public synchronized void setAttribute(String name, Object value)
         {
             checkManagedAttribute(name,value);
@@ -2069,6 +2143,7 @@
         /*
          * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
          */
+        @Override
         public synchronized void removeAttribute(String name)
         {
             checkManagedAttribute(name,null);
@@ -2098,6 +2173,7 @@
         /*
          * @see javax.servlet.ServletContext#getServletContextName()
          */
+        @Override
         public String getServletContextName()
         {
             String name = ContextHandler.this.getDisplayName();
@@ -2107,6 +2183,7 @@
         }
 
         /* ------------------------------------------------------------ */
+        @Override
         public String getContextPath()
         {
             if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH))
@@ -2123,6 +2200,7 @@
         }
 
         /* ------------------------------------------------------------ */
+        @Override
         public boolean setInitParameter(String name, String value)
         {
             if (ContextHandler.this.getInitParameter(name) != null)
@@ -2131,6 +2209,243 @@
             return true;
         }
 
+        /* ------------------------------------------------------------ */
+        final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler";
+
+        @Override
+        public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass)
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public Dynamic addFilter(String filterName, Filter filter)
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public Dynamic addFilter(String filterName, String className)
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass)
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, String className)
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public <T extends Filter> T createFilter(Class<T> c) throws ServletException
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public <T extends Servlet> T createServlet(Class<T> c) throws ServletException
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public FilterRegistration getFilterRegistration(String filterName)
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public Map<String, ? extends FilterRegistration> getFilterRegistrations()
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public ServletRegistration getServletRegistration(String servletName)
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public Map<String, ? extends ServletRegistration> getServletRegistrations()
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public SessionCookieConfig getSessionCookieConfig()
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        @Override
+        public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
+        {
+            LOG.warn(__unimplmented);
+        }
+
+        @Override
+        public void addListener(String className)
+        {
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
+            try
+            {
+                Class<? extends EventListener> clazz = _classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className);
+                addListener(clazz);
+            }
+            catch (ClassNotFoundException e)
+            {
+                throw new IllegalArgumentException(e);
+            }
+        }
+
+        @Override
+        public <T extends EventListener> void addListener(T t)
+        {            
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            ContextHandler.this.addEventListener(t);
+            ContextHandler.this.restrictEventListener(t);
+        }
+
+        @Override
+        public void addListener(Class<? extends EventListener> listenerClass)
+        {            
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+
+            try
+            {
+                EventListener e = createListener(listenerClass);
+                ContextHandler.this.addEventListener(e);
+                ContextHandler.this.restrictEventListener(e);
+            }
+            catch (ServletException e)
+            {
+                throw new IllegalArgumentException(e);
+            }
+        }
+
+        @Override
+        public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
+        {
+            try
+            {
+                return clazz.newInstance();
+            }
+            catch (InstantiationException e)
+            {
+                throw new ServletException(e);
+            }
+            catch (IllegalAccessException e)
+            {
+                throw new ServletException(e);
+            }
+        }
+
+        @Override
+        public ClassLoader getClassLoader()
+        {
+            AccessController.checkPermission(new RuntimePermission("getClassLoader"));
+            return _classLoader;
+        }
+
+        @Override
+        public int getEffectiveMajorVersion()
+        {
+            return _majorVersion;
+        }
+
+        @Override
+        public int getEffectiveMinorVersion()
+        {
+            return _minorVersion;
+        }
+
+        public void setEffectiveMajorVersion (int v)
+        {
+            _majorVersion = v;
+        }
+        
+        public void setEffectiveMinorVersion (int v)
+        {
+            _minorVersion = v;
+        }
+        
+        @Override
+        public JspConfigDescriptor getJspConfigDescriptor()
+        {
+            LOG.warn(__unimplmented);
+            return null;
+        }
+
+        public void setJspConfigDescriptor(JspConfigDescriptor d)
+        {
+            
+        }
+        
+        @Override
+        public void declareRoles(String... roleNames)
+        {
+            if (!isStarting())
+                throw new IllegalStateException ();
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
+            // TODO Auto-generated method stub
+            
+        }
+
+        public void setEnabled(boolean enabled)
+        {
+            _enabled = enabled;
+        }
+
+        public boolean isEnabled()
+        {
+            return _enabled;
+        }
     }
 
     private static class CLDump implements Dumpable
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 571c708..3cb655f 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
@@ -23,6 +23,7 @@
 import java.io.StringWriter;
 import java.io.Writer;
 
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -31,8 +32,11 @@
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.server.AbstractHttpConnection;
+import org.eclipse.jetty.server.Dispatcher;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.util.ByteArrayISO8859Writer;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 
 /* ------------------------------------------------------------ */
 /** Handler for Error pages
@@ -42,7 +46,10 @@
  * 
  */
 public class ErrorHandler extends AbstractHandler
-{
+{    
+    private static final Logger LOG = Log.getLogger(ErrorHandler.class);
+    public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
+    
     boolean _showStacks=true;
     boolean _showMessageInTitle=true;
     String _cacheControl="must-revalidate,no-cache,no-store";
@@ -54,10 +61,43 @@
     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
     {
         AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection();
-        connection.getRequest().setHandled(true);
         String method = request.getMethod();
         if(!method.equals(HttpMethods.GET) && !method.equals(HttpMethods.POST) && !method.equals(HttpMethods.HEAD))
+        {
+            connection.getRequest().setHandled(true);
             return;
+        }
+        
+        if (this instanceof ErrorPageMapper)
+        {
+            String error_page=((ErrorPageMapper)this).getErrorPage(request);
+            if (error_page!=null && request.getServletContext()!=null)
+            {
+                String old_error_page=(String)request.getAttribute(ERROR_PAGE);
+                if (old_error_page==null || !old_error_page.equals(error_page))
+                {
+                    request.setAttribute(ERROR_PAGE, error_page);
+
+                    Dispatcher dispatcher = (Dispatcher) request.getServletContext().getRequestDispatcher(error_page);
+                    try
+                    {
+                        if(dispatcher!=null)
+                        {
+                            dispatcher.error(request, response);
+                            return;
+                        }
+                        LOG.warn("No error page "+error_page);
+                    }
+                    catch (ServletException e)
+                    {
+                        LOG.warn(Log.EXCEPTION, e);
+                        return;
+                    }
+                }
+            }
+        }
+        
+        connection.getRequest().setHandled(true);
         response.setContentType(MimeTypes.TEXT_HTML_8859_1);    
         if (_cacheControl!=null)
             response.setHeader(HttpHeaders.CACHE_CONTROL, _cacheControl);
@@ -236,4 +276,10 @@
             }          
         }
     }
+
+    /* ------------------------------------------------------------ */
+    public interface ErrorPageMapper
+    {
+        String getErrorPage(HttpServletRequest request);
+    }
 }
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 e0fa96c..a6d6f12 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
@@ -242,7 +242,7 @@
                 pathMap = new PathMap(true);
                 patternMap.put(addr,pathMap);
             }
-            if (path != null)
+            if (path != null && !"".equals(path))
                 pathMap.put(path,path);
             
             if (deprecated)
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
new file mode 100644
index 0000000..2e9c19c
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java
@@ -0,0 +1,138 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.AbstractHttpConnection;
+import org.eclipse.jetty.server.Request;
+
+/**
+ * Handler to adjust the idle timeout of requests while dispatched.
+ * 
+ * <p>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>
+ * </pre>
+ */
+public class IdleTimeoutHandler extends HandlerWrapper
+{
+    private int _idleTimeoutMs = 1000;
+    private boolean _applyToAsync = false;
+    
+    
+    public boolean isApplyToAsync()
+    {
+        return _applyToAsync;
+    }
+
+    /**
+     * Should the adjusted idle time be maintained for asynchronous requests
+     * @param applyToAsync true if alternate idle timeout is applied to asynchronous requests
+     */
+    public void setApplyToAsync(boolean applyToAsync)
+    {
+        _applyToAsync = applyToAsync;
+    }
+
+    public long getIdleTimeoutMs()
+    {
+        return _idleTimeoutMs;
+    }
+
+    /**
+     * @param idleTimeoutMs The idle timeout in MS to apply while dispatched or async
+     */
+    public void setIdleTimeoutMs(int _idleTimeoutMs)
+    {
+        this._idleTimeoutMs = _idleTimeoutMs;
+    }
+    
+   
+    @Override
+    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+    {
+        AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection();
+        final EndPoint endp = connection==null?null:connection.getEndPoint();
+        
+        final int idle_timeout;
+        if (endp==null)
+            idle_timeout=-1;
+        else
+        {
+            idle_timeout=endp.getMaxIdleTime();
+            endp.setMaxIdleTime(_idleTimeoutMs);
+        }
+        
+        try
+        {
+            super.handle(target,baseRequest,request,response);
+        }
+        finally
+        {
+            if (endp!=null)
+            {
+                if (_applyToAsync && 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
+                        {
+                            endp.setMaxIdleTime(idle_timeout);
+                        }
+                        
+                        @Override
+                        public void onComplete(AsyncEvent event) throws IOException
+                        {
+                            endp.setMaxIdleTime(idle_timeout);
+                        }
+                    });
+                }
+                else 
+                {
+                    endp.setMaxIdleTime(idle_timeout);
+                }
+            }
+        }
+    }
+}
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 cfca629..5b7d525 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,6 +20,7 @@
 
 import java.io.IOException;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -27,7 +28,6 @@
 import org.eclipse.jetty.continuation.Continuation;
 import org.eclipse.jetty.continuation.ContinuationListener;
 import org.eclipse.jetty.server.AsyncContinuation;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.RequestLog;
 import org.eclipse.jetty.server.Response;
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 b616300..768bba1 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
@@ -211,7 +211,6 @@
     /* ------------------------------------------------------------- */
     public int getMaxInactiveInterval()
     {
-        checkValid();
         return (int)(_maxIdleMs/1000);
     }
 
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 6415d20..e7ee052 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
@@ -20,15 +20,20 @@
 
 import static java.lang.Math.round;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.EventListener;
+import java.util.HashSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.servlet.ServletRequest;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 import javax.servlet.http.HttpSessionAttributeListener;
@@ -63,6 +68,12 @@
 public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager
 {
     final static Logger __log = SessionHandler.LOG;
+
+    public Set<SessionTrackingMode> __defaultSessionTrackingModes =
+        Collections.unmodifiableSet(
+            new HashSet<SessionTrackingMode>(
+                    Arrays.asList(new SessionTrackingMode[]{SessionTrackingMode.COOKIE,SessionTrackingMode.URL})));
+        
     public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated";
     
     /* ------------------------------------------------------------ */
@@ -92,6 +103,8 @@
     protected boolean _httpOnly=false;
     protected SessionIdManager _sessionIdManager;
     protected boolean _secureCookies=false;
+    protected boolean _secureRequestOnly=true;
+
     protected final List<HttpSessionAttributeListener> _sessionAttributeListeners = new CopyOnWriteArrayList<HttpSessionAttributeListener>();
     protected final List<HttpSessionListener> _sessionListeners= new CopyOnWriteArrayList<HttpSessionListener>();
 
@@ -106,7 +119,12 @@
     protected int _refreshCookieAge;
     protected boolean _nodeIdInSessionId;
     protected boolean _checkingRemoteSessionIdEncoding;
+    protected String _sessionComment;
 
+    public Set<SessionTrackingMode> _sessionTrackingModes;
+
+    private boolean _usingURLs;
+    
     protected final CounterStatistic _sessionsStats = new CounterStatistic();
     protected final SampleStatistic _sessionTimeStats = new SampleStatistic();
     
@@ -135,6 +153,7 @@
     /* ------------------------------------------------------------ */
     public AbstractSessionManager()
     {
+        setSessionTrackingModes(__defaultSessionTrackingModes);
     }
 
     /* ------------------------------------------------------------ */
@@ -149,6 +168,16 @@
         return _context.getContextHandler();
     }
     
+    public String getSessionPath()
+    {
+        return _sessionPath;
+    }
+
+    public int getMaxCookieAge()
+    {
+        return _maxCookieAge;
+    }
+
     /* ------------------------------------------------------------ */
     public HttpCookie access(HttpSession session,boolean secure)
     {
@@ -156,14 +185,14 @@
 
         AbstractSession s = ((SessionIf)session).getSession();
 
-        if (s.access(now))
-        {
+       if (s.access(now))
+       {
             // Do we need to refresh the cookie?
             if (isUsingCookies() &&
-                    (s.isIdChanged() ||
-                            (getMaxCookieAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge()))
-                    )
-            )
+                (s.isIdChanged() ||
+                (getSessionCookieConfig().getMaxAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge()))
+                )
+               )
             {
                 HttpCookie cookie=getSessionCookie(session,_context==null?"/":(_context.getContextPath()),secure);
                 s.cookieSet();
@@ -305,16 +334,12 @@
         return _sessionIdManager;
     }
 
-    /* ------------------------------------------------------------ */
-    public int getMaxCookieAge()
-    {
-        return _maxCookieAge;
-    }
 
     /* ------------------------------------------------------------ */
     /**
      * @return seconds
      */
+    @Override
     public int getMaxInactiveInterval()
     {
         return _dftMaxIdleSecs;
@@ -377,13 +402,38 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @return Returns the secureCookies.
+     * @return same as SessionCookieConfig.getSecure(). If true, session
+     * cookies are ALWAYS marked as secure. If false, a session cookie is
+     * ONLY marked as secure if _secureRequestOnly == true and it is a HTTPS request.
      */
     public boolean getSecureCookies()
     {
         return _secureCookies;
     }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @return true if session cookie is to be marked as secure only on HTTPS requests
+     */
+    public boolean isSecureRequestOnly()
+    {
+        return _secureRequestOnly;
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @return if true, session cookie will be marked as secure only iff 
+     * 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.
+     */
+    public void setSecureRequestOnly(boolean secureRequestOnly)
+    {
+        _secureRequestOnly = secureRequestOnly;
+    }
 
+    
+    
     /* ------------------------------------------------------------ */
     public String getSessionCookie()
     {
@@ -391,6 +441,31 @@
     }
 
     /* ------------------------------------------------------------ */
+    /** 
+     * 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>
+     * </ol>
+     * According to SessionCookieConfig javadoc, case 1 can be used when:
+     * "... even though the request that initiated the session came over HTTP, 
+     * is to support a topology where the web container is front-ended by an 
+     * 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."
+     * 
+     * For case 2, you can use _secureRequestOnly to determine if you want the
+     * Servlet Spec 3.0  default behaviour when SessionCookieConfig.setSecure==false, 
+     * which is:
+     * "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
+     * you set it to false, then a session cookie is NEVER marked as secure, even if
+     * the initiating request was secure.
+     * 
+     * @see org.eclipse.jetty.server.SessionManager#getSessionCookie(javax.servlet.http.HttpSession, java.lang.String, boolean)
+     */
     public HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure)
     {
         if (isUsingCookies())
@@ -398,15 +473,32 @@
             String sessionPath = (_sessionPath==null) ? contextPath : _sessionPath;
             sessionPath = (sessionPath==null||sessionPath.length()==0) ? "/" : sessionPath;
             String id = getNodeId(session);
-            HttpCookie cookie=new HttpCookie(
-                    _sessionCookie,
-                    id,
-                    _sessionDomain,
-                    sessionPath,
-                    getMaxCookieAge(),
-                    getHttpOnly(),
-                    requestIsSecure&&getSecureCookies());      
-                    
+            HttpCookie cookie = null;
+            if (_sessionComment == null)
+            {
+                cookie = new HttpCookie(
+                                        _sessionCookie,
+                                        id,
+                                        _sessionDomain,
+                                        sessionPath,
+                                        _cookieConfig.getMaxAge(),
+                                        _cookieConfig.isHttpOnly(),
+                                        _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure));                  
+            }
+            else
+            {
+                cookie = new HttpCookie(
+                                        _sessionCookie,
+                                        id,
+                                        _sessionDomain,
+                                        sessionPath,
+                                        _cookieConfig.getMaxAge(),
+                                        _cookieConfig.isHttpOnly(),
+                                        _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure),
+                                        _sessionComment,
+                                        1);    
+            }
+
             return cookie;
         }
         return null;
@@ -436,11 +528,7 @@
         throw new UnsupportedOperationException();
     }
 
-    /* ------------------------------------------------------------ */
-    public String getSessionPath()
-    {
-        return _sessionPath;
-    }
+   
 
     /* ------------------------------------------------------------ */
     public int getSessions()
@@ -560,15 +648,7 @@
         _sessionIdManager=metaManager;
     }
 
-    /* ------------------------------------------------------------ */
-    public void setMaxCookieAge(int maxCookieAgeInSeconds)
-    {
-        _maxCookieAge=maxCookieAgeInSeconds;
 
-        if (_maxCookieAge>0 && _refreshCookieAge==0)
-            _refreshCookieAge=_maxCookieAge/3;
-
-    }
 
     /* ------------------------------------------------------------ */
     /**
@@ -579,15 +659,6 @@
         _dftMaxIdleSecs=seconds;
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @deprecated use {@link #setSessionIdManager(SessionIdManager)}
-     */
-    @Deprecated
-    public void setMetaManager(SessionIdManager metaManager)
-    {
-        setSessionIdManager(metaManager);
-    }
 
     /* ------------------------------------------------------------ */
     public void setRefreshCookieAge(int ageInSeconds)
@@ -596,34 +667,13 @@
     }
 
 
-    /* ------------------------------------------------------------ */
-    /**
-     * Set if the session manager should use SecureCookies.
-     * A secure cookie will only be sent by a browser on a secure (https) connection to 
-     * avoid the concern of cookies being intercepted on non secure channels.
-     * For the cookie to be issued as secure, the {@link ServletRequest#isSecure()} method must return true.
-     * If SSL offload is used, then the {@link AbstractConnector#customize(org.eclipse.jetty.io.EndPoint, Request)}
-     * method can be used to force the request to be https, or the {@link AbstractConnector#setForwarded(boolean)}
-     * can be set to true, so that the X-Forwarded-Proto header is respected.
-     * <p>
-     * If secure session cookies are used, then a session may not be shared between http and https requests.
-     * 
-     * @param secureCookies If true, use secure cookies.
-     */
-    public void setSecureCookies(boolean secureCookies)
-    {
-        _secureCookies=secureCookies;
-    }
 
     public void setSessionCookie(String cookieName)
     {
         _sessionCookie=cookieName;
     }
 
-    public void setSessionDomain(String domain)
-    {
-        _sessionDomain=domain;
-    }
+
 
     /* ------------------------------------------------------------ */
     /**
@@ -635,15 +685,7 @@
         _sessionHandler=sessionHandler;
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.server.SessionManager#setSessionPath(java.lang.String)
-     */
-    public void setSessionPath(String path)
-    {
-        _sessionPath=path;
-    }
-
+ 
     /* ------------------------------------------------------------ */
     public void setSessionIdPathParameterName(String param)
     {
@@ -781,6 +823,132 @@
     }
 
     /* ------------------------------------------------------------ */
+    public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
+    {
+        return __defaultSessionTrackingModes;
+    }
+
+    /* ------------------------------------------------------------ */
+    public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
+    {
+        return Collections.unmodifiableSet(_sessionTrackingModes);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
+    {
+        _sessionTrackingModes=new HashSet<SessionTrackingMode>(sessionTrackingModes);
+        _usingCookies=_sessionTrackingModes.contains(SessionTrackingMode.COOKIE);
+        _usingURLs=_sessionTrackingModes.contains(SessionTrackingMode.URL);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public boolean isUsingURLs()
+    {
+        return _usingURLs;
+    }
+
+
+    /* ------------------------------------------------------------ */
+    public SessionCookieConfig getSessionCookieConfig()
+    {
+        return _cookieConfig;
+    } 
+
+    /* ------------------------------------------------------------ */
+    private SessionCookieConfig _cookieConfig =
+        new SessionCookieConfig()
+        {
+            @Override
+            public String getComment()
+            {
+                return _sessionComment;
+            }
+
+            @Override
+            public String getDomain()
+            {
+                return _sessionDomain;
+            }
+
+            @Override
+            public int getMaxAge()
+            {
+                return _maxCookieAge;
+            }
+
+            @Override
+            public String getName()
+            {
+                return _sessionCookie;
+            }
+
+            @Override
+            public String getPath()
+            {
+                return _sessionPath;
+            }
+
+            @Override
+            public boolean isHttpOnly()
+            {
+                return _httpOnly;
+            }
+
+            @Override
+            public boolean isSecure()
+            {
+                return _secureCookies;
+            }
+
+            @Override
+            public void setComment(String comment)
+            {
+                _sessionComment = comment; 
+            }
+
+            @Override
+            public void setDomain(String domain)
+            {
+                _sessionDomain=domain;
+            }
+
+            @Override
+            public void setHttpOnly(boolean httpOnly)
+            {
+                _httpOnly=httpOnly;
+            }
+
+            @Override
+            public void setMaxAge(int maxAge)
+            {
+                _maxCookieAge=maxAge;
+            }
+
+            @Override
+            public void setName(String name)
+            {
+                _sessionCookie=name;
+            }
+
+            @Override
+            public void setPath(String path)
+            {
+                _sessionPath=path;
+            }
+
+            @Override
+            public void setSecure(boolean secure)
+            {
+                _secureCookies=secure;
+            }
+        
+        };
+
+
+    /* ------------------------------------------------------------ */
     /**
      * @return total amount of time all sessions remained valid
      */
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 3e29bd7..0a9e0c0 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
@@ -28,6 +28,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
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 aab7bba..f8d6dfb 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
@@ -634,10 +634,21 @@
             if (!(index1Exists && index2Exists))
             {
                 Statement statement = connection.createStatement();
-                if (!index1Exists)
-                    statement.executeUpdate("create index "+index1+" on "+_sessionTable+" (expiryTime)");
-                if (!index2Exists)
-                    statement.executeUpdate("create index "+index2+" on "+_sessionTable+" (sessionId, contextPath)");
+                try
+                {
+                    if (!index1Exists)
+                        statement.executeUpdate("create index "+index1+" on "+_sessionTable+" (expiryTime)");
+                    if (!index2Exists)
+                        statement.executeUpdate("create index "+index2+" on "+_sessionTable+" (sessionId, contextPath)");
+                }
+                finally
+                {
+                    if (statement!=null)
+                    {
+                        try { statement.close(); }
+                        catch(Exception e) { LOG.warn(e); }
+                    }
+                }
             }
 
             //set up some strings representing the statements for session manipulation
@@ -676,23 +687,37 @@
     throws SQLException 
     {
         Connection connection = null;
+        PreparedStatement statement = null;
+        PreparedStatement query = null;
         try
         {
             connection = getConnection();
             connection.setAutoCommit(true);            
-            PreparedStatement query = connection.prepareStatement(_queryId);
+            query = connection.prepareStatement(_queryId);
             query.setString(1, id);
             ResultSet result = query.executeQuery();
             //only insert the id if it isn't in the db already 
             if (!result.next())
             {
-                PreparedStatement statement = connection.prepareStatement(_insertId);
+                statement = connection.prepareStatement(_insertId);
                 statement.setString(1, id);
                 statement.executeUpdate();
             }
         }
         finally
         {
+            if (query!=null)
+            {
+                try { query.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             if (connection != null)
                 connection.close();
         }
@@ -708,16 +733,23 @@
     throws SQLException
     {
         Connection connection = null;
+        PreparedStatement statement = null;
         try
         {
             connection = getConnection();
             connection.setAutoCommit(true);
-            PreparedStatement statement = connection.prepareStatement(_deleteId);
+            statement = connection.prepareStatement(_deleteId);
             statement.setString(1, id);
             statement.executeUpdate();
         }
         finally
         {
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             if (connection != null)
                 connection.close();
         }
@@ -735,17 +767,24 @@
     throws SQLException
     {
         Connection connection = null;
+        PreparedStatement statement = null;
         try
         {
             connection = getConnection();
             connection.setAutoCommit(true);
-            PreparedStatement statement = connection.prepareStatement(_queryId);
+            statement = connection.prepareStatement(_queryId);
             statement.setString(1, id);
             ResultSet result = statement.executeQuery();
             return result.next();
         }
         finally
         {
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             if (connection != null)
                 connection.close();
         }
@@ -765,6 +804,7 @@
     private void scavenge ()
     {
         Connection connection = null;
+        PreparedStatement statement = null;
         List<String> expiredSessionIds = new ArrayList<String>();
         try
         {            
@@ -775,7 +815,7 @@
                 connection = getConnection();
                 connection.setAutoCommit(true);
                 //"select sessionId from JettySessions where expiryTime > (lastScavengeTime - scanInterval) and expiryTime < lastScavengeTime";
-                PreparedStatement statement = connection.prepareStatement(_selectBoundedExpiredSessions);
+                statement = connection.prepareStatement(_selectBoundedExpiredSessions);
                 long lowerBound = (_lastScavengeTime - _scavengeIntervalMs);
                 long upperBound = _lastScavengeTime;
                 if (LOG.isDebugEnabled()) 
@@ -812,10 +852,21 @@
                 if (upperBound > 0)
                 {
                     if (LOG.isDebugEnabled()) LOG.debug("Deleting old expired sessions expired before "+upperBound);
-                    statement = connection.prepareStatement(_deleteOldExpiredSessions);
-                    statement.setLong(1, upperBound);
-                    int rows = statement.executeUpdate();
-                    if (LOG.isDebugEnabled()) LOG.debug("Deleted "+rows+" rows of old sessions expired before "+upperBound);
+                    try
+                    {
+                        statement = connection.prepareStatement(_deleteOldExpiredSessions);
+                        statement.setLong(1, upperBound);
+                        int rows = statement.executeUpdate();
+                        if (LOG.isDebugEnabled()) LOG.debug("Deleted "+rows+" rows of old sessions expired before "+upperBound);
+                    }
+                    finally
+                    {
+                        if (statement!=null)
+                        {
+                            try { statement.close(); }
+                            catch(Exception e) { LOG.warn(e); }
+                        }
+                    }
                 }
             }
         }
@@ -849,17 +900,19 @@
      * @throws Exception
      */
     private void cleanExpiredSessions ()
-    throws Exception
     {
         Connection connection = null;
+        PreparedStatement statement = null;
+        Statement sessionsTableStatement = null;
+        Statement sessionIdsTableStatement = null;
         List<String> expiredSessionIds = new ArrayList<String>();
         try
         {     
             connection = getConnection();
-            connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
+            connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
             connection.setAutoCommit(false);
 
-            PreparedStatement statement = connection.prepareStatement(_selectExpiredSessions);
+            statement = connection.prepareStatement(_selectExpiredSessions);
             long now = System.currentTimeMillis();
             if (LOG.isDebugEnabled()) LOG.debug ("Searching for sessions expired before {}", now);
 
@@ -872,8 +925,8 @@
                 if (LOG.isDebugEnabled()) LOG.debug ("Found expired sessionId={}", sessionId); 
             }
             
-            Statement sessionsTableStatement = null;
-            Statement sessionIdsTableStatement = null;
+            sessionsTableStatement = null;
+            sessionIdsTableStatement = null;
 
             if (!expiredSessionIds.isEmpty())
             {
@@ -892,11 +945,35 @@
         catch (Exception e)
         {
             if (connection != null)
-                connection.rollback();
-            throw e;
+            {
+                try 
+                { 
+                    LOG.warn("Rolling back clean of expired sessions", e);
+                    connection.rollback();
+                }
+                catch (Exception x) { LOG.warn("Rollback of expired sessions failed", x);}
+            }
         }
         finally
         {
+            if (sessionIdsTableStatement!=null)
+            {
+                try { sessionIdsTableStatement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
+            if (sessionsTableStatement!=null)
+            {
+                try { sessionsTableStatement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             try
             {
                 if (connection != null)
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 61ba4fa..fcd214b 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
@@ -34,9 +34,11 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 
+import javax.servlet.SessionTrackingMode;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSessionEvent;
 import javax.servlet.http.HttpSessionListener;
@@ -532,7 +534,11 @@
 
                     }
                     else
+                    {
+                       //the session loaded from the db and the one in memory are the same, so keep using the one in memory
+                       session = memSession;
                        LOG.debug("getSession({}): Session not stale {}", idInCluster,session);
+                    }
                 }
                 else
                 {
@@ -841,6 +847,12 @@
                 }
                 finally
                 {
+                    if (statement!=null)
+                    {
+                        try { statement.close(); }
+                        catch(Exception e) { LOG.warn(e); }
+                    }
+
                     if (connection!=null)
                     {
                         try { connection.close();}
@@ -918,6 +930,12 @@
         }
         finally
         {
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             if (connection!=null)
                 connection.close();
         }
@@ -965,6 +983,12 @@
         }
         finally
         {
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             if (connection!=null)
                 connection.close();
         }
@@ -996,6 +1020,12 @@
         }
         finally
         {
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             if (connection!=null)
                 connection.close();
         }
@@ -1031,6 +1061,12 @@
         }
         finally
         {
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             if (connection!=null)
                 connection.close();
         }
@@ -1062,6 +1098,12 @@
         }
         finally
         {
+            if (statement!=null)
+            {
+                try { statement.close(); }
+                catch(Exception e) { LOG.warn(e); }
+            }
+
             if (connection!=null)
                 connection.close();
         }
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 76d780a..8bd2f95 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
@@ -19,15 +19,17 @@
 package org.eclipse.jetty.server.session;
 
 import java.io.IOException;
+import java.util.EnumSet;
 import java.util.EventListener;
+import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
+import javax.servlet.SessionTrackingMode;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
 import org.eclipse.jetty.http.HttpCookie;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.SessionManager;
@@ -43,6 +45,8 @@
 {
     final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
 
+    public final static EnumSet<SessionTrackingMode> DEFAULT_TRACKING = EnumSet.of(SessionTrackingMode.COOKIE,SessionTrackingMode.URL);
+
     /* -------------------------------------------------------------- */
     private SessionManager _sessionManager;
 
@@ -260,9 +264,10 @@
             Cookie[] cookies = request.getCookies();
             if (cookies != null && cookies.length > 0)
             {
+                final String sessionCookie=sessionManager.getSessionCookieConfig().getName();
                 for (int i = 0; i < cookies.length; i++)
                 {
-                    if (sessionManager.getSessionCookie().equalsIgnoreCase(cookies[i].getName()))
+                    if (sessionCookie.equalsIgnoreCase(cookies[i].getName()))
                     {
                         requested_session_id = cookies[i].getValue();
                         requested_session_id_from_cookie = true;
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 2d55cfa..808d04a 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
@@ -27,7 +27,10 @@
 import java.util.Random;
 import java.util.Timer;
 import java.util.TimerTask;
-
+import javax.servlet.AsyncContext;
+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;
@@ -226,10 +229,9 @@
                 if (suspend_for>=0)
                 {
                     final AsyncContext asyncContext = baseRequest.startAsync();
-                    asyncContext.addContinuationListener(__asyncListener);
+                    asyncContext.addListener(__asyncListener);
                     if (suspend_for>0)
                         asyncContext.setTimeout(suspend_for);
-
                     if (complete_after>0)
                     {
                         TimerTask complete = new TimerTask()
@@ -325,18 +327,31 @@
             }
         }
     }
-
-
-    private static ContinuationListener __asyncListener = new ContinuationListener()
+    
+    
+    private static AsyncListener __asyncListener = new AsyncListener()
     {
-        public void onComplete(Continuation continuation)
+        @Override
+        public void onComplete(AsyncEvent event) throws IOException
         {
         }
 
-        public void onTimeout(Continuation continuation)
+        @Override
+        public void onTimeout(AsyncEvent event) throws IOException
         {
-            continuation.setAttribute("TIMEOUT",Boolean.TRUE);
-            continuation.resume();
+            event.getSuppliedRequest().setAttribute("TIMEOUT",Boolean.TRUE);
+            event.getSuppliedRequest().getAsyncContext().dispatch();
+        }
+
+        @Override
+        public void onError(AsyncEvent event) throws IOException
+        {
+            
+        }
+
+        @Override
+        public void onStartAsync(AsyncEvent event) throws IOException
+        {
         }
     };
 }
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 d41238c..603f533 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
@@ -128,6 +128,66 @@
         checkContains(response,offset,"pathInfo=/");
     }
     
+    @Test
+    public void testBadNoPath() throws Exception
+    {
+        String response=connector.getResponses("GET http://localhost:80/../cheat HTTP/1.1\n"+
+                "Host: localhost:80\n"+
+                "\n");
+        int offset=0;
+        offset = checkContains(response,offset,"HTTP/1.1 400");
+    }
+
+    @Test
+    public void testOKPathDotDotPath() throws Exception
+    {
+        String response=connector.getResponses("GET /ooops/../path HTTP/1.0\nHost: localhost:80\n\n");
+        checkContains(response,0,"HTTP/1.1 200 OK");
+        checkContains(response,0,"pathInfo=/path");
+    }
+    
+    @Test
+    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");
+    }
+    
+    @Test
+    public void testOKPathEncodedDotDotPath() throws Exception
+    {
+        String response=connector.getResponses("GET /ooops/%2e%2e/path HTTP/1.0\nHost: localhost:80\n\n");
+        checkContains(response,0,"HTTP/1.1 200 OK");
+        checkContains(response,0,"pathInfo=/path");
+    }
+    
+    @Test
+    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");
+    }
+    
+    @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");
+    }
+    
+    @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");
+    }
+
+    @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");
+    }
 
     @Test
     public void testEmpty() throws Exception
@@ -441,6 +501,7 @@
         request.append("\015\012");
         
         response = connector.getResponses(request.toString());
+        System.err.println(response);
         checkContains(response, offset, "HTTP/1.1 413");
     }
 
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 aa54371..4fabe95 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,6 +18,27 @@
 
 package org.eclipse.jetty.server;
 
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.Exchanger;
+import java.util.concurrent.atomic.AtomicBoolean;
+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.io.EndPoint;
 import org.eclipse.jetty.io.EofException;
 import org.eclipse.jetty.server.handler.AbstractHandler;
@@ -30,23 +51,14 @@
 import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
 
-import javax.servlet.ServletException;
-import javax.servlet.ServletInputStream;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.*;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.concurrent.Exchanger;
-import java.util.concurrent.atomic.AtomicBoolean;
-
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 /**
  *
@@ -1427,6 +1439,72 @@
         }
     }
 
+
+    @Test
+    public void testWriteBodyAfterNoBodyREsponse() throws Exception
+    {
+        configureServer(new WriteBodyAfterNoBodyResponseHandler());
+        Socket client=newSocket(HOST,_connector.getLocalPort());
+        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
     {
         public void handle(String target, Request baseRequest,
@@ -1462,9 +1540,9 @@
                     "\r\n"
             ).getBytes());
             os.flush();
-
+            
             Thread.sleep(200);
-
+            
             // write an pipelined request
             os.write((
                     "GET / HTTP/1.1\r\n"+
@@ -1473,11 +1551,11 @@
                     "\r\n"
             ).getBytes());
             os.flush();
-
+            
             String response=readResponse(client);
             assertThat(response,JUnitMatchers.containsString("RESUMEDHTTP/1.1 200 OK"));
             assertThat((System.currentTimeMillis()-start),greaterThanOrEqualTo(1999L));
-
+            
             // TODO This test should also check that that the CPU did not spin during the suspend.
         }
         finally
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java
index 1b0c35a..8876f23 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java
@@ -18,18 +18,26 @@
 
 package org.eclipse.jetty.server;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.servlet.AsyncContext;
+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.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationListener;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.server.session.SessionHandler;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 public class LocalAsyncContextTest
 {
     protected Server _server = new Server();
@@ -48,7 +56,7 @@
         _server.setHandler(session);
         _server.start();
     }
-    
+
     protected Connector initConnector()
     {
         return new LocalConnector();
@@ -64,76 +72,123 @@
     @Test
     public void testSuspendResume() throws Exception
     {
+        String response;
+        __completed.set(0);
+        __completed1.set(0);
         _handler.setRead(0);
         _handler.setSuspendFor(1000);
         _handler.setResumeAfter(-1);
         _handler.setCompleteAfter(-1);
-        check("TIMEOUT",process(null));
+        response=process(null);
+        check(response,"TIMEOUT");
+        assertEquals(1,__completed.get());
+        assertEquals(1,__completed1.get());
 
         _handler.setSuspendFor(10000);
 
         _handler.setResumeAfter(0);
         _handler.setCompleteAfter(-1);
-        check("RESUMED",process(null));
+        response=process(null);
+        check(response,"DISPATCHED");
 
         _handler.setResumeAfter(100);
         _handler.setCompleteAfter(-1);
-        check("RESUMED",process(null));
+        response=process(null);
+        check(response,"DISPATCHED");
 
         _handler.setResumeAfter(-1);
         _handler.setCompleteAfter(0);
-        check("COMPLETED",process(null));
+        response=process(null);
+        check(response,"COMPLETED");
 
         _handler.setResumeAfter(-1);
         _handler.setCompleteAfter(200);
-        check("COMPLETED",process(null));
+        response=process(null);
+        check(response,"COMPLETED");
 
         _handler.setRead(-1);
 
         _handler.setResumeAfter(0);
         _handler.setCompleteAfter(-1);
-        check("RESUMED",process("wibble"));
+        response=process("wibble");
+        check(response,"DISPATCHED");
 
         _handler.setResumeAfter(100);
         _handler.setCompleteAfter(-1);
-        check("RESUMED",process("wibble"));
+        response=process("wibble");
+        check(response,"DISPATCHED");
 
         _handler.setResumeAfter(-1);
         _handler.setCompleteAfter(0);
-        check("COMPLETED",process("wibble"));
+        response=process("wibble");
+        check(response,"COMPLETED");
 
         _handler.setResumeAfter(-1);
         _handler.setCompleteAfter(100);
-        check("COMPLETED",process("wibble"));
+        response=process("wibble");
+        check(response,"COMPLETED");
 
         _handler.setRead(6);
 
         _handler.setResumeAfter(0);
         _handler.setCompleteAfter(-1);
-        check("RESUMED",process("wibble"));
+        response=process("wibble");
+        check(response,"DISPATCHED");
 
         _handler.setResumeAfter(100);
         _handler.setCompleteAfter(-1);
-        check("RESUMED",process("wibble"));
+        response=process("wibble");
+        check(response,"DISPATCHED");
 
         _handler.setResumeAfter(-1);
         _handler.setCompleteAfter(0);
-        check("COMPLETED",process("wibble"));
+        response=process("wibble");
+        check(response,"COMPLETED");
 
         _handler.setResumeAfter(-1);
         _handler.setCompleteAfter(100);
-        check("COMPLETED",process("wibble"));
+        response=process("wibble");
+        check(response,"COMPLETED");
     }
 
-    protected void check(String content,String response)
+    @Test
+    public void testTwoCycles() throws Exception
+    {
+        String response;
+
+        __completed.set(0);
+        __completed1.set(0);
+
+        _handler.setRead(0);
+        _handler.setSuspendFor(1000);
+        _handler.setResumeAfter(100);
+        _handler.setCompleteAfter(-1);
+        _handler.setSuspendFor2(1000);
+        _handler.setResumeAfter2(200);
+        _handler.setCompleteAfter2(-1);
+        response=process(null);
+        check(response,"STARTASYNC","DISPATCHED","startasync","STARTASYNC","DISPATCHED");
+        assertEquals(1,__completed.get());
+        assertEquals(0,__completed1.get());
+
+    }
+
+    protected void check(String response,String... content)
     {
         assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertTrue(response.contains(content));
+        int i=0;
+        for (String m:content)
+        {
+            i=response.indexOf(m,i);
+            assertTrue(i>=0);
+            i+=m.length();
+        }
+
     }
 
     private synchronized String process(String content) throws Exception
     {
-        String request = "GET / HTTP/1.1\r\n" + 
+        String request = "GET / HTTP/1.1\r\n" +
         "Host: localhost\r\n"+
         "Connection: close\r\n";
 
@@ -144,23 +199,346 @@
 
         return getResponse(request);
     }
-    
+
     protected String getResponse(String request) throws Exception
     {
         return ((LocalConnector)_connector).getResponses(request);
     }
 
-        
-    static ContinuationListener __asyncListener = new ContinuationListener()
+    private static class SuspendHandler extends HandlerWrapper
     {
-        public void onComplete(Continuation continuation)
+        private int _read;
+        private long _suspendFor=-1;
+        private long _resumeAfter=-1;
+        private long _completeAfter=-1;
+        private long _suspendFor2=-1;
+        private long _resumeAfter2=-1;
+        private long _completeAfter2=-1;
+
+        public SuspendHandler()
         {
         }
 
-        public void onTimeout(Continuation continuation)
+        public int getRead()
         {
-            continuation.setAttribute("TIMEOUT",Boolean.TRUE);
-            continuation.resume();
+            return _read;
         }
+
+        public void setRead(int read)
+        {
+            _read = read;
+        }
+
+        public long getSuspendFor()
+        {
+            return _suspendFor;
+        }
+
+        public void setSuspendFor(long suspendFor)
+        {
+            _suspendFor = suspendFor;
+        }
+
+        public long getResumeAfter()
+        {
+            return _resumeAfter;
+        }
+
+        public void setResumeAfter(long resumeAfter)
+        {
+            _resumeAfter = resumeAfter;
+        }
+
+        public long getCompleteAfter()
+        {
+            return _completeAfter;
+        }
+
+        public void setCompleteAfter(long completeAfter)
+        {
+            _completeAfter = completeAfter;
+        }
+
+
+
+        /* ------------------------------------------------------------ */
+        /** Get the suspendFor2.
+         * @return the suspendFor2
+         */
+        public long getSuspendFor2()
+        {
+            return _suspendFor2;
+        }
+
+
+        /* ------------------------------------------------------------ */
+        /** Set the suspendFor2.
+         * @param suspendFor2 the suspendFor2 to set
+         */
+        public void setSuspendFor2(long suspendFor2)
+        {
+            _suspendFor2 = suspendFor2;
+        }
+
+
+        /* ------------------------------------------------------------ */
+        /** Get the resumeAfter2.
+         * @return the resumeAfter2
+         */
+        public long getResumeAfter2()
+        {
+            return _resumeAfter2;
+        }
+
+
+        /* ------------------------------------------------------------ */
+        /** Set the resumeAfter2.
+         * @param resumeAfter2 the resumeAfter2 to set
+         */
+        public void setResumeAfter2(long resumeAfter2)
+        {
+            _resumeAfter2 = resumeAfter2;
+        }
+
+
+        /* ------------------------------------------------------------ */
+        /** Get the completeAfter2.
+         * @return the completeAfter2
+         */
+        public long getCompleteAfter2()
+        {
+            return _completeAfter2;
+        }
+
+
+        /* ------------------------------------------------------------ */
+        /** Set the completeAfter2.
+         * @param completeAfter2 the completeAfter2 to set
+         */
+        public void setCompleteAfter2(long completeAfter2)
+        {
+            _completeAfter2 = completeAfter2;
+        }
+
+
+        @Override
+        public void handle(String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException
+        {
+            try
+            {
+                if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType()))
+                {
+                    if (_read>0)
+                    {
+                        byte[] buf=new byte[_read];
+                        request.getInputStream().read(buf);
+                    }
+                    else if (_read<0)
+                    {
+                        InputStream in = request.getInputStream();
+                        int b=in.read();
+                        while(b!=-1)
+                            b=in.read();
+                    }
+
+
+                    final AsyncContext asyncContext = baseRequest.startAsync();
+                    response.getOutputStream().println("STARTASYNC");
+                    asyncContext.addListener(__asyncListener);
+                    asyncContext.addListener(__asyncListener1);
+                    if (_suspendFor>0)
+                        asyncContext.setTimeout(_suspendFor);
+
+
+                    if (_completeAfter>0)
+                    {
+                        new Thread() {
+                            @Override
+                            public void run()
+                            {
+                                try
+                                {
+                                    Thread.sleep(_completeAfter);
+                                    response.getOutputStream().println("COMPLETED");
+                                    response.setStatus(200);
+                                    baseRequest.setHandled(true);
+                                    asyncContext.complete();
+                                }
+                                catch(Exception e)
+                                {
+                                    e.printStackTrace();
+                                }
+                            }
+                        }.start();
+                    }
+                    else if (_completeAfter==0)
+                    {
+                        response.getOutputStream().println("COMPLETED");
+                        response.setStatus(200);
+                        baseRequest.setHandled(true);
+                        asyncContext.complete();
+                    }
+
+                    if (_resumeAfter>0)
+                    {
+                        new Thread() {
+                            @Override
+                            public void run()
+                            {
+                                try
+                                {
+                                    Thread.sleep(_resumeAfter);
+                                    if(((HttpServletRequest)asyncContext.getRequest()).getSession(true).getId()!=null)
+                                        asyncContext.dispatch();
+                                }
+                                catch(Exception e)
+                                {
+                                    e.printStackTrace();
+                                }
+                            }
+                        }.start();
+                    }
+                    else if (_resumeAfter==0)
+                    {
+                        asyncContext.dispatch();
+                    }
+                }
+                else
+                {
+                    if (request.getAttribute("TIMEOUT")!=null)
+                        response.getOutputStream().println("TIMEOUT");
+                    else
+                        response.getOutputStream().println("DISPATCHED");
+
+                    if (_suspendFor2>=0)
+                    {
+                        final AsyncContext asyncContext = baseRequest.startAsync();
+                        response.getOutputStream().println("STARTASYNC2");
+                        if (_suspendFor2>0)
+                            asyncContext.setTimeout(_suspendFor2);
+                        _suspendFor2=-1;
+
+                        if (_completeAfter2>0)
+                        {
+                            new Thread() {
+                                @Override
+                                public void run()
+                                {
+                                    try
+                                    {
+                                        Thread.sleep(_completeAfter2);
+                                        response.getOutputStream().println("COMPLETED2");
+                                        response.setStatus(200);
+                                        baseRequest.setHandled(true);
+                                        asyncContext.complete();
+                                    }
+                                    catch(Exception e)
+                                    {
+                                        e.printStackTrace();
+                                    }
+                                }
+                            }.start();
+                        }
+                        else if (_completeAfter2==0)
+                        {
+                            response.getOutputStream().println("COMPLETED2");
+                            response.setStatus(200);
+                            baseRequest.setHandled(true);
+                            asyncContext.complete();
+                        }
+
+                        if (_resumeAfter2>0)
+                        {
+                            new Thread() {
+                                @Override
+                                public void run()
+                                {
+                                    try
+                                    {
+                                        Thread.sleep(_resumeAfter2);
+                                        asyncContext.dispatch();
+                                    }
+                                    catch(Exception e)
+                                    {
+                                        e.printStackTrace();
+                                    }
+                                }
+                            }.start();
+                        }
+                        else if (_resumeAfter2==0)
+                        {
+                            asyncContext.dispatch();
+                        }
+                    }
+                    else
+                    {
+                        response.setStatus(200);
+                        baseRequest.setHandled(true);
+                    }
+                }
+            }
+            finally
+            {
+            }
+        }
+    }
+
+    static AtomicInteger __completed = new AtomicInteger();
+    static AtomicInteger __completed1 = new AtomicInteger();
+
+    private static AsyncListener __asyncListener = new AsyncListener()
+    {
+
+        @Override
+        public void onComplete(AsyncEvent event) throws IOException
+        {
+            __completed.incrementAndGet();
+        }
+
+        @Override
+        public void onError(AsyncEvent event) throws IOException
+        {
+            __completed.incrementAndGet();
+        }
+
+        @Override
+        public void onStartAsync(AsyncEvent event) throws IOException
+        {
+            event.getSuppliedResponse().getOutputStream().println("startasync");
+            event.getAsyncContext().addListener(this);
+        }
+
+        @Override
+        public void onTimeout(AsyncEvent event) throws IOException
+        {
+            event.getSuppliedRequest().setAttribute("TIMEOUT",Boolean.TRUE);
+            event.getAsyncContext().dispatch();
+        }
+
+    };
+
+    private static AsyncListener __asyncListener1 = new AsyncListener()
+    {
+
+        @Override
+        public void onComplete(AsyncEvent event) throws IOException
+        {
+            __completed1.incrementAndGet();
+        }
+
+        @Override
+        public void onError(AsyncEvent event) throws IOException
+        {
+        }
+        @Override
+        public void onStartAsync(AsyncEvent event) throws IOException
+        {
+        }
+
+        @Override
+        public void onTimeout(AsyncEvent event) throws IOException
+        {
+        }
+
     };
 }
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 c82deb3..b897f4f 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
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -36,10 +37,13 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.servlet.MultipartConfigElement;
 import javax.servlet.ServletException;
+import javax.servlet.ServletRequestEvent;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.Part;
 
 import junit.framework.Assert;
 
@@ -47,6 +51,7 @@
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.MultiPartInputStream;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.junit.After;
@@ -127,6 +132,113 @@
         assertTrue(responses.startsWith("HTTP/1.1 200"));
 
     }
+    
+    @Test
+    public void testMultiPartNoConfig() throws Exception
+    {
+        _handler._checker = new RequestTester()
+        {
+            public boolean check(HttpServletRequest request,HttpServletResponse response)
+            {
+                try
+                {
+                    Part foo = request.getPart("stuff");
+                    return false;
+                }
+                catch (IllegalStateException e)
+                {
+                    //expected exception because no multipart config is set up
+                    assertTrue(e.getMessage().startsWith("No multipart config"));
+                    return true;
+                }
+                catch (Exception e)
+                {
+                    return false;
+                }
+            }
+        };
+        
+        String multipart =  "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"field1\"\r\n"+
+        "\r\n"+
+        "Joe Blow\r\n"+
+        "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"\r\n"+
+        "Content-Type: text/plain;charset=ISO-8859-1\r\n"+
+        "\r\n"+
+        "000000000000000000000000000000000000000000000000000\r\n"+
+        "--AaB03x--\r\n";
+        
+        String request="GET / HTTP/1.1\r\n"+
+        "Host: whatever\r\n"+
+        "Content-Type: multipart/form-data; boundary=\"AaB03x\"\r\n"+
+        "Content-Length: "+multipart.getBytes().length+"\r\n"+
+        "\r\n"+
+        multipart;
+
+        String responses=_connector.getResponses(request);
+        assertTrue(responses.startsWith("HTTP/1.1 200"));
+    }
+    
+    
+    @Test
+    public void testMultiPart() throws Exception
+    {
+        final File tmpDir = new File (System.getProperty("java.io.tmpdir"));
+        final File testTmpDir = new File (tmpDir, "reqtest");
+        testTmpDir.deleteOnExit();
+        assertTrue(testTmpDir.mkdirs());
+        assertTrue(testTmpDir.list().length == 0);
+        
+        ContextHandler contextHandler = new ContextHandler();
+        contextHandler.setContextPath("/foo");
+        contextHandler.setResourceBase(".");
+        contextHandler.setHandler(new MultiPartRequestHandler(testTmpDir));
+        contextHandler.addEventListener(new Request.MultiPartCleanerListener()
+        {
+
+            @Override
+            public void requestDestroyed(ServletRequestEvent sre)
+            {
+                MultiPartInputStream m = (MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM);
+                ContextHandler.Context c = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT);
+                assertNotNull (m);
+                assertNotNull (c);
+                assertTrue(c == sre.getServletContext());
+                assertTrue(!m.getParsedParts().isEmpty());
+                assertTrue(testTmpDir.list().length == 2);
+                super.requestDestroyed(sre);
+                String[] files = testTmpDir.list();
+                assertTrue(files.length == 0);
+            }
+            
+        });
+        _server.stop();
+        _server.setHandler(contextHandler);
+        _server.start();
+        
+        String multipart =  "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"field1\"\r\n"+
+        "\r\n"+
+        "Joe Blow\r\n"+
+        "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"; filename=\"foo.upload\"\r\n"+
+        "Content-Type: text/plain;charset=ISO-8859-1\r\n"+
+        "\r\n"+
+        "000000000000000000000000000000000000000000000000000\r\n"+
+        "--AaB03x--\r\n";
+        
+        String request="GET /foo/x.html HTTP/1.1\r\n"+
+        "Host: whatever\r\n"+
+        "Content-Type: multipart/form-data; boundary=\"AaB03x\"\r\n"+
+        "Content-Length: "+multipart.getBytes().length+"\r\n"+
+        "\r\n"+
+        multipart;
+
+        String responses=_connector.getResponses(request);
+        System.err.println(responses);
+        assertTrue(responses.startsWith("HTTP/1.1 200"));
+    }
 
     @Test
     public void testBadUtf8ParamExtraction() throws Exception
@@ -670,10 +782,12 @@
         assertNotSame(cookies.get(1), cookies.get(3));
 
         cookies.clear();
+//NOTE: the javax.servlet.http.Cookie class sets the system property org.glassfish.web.rfc2109_cookie_names_enforced
+//to TRUE by default, and rejects all cookie names containing punctuation.Therefore this test cannot use "name2".
         response=_connector.getResponses(
                 "POST / HTTP/1.1\r\n"+
                 "Host: whatever\r\n"+
-                "Cookie: name0=value0; name1 = value1 ; \"\\\"name2\\\"\"  =  \"\\\"value2\\\"\"  \n" +
+                "Cookie: name0=value0; name1 = value1 ; \"name2\"  =  \"\\\"value2\\\"\"  \n" +
                 "Cookie: $Version=2; name3=value3=value3;$path=/path;$domain=acme.com;$port=8080; name4=; name5 =  ; name6\n" +
                 "Cookie: name7=value7;\n" +
                 "Connection: close\r\n"+
@@ -683,7 +797,7 @@
         assertEquals("value0", cookies.get(0).getValue());
         assertEquals("name1", cookies.get(1).getName());
         assertEquals("value1", cookies.get(1).getValue());
-        assertEquals("\"name2\"", cookies.get(2).getName());
+        assertEquals("name2", cookies.get(2).getName());
         assertEquals("\"value2\"", cookies.get(2).getValue());
         assertEquals("name3", cookies.get(3).getName());
         assertEquals("value3=value3", cookies.get(3).getValue());
@@ -850,7 +964,9 @@
         {
             ((Request)request).setHandled(true);
 
-            if (request.getContentLength()>0 && !MimeTypes.FORM_ENCODED.equals(request.getContentType()))
+            if (request.getContentLength()>0 
+                    && !MimeTypes.FORM_ENCODED.equals(request.getContentType()) 
+                    && !request.getContentType().startsWith("multipart/form-data"))
                 _content=IO.toString(request.getInputStream());
 
             if (_checker!=null && _checker.check(request,response))
@@ -861,4 +977,45 @@
 
         }
     }
+    
+    private class MultiPartRequestHandler extends AbstractHandler
+    {
+        File tmpDir;
+        
+        public MultiPartRequestHandler(File tmpDir)
+        {
+            this.tmpDir = tmpDir;
+        }
+        
+        
+        @Override
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+        {
+            ((Request)request).setHandled(true);
+            try
+            { 
+
+                MultipartConfigElement mpce = new MultipartConfigElement(tmpDir.getAbsolutePath(),-1, -1, 2);
+                request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce);
+               
+                String field1 = request.getParameter("field1");
+                assertNotNull(field1);
+                
+                Part foo = request.getPart("stuff");
+                assertNotNull(foo);
+                assertTrue(foo.getSize() > 0);
+                response.setStatus(200);
+            }
+            catch (IllegalStateException e)
+            {
+                //expected exception because no multipart config is set up
+                assertTrue(e.getMessage().startsWith("No multipart config"));
+                response.setStatus(200);
+            }
+            catch (Exception e)
+            {
+                response.sendError(500);
+            }
+        }
+    }
 }
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 91bb91c..b853cf4 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
@@ -32,6 +32,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
 
@@ -57,6 +58,7 @@
 import org.eclipse.jetty.server.session.AbstractSessionManager;
 import org.eclipse.jetty.server.session.HashSessionIdManager;
 import org.eclipse.jetty.server.session.HashSessionManager;
+import org.eclipse.jetty.util.StringUtil;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -73,6 +75,7 @@
     public void init() throws Exception
     {
         server = new Server();
+        server.setSendServerVersion(false);
         connector = new LocalConnector();
         server.addConnector(connector);
         server.setHandler(new DumpHandler());
@@ -104,14 +107,15 @@
         response.setContentType("foo2/bar2");
         assertEquals("foo2/bar2;charset=ISO-8859-1",response.getContentType());
         response.setHeader("name","foo");
-        Enumeration<?> en=response.getHeaders("name");
-        assertEquals("foo",en.nextElement());
-        assertFalse(en.hasMoreElements());
+
+        Iterator<String> en = response.getHeaders("name").iterator();
+        assertEquals("foo",en.next());
+        assertFalse(en.hasNext());
         response.addHeader("name","bar");
-        en=response.getHeaders("name");
-        assertEquals("foo",en.nextElement());
-        assertEquals("bar",en.nextElement());
-        assertFalse(en.hasMoreElements());
+        en=response.getHeaders("name").iterator();
+        assertEquals("foo",en.next());
+        assertEquals("bar",en.next());
+        assertFalse(en.hasNext());
 
         response.recycle();
 
@@ -418,8 +422,45 @@
         assertEquals("/foo;jsessionid=12345", response.encodeURL("/foo"));
         assertEquals("/;jsessionid=12345", response.encodeURL("/"));
         assertEquals("/foo.html;jsessionid=12345#target", response.encodeURL("/foo.html#target"));
-        assertEquals(";jsessionid=12345", response.encodeURL(""));
-        
+        assertEquals(";jsessionid=12345", response.encodeURL("")); 
+    }
+
+    @Test
+    public void testCanonicalSendRedirect() throws Exception
+    {
+        ByteArrayEndPoint out=new ByteArrayEndPoint(new byte[]{},4096);
+        AbstractHttpConnection connection=new TestHttpConnection(connector,out, connector.getServer());
+        Response response = new Response(connection);
+        Request request = connection.getRequest();
+        request.setServerName("myhost");
+        request.setServerPort(8888);
+        request.setRequestURI("/path/test/info/");
+        request.setContextPath("/path");
+        request.setServletPath("/test");
+        request.setPathInfo("/info/");
+
+        response.sendRedirect("../other%2Fpath");
+        String location = response.getHeader("Location");
+        assertEquals("http://myhost:8888/path/test/other%2Fpath",location);
+    }
+    
+    @Test
+    public void testSendServerVersion() throws Exception
+    {
+        ByteArrayEndPoint out=new ByteArrayEndPoint(new byte[]{},4096);
+        AbstractHttpConnection connection=new TestHttpConnection(connector,out, connector.getServer());
+        Response response = new Response(connection);
+        Request request = connection.getRequest();
+        request.setServerName("myhost");
+        request.setServerPort(8888);
+        request.setRequestURI("/oops/");
+        request.setContextPath("/");
+        request.setServletPath("/");
+        request.setPathInfo("/info/");
+
+        response.sendError(500, "Ooops");
+        ByteArrayBuffer output = out.getOut();
+        assertFalse("Contains jetty://", output.toString(StringUtil.__UTF8_CHARSET).contains("jetty://"));
     }
 
     @Test
@@ -442,7 +483,8 @@
                 {"l%20cation","http://myhost:8888/path/l%20cation"},
                 {"./l%20cation","http://myhost:8888/path/l%20cation"},
                 {"../l%20cation","http://myhost:8888/l%20cation"},
-                {"../locati%C3%abn","http://myhost:8888/locati%C3%ABn"},
+                {"../locati%C3%abn","http://myhost:8888/locati%C3%abn"},
+                {"../other%2fplace","http://myhost:8888/other%2fplace"},
         };
         
         for (int i=0;i<tests.length;i++)
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelTimeoutTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelTimeoutTest.java
index fa3b2e2..3ebf08f 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelTimeoutTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelTimeoutTest.java
@@ -18,8 +18,6 @@
 
 package org.eclipse.jetty.server;
 
-import static org.junit.Assert.assertTrue;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
@@ -32,6 +30,8 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import static org.junit.Assert.assertTrue;
+
 public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
 {
 
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/SuspendHandler.java b/jetty-server/src/test/java/org/eclipse/jetty/server/SuspendHandler.java
index 1ffe892..fbca306 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/SuspendHandler.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/SuspendHandler.java
@@ -20,14 +20,17 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-
+import javax.servlet.AsyncContext;
+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.handler.HandlerWrapper;
 
-class SuspendHandler extends HandlerWrapper
+class SuspendHandler extends HandlerWrapper implements AsyncListener
 {
     private int _read;
     private long _suspendFor=-1;
@@ -77,7 +80,7 @@
     {
         _completeAfter = completeAfter;
     }
-    
+
     @Override
     public void handle(String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException
     {
@@ -97,7 +100,7 @@
             }
 
             final AsyncContext asyncContext = baseRequest.startAsync();
-            asyncContext.addContinuationListener(LocalAsyncContextTest.__asyncListener);
+            asyncContext.addListener(this);
             if (_suspendFor>0)
                 asyncContext.setTimeout(_suspendFor);
 
@@ -110,7 +113,7 @@
                         try
                         {
                             Thread.sleep(_completeAfter);
-                            response.getOutputStream().print("COMPLETED");
+                            response.getOutputStream().println("COMPLETED");
                             response.setStatus(200);
                             baseRequest.setHandled(true);
                             asyncContext.complete();
@@ -124,7 +127,7 @@
             }
             else if (_completeAfter==0)
             {
-                response.getOutputStream().print("COMPLETED");
+                response.getOutputStream().println("COMPLETED");
                 response.setStatus(200);
                 baseRequest.setHandled(true);
                 asyncContext.complete();
@@ -167,4 +170,25 @@
         }
     }
 
+    @Override
+    public void onComplete(AsyncEvent asyncEvent) throws IOException
+    {
+    }
+
+    @Override
+    public void onTimeout(AsyncEvent asyncEvent) throws IOException
+    {
+        asyncEvent.getSuppliedRequest().setAttribute("TIMEOUT",Boolean.TRUE);
+        asyncEvent.getAsyncContext().dispatch();
+    }
+
+    @Override
+    public void onError(AsyncEvent asyncEvent) throws IOException
+    {
+    }
+
+    @Override
+    public void onStartAsync(AsyncEvent asyncEvent) throws IOException
+    {
+    }
 }
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
new file mode 100644
index 0000000..3a8af17
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.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.server.session;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+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);
+        }
+        
+    }
+    
+    public class MockSessionIdManager extends AbstractSessionIdManager
+    {
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionIdManager#idInUse(java.lang.String)
+         */
+        public boolean idInUse(String id)
+        {
+            return false;
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionIdManager#addSession(javax.servlet.http.HttpSession)
+         */
+        public void addSession(HttpSession session)
+        {
+           
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionIdManager#removeSession(javax.servlet.http.HttpSession)
+         */
+        public void removeSession(HttpSession session)
+        {
+             
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionIdManager#invalidateAll(java.lang.String)
+         */
+        public void invalidateAll(String id)
+        {
+           
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionIdManager#getClusterId(java.lang.String)
+         */
+        public String getClusterId(String nodeId)
+        {
+            int dot=nodeId.lastIndexOf('.');
+            return (dot>0)?nodeId.substring(0,dot):nodeId;
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionIdManager#getNodeId(java.lang.String, javax.servlet.http.HttpServletRequest)
+         */
+        public String getNodeId(String clusterId, HttpServletRequest request)
+        {
+            return clusterId+'.'+_workerName;
+        }
+
+    }
+    
+    public class MockSessionManager extends AbstractSessionManager
+    {
+
+        /** 
+         * @see org.eclipse.jetty.server.session.AbstractSessionManager#addSession(org.eclipse.jetty.server.session.AbstractSession)
+         */
+        protected void addSession(AbstractSession session)
+        {
+            
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.session.AbstractSessionManager#getSession(java.lang.String)
+         */
+        public AbstractSession getSession(String idInCluster)
+        {
+            return null;
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.session.AbstractSessionManager#invalidateSessions()
+         */
+        protected void invalidateSessions() throws Exception
+        {
+            
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.session.AbstractSessionManager#newSession(javax.servlet.http.HttpServletRequest)
+         */
+        protected AbstractSession newSession(HttpServletRequest request)
+        {
+            return null;
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.session.AbstractSessionManager#removeSession(java.lang.String)
+         */
+        protected boolean removeSession(String idInCluster)
+        {
+            return false;
+        }
+        
+    }
+    
+    @Test
+    public void testSecureSessionCookie () throws Exception
+    {
+        MockSessionIdManager idMgr = new MockSessionIdManager();
+        idMgr.setWorkerName("node1");
+        MockSessionManager mgr = new MockSessionManager();
+        mgr.setSessionIdManager(idMgr);
+        MockSession session = new MockSession(mgr, System.currentTimeMillis(), System.currentTimeMillis(), "node1123"); //clusterId
+        
+        SessionCookieConfig sessionCookieConfig = mgr.getSessionCookieConfig();
+        sessionCookieConfig.setSecure(true);
+        
+        //sessionCookieConfig.secure == true, always mark cookie as secure, irrespective of if requestIsSecure
+        HttpCookie cookie = mgr.getSessionCookie(session, "/foo", true);
+        assertTrue(cookie.isSecure());
+        //sessionCookieConfig.secure == true, always mark cookie as secure, irrespective of if requestIsSecure
+        cookie = mgr.getSessionCookie(session, "/foo", false);
+        assertTrue(cookie.isSecure());
+        
+        //sessionCookieConfig.secure==false, setSecureRequestOnly==true, requestIsSecure==true
+        //cookie should be secure: see SessionCookieConfig.setSecure() javadoc
+        sessionCookieConfig.setSecure(false);
+        cookie = mgr.getSessionCookie(session, "/foo", true);
+        assertTrue(cookie.isSecure());
+        
+        //sessionCookieConfig.secure=false, setSecureRequestOnly==true, requestIsSecure==false
+        //cookie is not secure: see SessionCookieConfig.setSecure() javadoc
+        cookie = mgr.getSessionCookie(session, "/foo", false);
+        assertFalse(cookie.isSecure());
+        
+        //sessionCookieConfig.secure=false, setSecureRequestOnly==false, requestIsSecure==false
+        //cookie is not secure: not a secure request
+        mgr.setSecureRequestOnly(false);
+        cookie = mgr.getSessionCookie(session, "/foo", false);
+        assertFalse(cookie.isSecure());
+        
+        //sessionCookieConfig.secure=false, setSecureRequestOnly==false, requestIsSecure==true
+        //cookie is not secure: not on secured requests and request is secure
+        cookie = mgr.getSessionCookie(session, "/foo", true);
+        assertFalse(cookie.isSecure());
+        
+        
+    }
+
+}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
index 690cbfe..82a6b18 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
@@ -26,20 +26,29 @@
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.security.Principal;
+import java.util.Collection;
 import java.util.Enumeration;
 import java.util.EventListener;
 import java.util.Locale;
 import java.util.Map;
-
+import java.util.Set;
+import javax.servlet.AsyncContext;
 import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
+import javax.servlet.DispatcherType;
 
 import org.eclipse.jetty.http.HttpCookie;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.SessionIdManager;
 import org.eclipse.jetty.server.SessionManager;
@@ -68,6 +77,98 @@
         SessionHandler sessionHandler = new SessionHandler();
         sessionHandler.setSessionManager(new MockSessionManager()
         {
+ 
+            
+            public SessionCookieConfig getSessionCookieConfig()
+            {
+                return new SessionCookieConfig()
+                {
+
+                    public String getComment()
+                    {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    public String getDomain()
+                    {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    public int getMaxAge()
+                    {
+                        // TODO Auto-generated method stub
+                        return 0;
+                    }
+
+                    public String getName()
+                    {
+                        return cookieName;
+                    }
+
+                    public String getPath()
+                    {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    public boolean isHttpOnly()
+                    {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    public boolean isSecure()
+                    {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    public void setComment(String comment)
+                    {
+                        // TODO Auto-generated method stub
+                        
+                    }
+
+                    public void setDomain(String domain)
+                    {
+                        // TODO Auto-generated method stub
+                        
+                    }
+
+                    public void setHttpOnly(boolean httpOnly)
+                    {
+                        // TODO Auto-generated method stub
+                        
+                    }
+
+                    public void setMaxAge(int maxAge)
+                    {
+                        // TODO Auto-generated method stub
+                        
+                    }
+
+                    public void setName(String name)
+                    {
+                        // TODO Auto-generated method stub
+                        
+                    }
+
+                    public void setPath(String path)
+                    {
+                        // TODO Auto-generated method stub
+                        
+                    }
+
+                    public void setSecure(boolean secure)
+                    {
+                        // TODO Auto-generated method stub
+                        
+                    }
+                    
+                };
+            }
             public boolean isUsingCookies()
             {
                 return true;
@@ -104,7 +205,8 @@
 
         SessionHandler sessionHandler = new SessionHandler();
         sessionHandler.setSessionManager(new MockSessionManager()
-        {
+        {       
+
             @Override
             public String getSessionIdPathParameterName()
             {
@@ -396,6 +498,114 @@
         public void setCharacterEncoding(String env) throws UnsupportedEncodingException
         {
         }
+
+        /** 
+         * @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse)
+         */
+        public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
+        {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        /** 
+         * @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String)
+         */
+        public Part getPart(String name) throws IOException, ServletException
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        /** 
+         * @see javax.servlet.http.HttpServletRequest#getParts()
+         */
+        public Collection<Part> getParts() throws IOException, ServletException
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        /** 
+         * @see javax.servlet.http.HttpServletRequest#login(java.lang.String, java.lang.String)
+         */
+        public void login(String username, String password) throws ServletException
+        {
+            // TODO Auto-generated method stub
+            
+        }
+
+        /** 
+         * @see javax.servlet.http.HttpServletRequest#logout()
+         */
+        public void logout() throws ServletException
+        {
+            // TODO Auto-generated method stub
+            
+        }
+
+        /** 
+         * @see javax.servlet.ServletRequest#getAsyncContext()
+         */
+        public AsyncContext getAsyncContext()
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        /** 
+         * @see javax.servlet.ServletRequest#getDispatcherType()
+         */
+        public DispatcherType getDispatcherType()
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        /** 
+         * @see javax.servlet.ServletRequest#getServletContext()
+         */
+        public ServletContext getServletContext()
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        /** 
+         * @see javax.servlet.ServletRequest#isAsyncStarted()
+         */
+        public boolean isAsyncStarted()
+        {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        /** 
+         * @see javax.servlet.ServletRequest#isAsyncSupported()
+         */
+        public boolean isAsyncSupported()
+        {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        /** 
+         * @see javax.servlet.ServletRequest#startAsync()
+         */
+        public AsyncContext startAsync() throws IllegalStateException
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        /** 
+         * @see javax.servlet.ServletRequest#startAsync(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
+         */
+        public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
     }
 
     /**
@@ -592,6 +802,50 @@
         {
         }
 
+        /** 
+         * @see org.eclipse.jetty.server.SessionManager#getDefaultSessionTrackingModes()
+         */
+        public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionManager#getEffectiveSessionTrackingModes()
+         */
+        public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
+        {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionManager#getSessionCookieConfig()
+         */
+        public SessionCookieConfig getSessionCookieConfig()
+        {
+            return null;
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionManager#isUsingURLs()
+         */
+        public boolean isUsingURLs()
+        {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        /** 
+         * @see org.eclipse.jetty.server.SessionManager#setSessionTrackingModes(java.util.Set)
+         */
+        public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
+        {
+            // TODO Auto-generated method stub
+            
+        }
+
         private boolean _checkRemote=false;
 
         public boolean isCheckingRemoteSessionIdEncoding()
diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml
index af848b8..bd8f62d 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-servlet</artifactId>
@@ -26,7 +26,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>org.eclipse.jetty.jmx.*;version="[7.3,8)";resolution:=optional,*</Import-Package>
+                <Import-Package>javax.servlet.*;version="2.6.0",org.eclipse.jetty.jmx.*;version="8.0";resolution:=optional,*</Import-Package>
               </instructions>
             </configuration>
            </execution>
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
index c3ba685..580293c 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
@@ -18,25 +18,18 @@
 
 package org.eclipse.jetty.servlet;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.http.HttpMethods;
-import org.eclipse.jetty.server.AbstractHttpConnection;
-import org.eclipse.jetty.server.Dispatcher;
-import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.ErrorHandler;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
 
 /* ------------------------------------------------------------ */
 /** Error Page Error Handler
@@ -45,11 +38,8 @@
  * the internal ERROR style of dispatch.
  *
  */
-public class ErrorPageErrorHandler extends ErrorHandler
+public class ErrorPageErrorHandler extends ErrorHandler implements ErrorHandler.ErrorPageMapper
 {
-    private static final Logger LOG = Log.getLogger(ErrorPageErrorHandler.class);
-
-    public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
     public final static String GLOBAL_ERROR_PAGE = "org.eclipse.jetty.server.error_page.global";
 
     protected ServletContext _servletContext;
@@ -60,104 +50,63 @@
     public ErrorPageErrorHandler()
     {}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.server.handler.ErrorHandler#handle(String, Request, HttpServletRequest, HttpServletResponse)
-     */
     @Override
-    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
+    public String getErrorPage(HttpServletRequest request)
     {
-        String method = request.getMethod();
-        if(!method.equals(HttpMethods.GET) && !method.equals(HttpMethods.POST) && !method.equals(HttpMethods.HEAD))
+        String error_page= null;
+        Class<?> exClass= (Class<?>)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
+
+        if (ServletException.class.equals(exClass))
         {
-            AbstractHttpConnection.getCurrentConnection().getRequest().setHandled(true);
-            return;
+            error_page= (String)_errorPages.get(exClass.getName());
+            if (error_page == null)
+            {
+                Throwable th= (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
+                while (th instanceof ServletException)
+                    th= ((ServletException)th).getRootCause();
+                if (th != null)
+                    exClass= th.getClass();
+            }
         }
-        if (_errorPages!=null)
+
+        while (error_page == null && exClass != null )
         {
-            String error_page= null;
-            Class<?> exClass= (Class<?>)request.getAttribute(Dispatcher.ERROR_EXCEPTION_TYPE);
+            error_page= (String)_errorPages.get(exClass.getName());
+            exClass= exClass.getSuperclass();
+        }
 
-            if (ServletException.class.equals(exClass))
+        if (error_page == null)
+        {
+            // look for an exact code match
+            Integer code=(Integer)request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
+            if (code!=null)
             {
-                error_page= (String)_errorPages.get(exClass.getName());
-                if (error_page == null)
+                error_page= (String)_errorPages.get(Integer.toString(code));
+
+                // if still not found
+                if ((error_page == null) && (_errorPageList != null))
                 {
-                    Throwable th= (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
-                    while (th instanceof ServletException)
-                        th= ((ServletException)th).getRootCause();
-                    if (th != null)
-                        exClass= th.getClass();
-                }
-            }
-
-            while (error_page == null && exClass != null )
-            {
-                error_page= (String)_errorPages.get(exClass.getName());
-                exClass= exClass.getSuperclass();
-            }
-
-            if (error_page == null)
-            {
-                // look for an exact code match
-                Integer code=(Integer)request.getAttribute(Dispatcher.ERROR_STATUS_CODE);
-                if (code!=null)
-                {
-                    error_page= (String)_errorPages.get(Integer.toString(code));
-
-                    // if still not found
-                    if ((error_page == null) && (_errorPageList != null))
+                    // look for an error code range match.
+                    for (int i = 0; i < _errorPageList.size(); i++)
                     {
-                        // look for an error code range match.
-                        for (int i = 0; i < _errorPageList.size(); i++)
+                        ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i);
+                        if (errCode.isInRange(code))
                         {
-                            ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i);
-                            if (errCode.isInRange(code))
-                            {
-                                error_page = errCode.getUri();
-                                break;
-                            }
+                            error_page = errCode.getUri();
+                            break;
                         }
                     }
                 }
             }
-            
-            //try new servlet 3.0 global error page
-            if (error_page == null)
-            {
-                error_page = _errorPages.get(GLOBAL_ERROR_PAGE);
-            }
-
-            if (error_page!=null)
-            {
-                String old_error_page=(String)request.getAttribute(ERROR_PAGE);
-                if (old_error_page==null || !old_error_page.equals(error_page))
-                {
-                    request.setAttribute(ERROR_PAGE, error_page);
-
-                    Dispatcher dispatcher = (Dispatcher) _servletContext.getRequestDispatcher(error_page);
-                    try
-                    {
-                        if(dispatcher!=null)
-                        {
-                            dispatcher.error(request, response);
-                            return;
-                        }
-                        else
-                        {
-                            LOG.warn("No error page "+error_page);
-                        }
-                    }
-                    catch (ServletException e)
-                    {
-                        LOG.warn(Log.EXCEPTION, e);
-                        return;
-                    }
-                }
-            }
         }
 
-        super.handle(target, baseRequest, request, response);
+        //try new servlet 3.0 global error page
+        if (error_page == null)
+        {
+            error_page = _errorPages.get(GLOBAL_ERROR_PAGE);
+        }
+
+        return error_page;
     }
 
     /* ------------------------------------------------------------ */
@@ -238,14 +187,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    @Override
-    protected void doStop() throws Exception
-    {
-        // TODO Auto-generated method stub
-        super.doStop();
-    }
-
-    /* ------------------------------------------------------------ */
     /* ------------------------------------------------------------ */
     private class ErrorCodeRange
     {
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 6e96ae8..5138899 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
@@ -24,12 +24,13 @@
 import java.util.EnumSet;
 import java.util.List;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.FilterConfig;
+import javax.servlet.FilterRegistration;
 import javax.servlet.ServletException;
 
-import org.eclipse.jetty.server.DispatcherType;
-import org.eclipse.jetty.servlet.api.FilterRegistration;
+import org.eclipse.jetty.servlet.Holder.Source;
 import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -52,14 +53,23 @@
      */
     public FilterHolder()
     {
+        this(Source.EMBEDDED);
     }   
- 
+    
+    /* ---------------------------------------------------------------- */
+    /** Constructor 
+     */
+    public FilterHolder(Holder.Source source)
+    {
+        super(source);
+    }   
     
     /* ---------------------------------------------------------------- */
     /** Constructor 
      */
     public FilterHolder(Class<? extends Filter> filter)
     {
+        this(Source.EMBEDDED);
         setHeldClass(filter);
     }
 
@@ -68,6 +78,7 @@
      */
     public FilterHolder(Filter filter)
     {
+        this(Source.EMBEDDED);
         setFilter(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 fdab6b0..15c946e 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
@@ -21,8 +21,8 @@
 import java.io.IOException;
 import java.util.EnumSet;
 
+import javax.servlet.DispatcherType;
 import org.eclipse.jetty.http.PathMap;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.util.component.AggregateLifeCycle;
@@ -172,7 +172,22 @@
         }
     }
     
-    
+    /* ------------------------------------------------------------ */
+    public EnumSet<DispatcherType> getDispatcherTypes()
+    {
+        EnumSet<DispatcherType> dispatcherTypes = EnumSet.noneOf(DispatcherType.class);
+        if ((_dispatches & ERROR) == ERROR)
+            dispatcherTypes.add(DispatcherType.ERROR);
+        if ((_dispatches & FORWARD) == FORWARD)
+            dispatcherTypes.add(DispatcherType.FORWARD);
+        if ((_dispatches & INCLUDE) == INCLUDE)
+            dispatcherTypes.add(DispatcherType.INCLUDE);
+        if ((_dispatches & REQUEST) == REQUEST)
+            dispatcherTypes.add(DispatcherType.REQUEST);
+        if ((_dispatches & ASYNC) == ASYNC)
+            dispatcherTypes.add(DispatcherType.ASYNC);
+        return dispatcherTypes;
+    }
     
     /* ------------------------------------------------------------ */
     /**
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 1a83087..c19778c 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
@@ -26,11 +26,11 @@
 import java.util.Map;
 import java.util.Set;
 
+import javax.servlet.Registration;
 import javax.servlet.ServletContext;
 import javax.servlet.UnavailableException;
 
 import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.servlet.api.Registration;
 import org.eclipse.jetty.util.Loader;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.component.AggregateLifeCycle;
@@ -45,6 +45,8 @@
  */
 public class Holder<T> extends AbstractLifeCycle implements Dumpable
 {
+    public enum Source { EMBEDDED, JAVAX_API, DESCRIPTOR, ANNOTATION };
+    final private Source _source;
     private static final Logger LOG = Log.getLogger(Holder.class);
 
     protected transient Class<? extends T> _class;
@@ -52,17 +54,33 @@
     protected String _className;
     protected String _displayName;
     protected boolean _extInstance;
-    protected boolean _asyncSupported=true;
+    protected boolean _asyncSupported;
 
     /* ---------------------------------------------------------------- */
     protected String _name;
     protected ServletHandler _servletHandler;
 
     /* ---------------------------------------------------------------- */
-    protected Holder()
+    protected Holder(Source source)
     {
+        _source=source;
+        switch(_source)
+        {
+            case JAVAX_API:
+            case DESCRIPTOR:
+            case ANNOTATION:
+                _asyncSupported=false;
+                break;
+            default:
+                _asyncSupported=true;
+        }
     }
-
+    
+    public Source getSource()
+    {
+        return _source;
+    }
+    
     /* ------------------------------------------------------------ */
     /**
      * @return True if this holder was created for a specific instance.
@@ -79,7 +97,7 @@
     {
         //if no class already loaded and no classname, make servlet permanently unavailable
         if (_class==null && (_className==null || _className.equals("")))
-            throw new UnavailableException("No class for Servlet or Filter", -1);
+            throw new UnavailableException("No class for Servlet or Filter for "+_name);
         
         //try to load class
         if (_class==null)
@@ -93,7 +111,7 @@
             catch (Exception e)
             {
                 LOG.warn(e);
-                throw new UnavailableException(e.getMessage(), -1);
+                throw new UnavailableException(e.getMessage());
             }
         }
     }
@@ -343,6 +361,12 @@
         public boolean setInitParameter(String name, String value)
         {
             illegalStateIfContextStarted();
+            if (name == null) {
+                throw new IllegalArgumentException("init parameter name required");
+            }
+            if (value == null) {
+                throw new IllegalArgumentException("non-null value required for init parameter " + name);
+            }
             if (Holder.this.getInitParameter(name)!=null)
                 return false;
             Holder.this.setInitParameter(name,value);
@@ -353,20 +377,28 @@
         {
             illegalStateIfContextStarted();
             Set<String> clash=null;
-            for (String name : initParameters.keySet())
+            for (Map.Entry<String, String> entry : initParameters.entrySet())
             {
-                if (Holder.this.getInitParameter(name)!=null)
+                if (entry.getKey() == null) {
+                    throw new IllegalArgumentException("init parameter name required");
+                }
+                if (entry.getValue() == null) {
+                    throw new IllegalArgumentException("non-null value required for init parameter " + entry.getKey());
+                }
+                if (Holder.this.getInitParameter(entry.getKey())!=null)
                 {
                     if (clash==null)
                         clash=new HashSet<String>();
-                    clash.add(name);
+                    clash.add(entry.getKey());
                 }
             }
             if (clash!=null)
                 return clash;
-            Holder.this.setInitParameters(initParameters);
+            Holder.this.getInitParameters().putAll(initParameters);
             return Collections.emptySet();
-        }; 
+        }
+        
+        
     }
 }
 
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 59eeeae..a29b9dc 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
@@ -20,6 +20,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.EventListener;
@@ -29,19 +30,28 @@
 import java.util.Map;
 import java.util.Set;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
+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;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
+import javax.servlet.descriptor.JspPropertyGroupDescriptor;
+import javax.servlet.descriptor.TaglibDescriptor;
 
 import org.eclipse.jetty.security.ConstraintAware;
+import org.eclipse.jetty.security.ConstraintMapping;
 import org.eclipse.jetty.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.security.SecurityHandler;
 import org.eclipse.jetty.server.Dispatcher;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HandlerContainer;
 import org.eclipse.jetty.server.handler.ContextHandler;
@@ -49,9 +59,8 @@
 import org.eclipse.jetty.server.handler.HandlerCollection;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.server.session.SessionHandler;
-import org.eclipse.jetty.servlet.api.FilterRegistration;
-import org.eclipse.jetty.servlet.api.ServletRegistration;
-import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.LazyList;
+import org.eclipse.jetty.util.security.Constraint;
 
 
 /* ------------------------------------------------------------ */
@@ -79,8 +88,10 @@
     protected ServletHandler _servletHandler;
     protected HandlerWrapper _wrapper;
     protected int _options;
+    protected JspConfigDescriptor _jspConfig;
     protected Object _restrictedContextListeners;
-    
+    private boolean _restrictListeners = true;
+
     /* ------------------------------------------------------------ */
     public ServletContextHandler()
     {
@@ -336,46 +347,96 @@
     {
         return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches);
     }
+
+    /**
+     * notification that a ServletRegistration has been created so we can track the annotations
+     * @param holder new holder created through the api.
+     * @return the ServletRegistration.Dynamic
+     */
+    protected ServletRegistration.Dynamic dynamicHolderAdded(ServletHolder holder) {
+        return holder.getRegistration();
+    }
+
+    /**
+     * delegate for ServletContext.declareRole method
+     * @param roleNames role names to add
+     */
+    protected void addRoles(String... roleNames) {
+        //Get a reference to the SecurityHandler, which must be ConstraintAware
+        if (_securityHandler != null && _securityHandler instanceof ConstraintAware)
+        {
+            HashSet<String> union = new HashSet<String>();
+            Set<String> existing = ((ConstraintAware)_securityHandler).getRoles();
+            if (existing != null)
+                union.addAll(existing);
+            union.addAll(Arrays.asList(roleNames));
+            ((ConstraintSecurityHandler)_securityHandler).setRoles(union);
+        }
+    }
+
+    /**
+     * Delegate for ServletRegistration.Dynamic.setServletSecurity method
+     * @param registration ServletRegistration.Dynamic instance that setServletSecurity was called on
+     * @param servletSecurityElement new security info
+     * @return the set of exact URL mappings currently associated with the registration that are also present in the web.xml
+     * security constraints and thus will be unaffected by this call.
+     */
+    public Set<String> setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement)
+    {
+        //Default implementation is to just accept them all. If using a webapp, then this behaviour is overridden in WebAppContext.setServletSecurity       
+        Collection<String> pathSpecs = registration.getMappings();
+        if (pathSpecs != null)
+        {
+            for (String pathSpec:pathSpecs)
+            {
+                List<ConstraintMapping> mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
+                for (ConstraintMapping m:mappings)
+                    ((ConstraintAware)getSecurityHandler()).addConstraintMapping(m);
+            }
+        }
+        return Collections.emptySet();
+    }
+
+
     
-
-    /* ------------------------------------------------------------ */
-    /** conveniance method to add a filter
-     */
-    public void addFilter(FilterHolder holder,String pathSpec,int dispatches)
+    public void restrictEventListener (EventListener e)
     {
-        getServletHandler().addFilterWithMapping(holder,pathSpec,dispatches);
+        if (_restrictListeners && e instanceof ServletContextListener)
+            _restrictedContextListeners = LazyList.add(_restrictedContextListeners, e);
     }
 
-    /* ------------------------------------------------------------ */
-    /** convenience method to add a filter
-     */
-    public FilterHolder addFilter(Class<? extends Filter> filterClass,String pathSpec,int dispatches)
-    {
-        return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches);
+    public boolean isRestrictListeners() {
+        return _restrictListeners;
     }
 
-    /* ------------------------------------------------------------ */
-    /** convenience method to add a filter
-     */
-    public FilterHolder addFilter(String filterClass,String pathSpec,int dispatches)
-    {
-        return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches);
+    public void setRestrictListeners(boolean restrictListeners) {
+        this._restrictListeners = restrictListeners;
     }
 
- 
-
     public void callContextInitialized(ServletContextListener l, ServletContextEvent e)
-    {       
-        l.contextInitialized(e);  
+    {
+        try
+        {
+            //toggle state of the dynamic API so that the listener cannot use it
+            if (LazyList.contains(_restrictedContextListeners, l))
+                this.getServletContext().setEnabled(false);
+            
+            super.callContextInitialized(l, e);
+        }
+        finally
+        {
+            //untoggle the state of the dynamic API
+            this.getServletContext().setEnabled(true);
+        }
     }
 
-
+    
     public void callContextDestroyed(ServletContextListener l, ServletContextEvent e)
     {
-        l.contextDestroyed(e);
+        super.callContextDestroyed(l, e);
     }
 
-
+  
 
     /* ------------------------------------------------------------ */
     /**
@@ -456,6 +517,290 @@
     }
     
     /* ------------------------------------------------------------ */
+    public static class JspPropertyGroup implements JspPropertyGroupDescriptor
+    {
+        private List<String> _urlPatterns = new ArrayList<String>();
+        private String _elIgnored;
+        private String _pageEncoding;
+        private String _scriptingInvalid;
+        private String _isXml;
+        private List<String> _includePreludes = new ArrayList<String>();
+        private List<String> _includeCodas = new ArrayList<String>();
+        private String _deferredSyntaxAllowedAsLiteral;
+        private String _trimDirectiveWhitespaces;
+        private String _defaultContentType;
+        private String _buffer;
+        private String _errorOnUndeclaredNamespace;
+        
+        
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getUrlPatterns()
+         */
+        public Collection<String> getUrlPatterns()
+        {
+            return new ArrayList<String>(_urlPatterns); // spec says must be a copy
+        }
+        
+        public void addUrlPattern (String s)
+        {
+            if (!_urlPatterns.contains(s))
+                _urlPatterns.add(s);
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getElIgnored()
+         */
+        public String getElIgnored()
+        {
+            return _elIgnored;
+        }
+        
+        public void setElIgnored (String s)
+        {
+            _elIgnored = s;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getPageEncoding()
+         */
+        public String getPageEncoding()
+        {
+            return _pageEncoding;
+        }
+        
+        public void setPageEncoding(String pageEncoding)
+        {
+            _pageEncoding = pageEncoding;
+        }
+
+        public void setScriptingInvalid(String scriptingInvalid)
+        {
+            _scriptingInvalid = scriptingInvalid;
+        }
+
+        public void setIsXml(String isXml)
+        {
+            _isXml = isXml;
+        }
+
+        public void setDeferredSyntaxAllowedAsLiteral(String deferredSyntaxAllowedAsLiteral)
+        {
+            _deferredSyntaxAllowedAsLiteral = deferredSyntaxAllowedAsLiteral;
+        }
+
+        public void setTrimDirectiveWhitespaces(String trimDirectiveWhitespaces)
+        {
+            _trimDirectiveWhitespaces = trimDirectiveWhitespaces;
+        }
+
+        public void setDefaultContentType(String defaultContentType)
+        {
+            _defaultContentType = defaultContentType;
+        }
+
+        public void setBuffer(String buffer)
+        {
+            _buffer = buffer;
+        }
+
+        public void setErrorOnUndeclaredNamespace(String errorOnUndeclaredNamespace)
+        {
+            _errorOnUndeclaredNamespace = errorOnUndeclaredNamespace;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getScriptingInvalid()
+         */
+        public String getScriptingInvalid()
+        {
+            return _scriptingInvalid;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getIsXml()
+         */
+        public String getIsXml()
+        {
+            return _isXml;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getIncludePreludes()
+         */
+        public Collection<String> getIncludePreludes()
+        {
+            return new ArrayList<String>(_includePreludes); //must be a copy
+        }
+        
+        public void addIncludePrelude(String prelude)
+        {
+            if (!_includePreludes.contains(prelude))
+                _includePreludes.add(prelude);
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getIncludeCodas()
+         */
+        public Collection<String> getIncludeCodas()
+        {
+            return new ArrayList<String>(_includeCodas); //must be a copy
+        }
+
+        public void addIncludeCoda (String coda)
+        {
+            if (!_includeCodas.contains(coda))
+                _includeCodas.add(coda);
+        }
+        
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getDeferredSyntaxAllowedAsLiteral()
+         */
+        public String getDeferredSyntaxAllowedAsLiteral()
+        {
+            return _deferredSyntaxAllowedAsLiteral;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getTrimDirectiveWhitespaces()
+         */
+        public String getTrimDirectiveWhitespaces()
+        {
+            return _trimDirectiveWhitespaces;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getDefaultContentType()
+         */
+        public String getDefaultContentType()
+        {
+            return _defaultContentType;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getBuffer()
+         */
+        public String getBuffer()
+        {
+            return _buffer;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspPropertyGroupDescriptor#getErrorOnUndeclaredNamespace()
+         */
+        public String getErrorOnUndeclaredNamespace()
+        {
+            return _errorOnUndeclaredNamespace;
+        }
+        
+        public String toString ()
+        {
+            StringBuffer sb = new StringBuffer();
+            sb.append("JspPropertyGroupDescriptor:");
+            sb.append(" el-ignored="+_elIgnored);
+            sb.append(" is-xml="+_isXml);
+            sb.append(" page-encoding="+_pageEncoding);
+            sb.append(" scripting-invalid="+_scriptingInvalid);
+            sb.append(" deferred-syntax-allowed-as-literal="+_deferredSyntaxAllowedAsLiteral);
+            sb.append(" trim-directive-whitespaces"+_trimDirectiveWhitespaces);
+            sb.append(" default-content-type="+_defaultContentType);
+            sb.append(" buffer="+_buffer);
+            sb.append(" error-on-undeclared-namespace="+_errorOnUndeclaredNamespace);
+            for (String prelude:_includePreludes)
+                sb.append(" include-prelude="+prelude);
+            for (String coda:_includeCodas)
+                sb.append(" include-coda="+coda);
+            return sb.toString();
+        }
+    }
+    
+    /* ------------------------------------------------------------ */
+    public static class TagLib implements TaglibDescriptor
+    {
+        private String _uri;
+        private String _location;
+
+        /** 
+         * @see javax.servlet.descriptor.TaglibDescriptor#getTaglibURI()
+         */
+        public String getTaglibURI()
+        {
+           return _uri;
+        }
+        
+        public void setTaglibURI(String uri)
+        {
+            _uri = uri;
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.TaglibDescriptor#getTaglibLocation()
+         */
+        public String getTaglibLocation()
+        {
+            return _location;
+        }
+        
+        public void setTaglibLocation(String location)
+        {
+            _location = location;
+        }
+    
+        public String toString()
+        {
+            return ("TagLibDescriptor: taglib-uri="+_uri+" location="+_location);
+        }
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    public static class JspConfig implements JspConfigDescriptor
+    {
+        private List<TaglibDescriptor> _taglibs = new ArrayList<TaglibDescriptor>();
+        private List<JspPropertyGroupDescriptor> _jspPropertyGroups = new ArrayList<JspPropertyGroupDescriptor>();
+        
+        public JspConfig() {}
+
+        /** 
+         * @see javax.servlet.descriptor.JspConfigDescriptor#getTaglibs()
+         */
+        public Collection<TaglibDescriptor> getTaglibs()
+        {
+            return new ArrayList<TaglibDescriptor>(_taglibs);
+        }
+        
+        public void addTaglibDescriptor (TaglibDescriptor d)
+        {
+            _taglibs.add(d);
+        }
+
+        /** 
+         * @see javax.servlet.descriptor.JspConfigDescriptor#getJspPropertyGroups()
+         */
+        public Collection<JspPropertyGroupDescriptor> getJspPropertyGroups()
+        {
+           return new ArrayList<JspPropertyGroupDescriptor>(_jspPropertyGroups);
+        }
+        
+        public void addJspPropertyGroup(JspPropertyGroupDescriptor g)
+        {
+            _jspPropertyGroups.add(g);
+        }
+        
+        public String toString()
+        {
+            StringBuffer sb = new StringBuffer();
+            sb.append("JspConfigDescriptor: \n");
+            for (TaglibDescriptor taglib:_taglibs)
+                sb.append(taglib+"\n");
+            for (JspPropertyGroupDescriptor jpg:_jspPropertyGroups)
+                sb.append(jpg+"\n");
+            return sb.toString();
+        }
+    }
+    
+    
+    /* ------------------------------------------------------------ */
     public class Context extends ContextHandler.Context
     {
         /* ------------------------------------------------------------ */
@@ -466,7 +811,10 @@
         public RequestDispatcher getNamedDispatcher(String name)
         {
             ContextHandler context=org.eclipse.jetty.servlet.ServletContextHandler.this;
-            if (_servletHandler==null || _servletHandler.getServlet(name)==null)
+            if (_servletHandler==null)
+                return null;
+            ServletHolder holder = _servletHandler.getServlet(name);
+            if (holder==null || !holder.isEnabled())
                 return null;
             return new Dispatcher(context, name);
         }
@@ -475,34 +823,68 @@
         /**
          * @since servlet-api-3.0
          */
+        @Override
         public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass)
         {
             if (isStarted())
                 throw new IllegalStateException();
+            
+            if (!_enabled)
+                throw new UnsupportedOperationException();
 
             final ServletHandler handler = ServletContextHandler.this.getServletHandler();
-            final FilterHolder holder= handler.newFilterHolder();
-            holder.setName(filterName);
-            holder.setHeldClass(filterClass);
-            handler.addFilter(holder);
-            return holder.getRegistration();
+            FilterHolder holder = handler.getFilter(filterName);
+            if (holder == null)
+            {
+                //new filter
+                holder = handler.newFilterHolder(Holder.Source.JAVAX_API);
+                holder.setName(filterName);
+                holder.setHeldClass(filterClass);
+                handler.addFilter(holder);
+                return holder.getRegistration();
+            }
+            if (holder.getClassName()==null && holder.getHeldClass()==null)
+            {
+                //preliminary filter registration completion
+                holder.setHeldClass(filterClass);
+                return holder.getRegistration();
+            }
+            else
+                return null; //existing filter
         }
 
         /* ------------------------------------------------------------ */
         /**
          * @since servlet-api-3.0
          */
+        @Override
         public FilterRegistration.Dynamic addFilter(String filterName, String className)
         {
             if (isStarted())
                 throw new IllegalStateException();
+            
+            if (!_enabled)
+                throw new UnsupportedOperationException();
 
             final ServletHandler handler = ServletContextHandler.this.getServletHandler();
-            final FilterHolder holder= handler.newFilterHolder();
-            holder.setName(filterName);
-            holder.setClassName(className);
-            handler.addFilter(holder);
-            return holder.getRegistration();
+            FilterHolder holder = handler.getFilter(filterName);
+            if (holder == null)
+            {
+                //new filter
+                holder = handler.newFilterHolder(Holder.Source.JAVAX_API);
+                holder.setName(filterName);
+                holder.setClassName(className);
+                handler.addFilter(holder);
+                return holder.getRegistration();
+            }
+            if (holder.getClassName()==null && holder.getHeldClass()==null)
+            {
+                //preliminary filter registration completion
+                holder.setClassName(className);
+                return holder.getRegistration();
+            }
+            else
+                return null; //existing filter
         }
 
 
@@ -510,81 +892,158 @@
         /**
          * @since servlet-api-3.0
          */
+        @Override
         public FilterRegistration.Dynamic addFilter(String filterName, Filter filter)
         {
             if (isStarted())
                 throw new IllegalStateException();
 
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
             final ServletHandler handler = ServletContextHandler.this.getServletHandler();
-            final FilterHolder holder= handler.newFilterHolder();
-            holder.setName(filterName);
-            holder.setFilter(filter);
-            handler.addFilter(holder);
-            return holder.getRegistration();
+            FilterHolder holder = handler.getFilter(filterName);
+            if (holder == null)
+            {
+                //new filter
+                holder = handler.newFilterHolder(Holder.Source.JAVAX_API);
+                holder.setName(filterName);
+                holder.setFilter(filter);
+                handler.addFilter(holder);
+                return holder.getRegistration();
+            }
+            
+            if (holder.getClassName()==null && holder.getHeldClass()==null)
+            {
+                //preliminary filter registration completion
+                holder.setFilter(filter);
+                return holder.getRegistration();
+            }
+            else
+                return null; //existing filter
         }
         
         /* ------------------------------------------------------------ */
         /**
          * @since servlet-api-3.0
          */
+        @Override
         public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass)
         {
             if (!isStarting())
                 throw new IllegalStateException();
-
+            
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
             final ServletHandler handler = ServletContextHandler.this.getServletHandler();
-            final ServletHolder holder= handler.newServletHolder();
-            holder.setName(servletName);
-            holder.setHeldClass(servletClass);
-            handler.addServlet(holder);
-            return holder.getRegistration();
+            ServletHolder holder = handler.getServlet(servletName);
+            if (holder == null)
+            {
+                //new servlet
+                holder = handler.newServletHolder(Holder.Source.JAVAX_API);
+                holder.setName(servletName);
+                holder.setHeldClass(servletClass);
+                handler.addServlet(holder);
+                return dynamicHolderAdded(holder);
+            }
+
+            //complete a partial registration
+            if (holder.getClassName()==null && holder.getHeldClass()==null)
+            {
+                holder.setHeldClass(servletClass);
+                return holder.getRegistration();
+            }
+            else
+                return null; //existing completed registration for servlet name      
         }
 
         /* ------------------------------------------------------------ */
         /**
          * @since servlet-api-3.0
          */
+        @Override
         public ServletRegistration.Dynamic addServlet(String servletName, String className)
         {
             if (!isStarting())
                 throw new IllegalStateException();
             
-            final ServletHandler handler = ServletContextHandler.this.getServletHandler();
-            final ServletHolder holder= handler.newServletHolder();
-            holder.setName(servletName);
-            holder.setClassName(className);
-            handler.addServlet(holder);
-            return holder.getRegistration();
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+
+
+            final ServletHandler handler = ServletContextHandler.this.getServletHandler();            
+            ServletHolder holder = handler.getServlet(servletName);
+            if (holder == null)
+            {
+                //new servlet
+                holder = handler.newServletHolder(Holder.Source.JAVAX_API);
+                holder.setName(servletName);
+                holder.setClassName(className);
+                handler.addServlet(holder);
+                return dynamicHolderAdded(holder);
+            }
+
+            //complete a partial registration
+            if (holder.getClassName()==null && holder.getHeldClass()==null)
+            {
+                holder.setClassName(className); 
+                return holder.getRegistration();
+            }
+            else
+                return null; //existing completed registration for servlet name
         }
 
         /* ------------------------------------------------------------ */
         /**
          * @since servlet-api-3.0
          */
+        @Override
         public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
         {
             if (!isStarting())
                 throw new IllegalStateException();
 
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+
             final ServletHandler handler = ServletContextHandler.this.getServletHandler();
-            final ServletHolder holder= handler.newServletHolder();
-            holder.setName(servletName);
-            holder.setServlet(servlet);
-            handler.addServlet(holder);
-            return holder.getRegistration();
+            ServletHolder holder = handler.getServlet(servletName);
+            if (holder == null)
+            {
+                holder = handler.newServletHolder(Holder.Source.JAVAX_API);
+                holder.setName(servletName);
+                holder.setServlet(servlet);
+                handler.addServlet(holder);
+                return dynamicHolderAdded(holder);
+            }
+            
+            //complete a partial registration
+            if (holder.getClassName()==null && holder.getHeldClass()==null)
+            {
+                holder.setServlet(servlet);
+                return holder.getRegistration();
+            }
+            else
+                return null; //existing completed registration for servlet name
         }
 
         /* ------------------------------------------------------------ */
+        @Override
         public boolean setInitParameter(String name, String value)
         {
             // TODO other started conditions
             if (!isStarting())
                 throw new IllegalStateException();
             
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
             return super.setInitParameter(name,value);
         }
 
         /* ------------------------------------------------------------ */
+        @Override
         public <T extends Filter> T createFilter(Class<T> c) throws ServletException
         {
             try
@@ -608,6 +1067,7 @@
         }
 
         /* ------------------------------------------------------------ */
+        @Override
         public <T extends Servlet> T createServlet(Class<T> c) throws ServletException
         {
             try
@@ -629,16 +1089,39 @@
                 throw new ServletException(e);
             }
         }
-        
+
+        @Override
+        public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
+        {
+            if (_sessionHandler!=null)
+                return _sessionHandler.getSessionManager().getDefaultSessionTrackingModes();
+            return null;
+        }
+
+        @Override
+        public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
+        {
+            if (_sessionHandler!=null)
+                return _sessionHandler.getSessionManager().getEffectiveSessionTrackingModes();
+            return null;
+        }
+
+        @Override
         public FilterRegistration getFilterRegistration(String filterName)
-        {   
+        {
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
             final FilterHolder holder=ServletContextHandler.this.getServletHandler().getFilter(filterName);
             return (holder==null)?null:holder.getRegistration();
         }
 
-        
+        @Override
         public Map<String, ? extends FilterRegistration> getFilterRegistrations()
         {
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
             HashMap<String, FilterRegistration> registrations = new HashMap<String, FilterRegistration>();
             ServletHandler handler=ServletContextHandler.this.getServletHandler();
             FilterHolder[] holders=handler.getFilters();
@@ -650,16 +1133,22 @@
             return registrations;
         }
 
-        
+        @Override
         public ServletRegistration getServletRegistration(String servletName)
-        { 
+        {
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
             final ServletHolder holder=ServletContextHandler.this.getServletHandler().getServlet(servletName);
             return (holder==null)?null:holder.getRegistration();
         }
 
-        
+        @Override
         public Map<String, ? extends ServletRegistration> getServletRegistrations()
-        { 
+        {
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
             HashMap<String, ServletRegistration> registrations = new HashMap<String, ServletRegistration>();
             ServletHandler handler=ServletContextHandler.this.getServletHandler();
             ServletHolder[] holders=handler.getServlets();
@@ -671,67 +1160,71 @@
             return registrations;
         }
 
-  
+        @Override
+        public SessionCookieConfig getSessionCookieConfig()
+        {
+            // TODO other started conditions
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
+            if (_sessionHandler!=null)
+                return _sessionHandler.getSessionManager().getSessionCookieConfig();
+            return null;
+        }
+
+        @Override
+        public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
+        {
+            // TODO other started conditions
+            if (!isStarting())
+                throw new IllegalStateException();
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            
+            
+            if (_sessionHandler!=null)
+                _sessionHandler.getSessionManager().setSessionTrackingModes(sessionTrackingModes);
+        }
+
+        @Override
         public void addListener(String className)
         {
             // TODO other started conditions
             if (!isStarting())
                 throw new IllegalStateException();
-            try
-            {
-                Class<? extends EventListener> clazz = getClassLoader()==null?Loader.loadClass(ContextHandler.class,className):getClassLoader().loadClass(className);
-                addListener(clazz);
-            }
-            catch (ClassNotFoundException e)
-            {
-                throw new IllegalArgumentException(e);
-            }
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            super.addListener(className);
         }
 
-      
+        @Override
         public <T extends EventListener> void addListener(T t)
         {
+            // TODO other started conditions
             if (!isStarting())
                 throw new IllegalStateException();
-         
-            ServletContextHandler.this.addEventListener(t);
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            super.addListener(t);
         }
 
-      
+        @Override
         public void addListener(Class<? extends EventListener> listenerClass)
         {
+            // TODO other started conditions
             if (!isStarting())
                 throw new IllegalStateException();
-
-            try
-            {
-                EventListener l = createListener(listenerClass);
-                ServletContextHandler.this.addEventListener(l);
-            }
-            catch (ServletException e)
-            {
-                throw new IllegalStateException(e);
-            }
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            super.addListener(listenerClass);
         }
 
-   
+        @Override
         public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
         {
             try
             {
-                T l = null;
-                try
-                {
-                    l = clazz.newInstance();
-                }
-                catch (InstantiationException e)
-                {
-                    throw new ServletException(e);
-                }
-                catch (IllegalAccessException e)
-                {
-                    throw new ServletException(e);
-                }
+                T l = super.createListener(clazz);
 
                 for (int i=_decorators.size()-1; i>=0; i--)
                 {
@@ -750,26 +1243,36 @@
             }
         }
 
-     
+
+        @Override
+        public JspConfigDescriptor getJspConfigDescriptor()
+        {
+            return _jspConfig;
+        }
+        
+        @Override
+        public void setJspConfigDescriptor(JspConfigDescriptor d)
+        {
+            _jspConfig = d;
+        }
+        
+        
+        @Override
         public void declareRoles(String... roleNames)
         {
             if (!isStarting())
                 throw new IllegalStateException();
-           
-            //Get a reference to the SecurityHandler, which must be ConstraintAware
-            if (_securityHandler != null && _securityHandler instanceof ConstraintAware)
-            {
-                HashSet<String> union = new HashSet<String>();
-                Set<String> existing = ((ConstraintAware)_securityHandler).getRoles();
-                if (existing != null)
-                    union.addAll(existing);
-                union.addAll(Arrays.asList(roleNames));
-                ((ConstraintSecurityHandler)_securityHandler).setRoles(union);
-            }
+            if (!_enabled)
+                throw new UnsupportedOperationException();
+            addRoles(roleNames);
+
+
         }
+
     }
-    
-    
+
+
+
     /* ------------------------------------------------------------ */
     /** Interface to decorate loaded classes.
      */
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 87708cf..bb160f2 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
@@ -21,21 +21,29 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Queue;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentMap;
+
+import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
+import javax.servlet.RequestDispatcher;
 import javax.servlet.Servlet;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.ServletSecurityElement;
 import javax.servlet.UnavailableException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -48,8 +56,8 @@
 import org.eclipse.jetty.security.IdentityService;
 import org.eclipse.jetty.security.SecurityHandler;
 import org.eclipse.jetty.server.AbstractHttpConnection;
+import org.eclipse.jetty.server.AsyncContinuation;
 import org.eclipse.jetty.server.Dispatcher;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServletRequestHttpWrapper;
@@ -57,6 +65,7 @@
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.ScopedHandler;
+import org.eclipse.jetty.servlet.Holder.Source;
 import org.eclipse.jetty.util.LazyList;
 import org.eclipse.jetty.util.MultiException;
 import org.eclipse.jetty.util.MultiMap;
@@ -80,6 +89,7 @@
 public class ServletHandler extends ScopedHandler
 {
     private static final Logger LOG = Log.getLogger(ServletHandler.class);
+    private static final Logger LOG_UNHANDLED = LOG.getLogger("unhandled");
 
     /* ------------------------------------------------------------ */
     public static final String __DEFAULT_SERVLET="default";
@@ -89,9 +99,11 @@
     private ContextHandler.Context _servletContext;
     private FilterHolder[] _filters=new FilterHolder[0];
     private FilterMapping[] _filterMappings;
+    private int _matchBeforeIndex = -1; //index of last programmatic FilterMapping with isMatchAfter=false
+    private int _matchAfterIndex = -1;  //index of 1st programmatic FilterMapping with isMatchAfter=true
     private boolean _filterChainsCached=true;
     private int _maxFilterChainsCacheSize=512;
-    private boolean _startWithUnavailable=true;
+    private boolean _startWithUnavailable=false;
     private IdentityService _identityService;
     
     private ServletHolder[] _servlets=new ServletHolder[0];
@@ -186,33 +198,75 @@
         throws Exception
     {
         super.doStop();
-        
+
         // Stop filters
+        List<FilterHolder> filterHolders = new ArrayList<FilterHolder>();
+        List<FilterMapping> filterMappings = LazyList.array2List(_filterMappings);
         if (_filters!=null)
         {
             for (int i=_filters.length; i-->0;)
             {
                 try { _filters[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);}
+                if (_filters[i].getSource() != Source.EMBEDDED)
+                {
+                    //remove all of the mappings that were for non-embedded filters
+                    _filterNameMap.remove(_filters[i].getName());
+                    //remove any mappings associated with this filter
+                    ListIterator<FilterMapping> fmitor = filterMappings.listIterator();
+                    while (fmitor.hasNext())
+                    {
+                        FilterMapping fm = fmitor.next();
+                        if (fm.getFilterName().equals(_filters[i].getName()))
+                            fmitor.remove();
+                    }
+                }
+                else
+                    filterHolders.add(_filters[i]); //only retain embedded
             }
         }
-        
+        _filters = (FilterHolder[]) LazyList.toArray(filterHolders, FilterHolder.class);
+        _filterMappings = (FilterMapping[]) LazyList.toArray(filterMappings, FilterMapping.class);
+        _matchAfterIndex = (_filterMappings == null || _filterMappings.length == 0 ? -1 : _filterMappings.length-1);
+        _matchBeforeIndex = -1;
+
+
         // Stop servlets
+        List<ServletHolder> servletHolders = new ArrayList<ServletHolder>();  //will be remaining servlets
+        List<ServletMapping> servletMappings = LazyList.array2List(_servletMappings); //will be remaining mappings
         if (_servlets!=null)
         {
             for (int i=_servlets.length; i-->0;)
             {
                 try { _servlets[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);}
+                if (_servlets[i].getSource() != Source.EMBEDDED)
+                {
+                    //remove from servlet name map
+                    _servletNameMap.remove(_servlets[i].getName());
+                    //remove any mappings associated with this servlet
+                    ListIterator<ServletMapping> smitor = servletMappings.listIterator();
+                    while (smitor.hasNext())
+                    {
+                        ServletMapping sm = smitor.next();
+                        if (sm.getServletName().equals(_servlets[i].getName()))
+                            smitor.remove();
+                    }
+                }
+                else
+                    servletHolders.add(_servlets[i]); //only retain embedded 
             }
         }
+        _servlets = (ServletHolder[]) LazyList.toArray(servletHolders, ServletHolder.class);
+        _servletMappings = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class);
 
+
+        //will be regenerated on next start
         _filterPathMappings=null;
-        _filterNameMappings=null;
-        
+        _filterNameMappings=null;       
         _servletPathMap=null;
     }
 
     /* ------------------------------------------------------------ */
-    IdentityService getIdentityService()
+    protected IdentityService getIdentityService()
     {
         return _identityService;
     }
@@ -277,6 +331,7 @@
      */
     public ServletMapping getServletMapping(String pattern)
     {
+        ServletMapping theMapping = null;
         if (_servletMappings!=null)
         {
             for (ServletMapping m:_servletMappings)
@@ -287,12 +342,12 @@
                     for (String path:paths)
                     {
                         if (pattern.equals(path))
-                            return m;
+                            theMapping = m;
                     }
                 }
             }
         }
-        return null;
+        return theMapping;
     }
         
     /* ------------------------------------------------------------ */
@@ -334,8 +389,8 @@
 
                 String servlet_path_spec=(String)entry.getKey(); 
                 String servlet_path=entry.getMapped()!=null?entry.getMapped():PathMap.pathMatch(servlet_path_spec,target);
-                String path_info=PathMap.pathInfo(servlet_path_spec,target);
-
+                String path_info=PathMap.pathInfo(servlet_path_spec,target); 
+                
                 if (DispatcherType.INCLUDE.equals(type))
                 {
                     baseRequest.setAttribute(Dispatcher.INCLUDE_SERVLET_PATH,servlet_path);
@@ -353,7 +408,7 @@
             // look for a servlet by name!
             servlet_holder=(ServletHolder)_servletNameMap.get(target);
         }
-
+       
         if (LOG.isDebugEnabled())
             LOG.debug("servlet {}|{}|{} -> {}",baseRequest.getContextPath(),baseRequest.getServletPath(),baseRequest.getPathInfo(),servlet_holder);
 
@@ -418,7 +473,8 @@
         }
 
         LOG.debug("chain={}",chain);
-        
+
+        Throwable th=null;
         try
         {
             if (servlet_holder==null)
@@ -470,7 +526,7 @@
             }
 
             // unwrap cause
-            Throwable th=e;
+            th=e;
             if (th instanceof UnavailableException)
             {
                 LOG.debug(th); 
@@ -502,13 +558,17 @@
             }
             else
             {
-                LOG.warn(request.getRequestURI(),th);
+                LOG.warn("Error Processing URI: {} - ({}) {}",request.getRequestURI(),th.getClass().getName(),th.getMessage());
+                if (LOG_UNHANDLED.isDebugEnabled())
+                {
+                    LOG_UNHANDLED.debug(request.getRequestURI(),th);
+                }
             }
 
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass());
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th);
             if (!response.isCommitted())
             {
-                request.setAttribute(Dispatcher.ERROR_EXCEPTION_TYPE,th.getClass());
-                request.setAttribute(Dispatcher.ERROR_EXCEPTION,th);
                 if (th instanceof UnavailableException)
                 {
                     UnavailableException ue = (UnavailableException)th;
@@ -522,21 +582,20 @@
             }
             else
                 LOG.debug("Response already committed for handling "+th);
+            
         }
         catch(Error e)
         {   
             if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
                 throw e;
+            th=e;
             LOG.warn("Error for "+request.getRequestURI(),e);
             if(LOG.isDebugEnabled())LOG.debug(request.toString());
 
-            // TODO httpResponse.getHttpConnection().forceClose();
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
             if (!response.isCommitted())
-            {
-                request.setAttribute(Dispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
-                request.setAttribute(Dispatcher.ERROR_EXCEPTION,e);
                 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            }
             else
                 LOG.debug("Response already committed for handling ",e);
         }
@@ -544,11 +603,15 @@
         {
             if (servlet_holder!=null)
                 baseRequest.setHandled(true);
+
+            // Complete async requests 
+            if (th!=null && request.isAsyncStarted())
+                ((AsyncContinuation)request.getAsyncContext()).errorComplete();
         }
     }
 
     /* ------------------------------------------------------------ */
-    private FilterChain getFilterChain(Request baseRequest, String pathInContext, ServletHolder servletHolder) 
+    protected FilterChain getFilterChain(Request baseRequest, String pathInContext, ServletHolder servletHolder) 
     {
         String key=pathInContext==null?servletHolder.getName():pathInContext;
         int dispatch = FilterMapping.dispatch(baseRequest.getDispatcherType());
@@ -605,7 +668,7 @@
         if (_filterChainsCached)
         {
             if (LazyList.size(filters) > 0)
-                chain= new CachedChain(filters, servletHolder);
+                chain = newCachedChain(filters, servletHolder);
 
             final Map<String,FilterChain> cache=_chainCache[dispatch];
             final Queue<String> lru=_chainLRU[dispatch];
@@ -635,7 +698,7 @@
     }
     
     /* ------------------------------------------------------------ */
-    private void invalidateChainsCache()
+    protected void invalidateChainsCache()
     {
         if (_chainLRU[FilterMapping.REQUEST]!=null)
         {
@@ -752,12 +815,22 @@
     /**
      * see also newServletHolder(Class)
      */
-    public ServletHolder newServletHolder()
+    public ServletHolder newServletHolder(Holder.Source source)
     {
-        return new ServletHolder();
+        return new ServletHolder(source);
     }
     
     /* ------------------------------------------------------------ */
+    /**
+     * Create a new CachedChain 
+     */
+    public CachedChain newCachedChain(Object filters, ServletHolder servletHolder)
+    {
+        return new CachedChain(filters, servletHolder);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Convenience method to add a servlet Holder.
     public ServletHolder newServletHolder(Class<? extends Servlet> servlet)
     {
         return new ServletHolder(servlet);
@@ -769,7 +842,7 @@
      */
     public ServletHolder addServletWithMapping (String className,String pathSpec)
     {
-        ServletHolder holder = newServletHolder(null);
+        ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED);
         holder.setClassName(className);
         addServletWithMapping(holder,pathSpec);
         return holder;
@@ -781,9 +854,10 @@
      */
     public ServletHolder addServletWithMapping (Class<? extends Servlet> servlet,String pathSpec)
     {
-        ServletHolder holder = newServletHolder();
+        ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED);
         holder.setHeldClass(servlet);
-        setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class));
+        //DUPLICATES adding servlet from addServletWithMapping(holder, pathSpec)?
+        //setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class));
         addServletWithMapping(holder,pathSpec);
         
         return holder;
@@ -836,23 +910,23 @@
     {
         setServletMappings((ServletMapping[])LazyList.addToArray(getServletMappings(), mapping, ServletMapping.class));
     }
-    
-    /* ------------------------------------------------------------ */
-    public FilterHolder newFilterHolder(Class<? extends Filter> filter)
-    {
-        return new FilterHolder(filter);
+
+    public Set<String>  setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement) {
+        if (_contextHandler != null) {
+            return _contextHandler.setServletSecurity(registration, servletSecurityElement);
+        }
+        return Collections.emptySet();
     }
-    
+
     /* ------------------------------------------------------------ */
     /** 
      * @see #newFilterHolder(Class)
      */
-    public FilterHolder newFilterHolder()
+    public FilterHolder newFilterHolder(Holder.Source source)
     {
-        return new FilterHolder();
+        return new FilterHolder(source);
     }
 
-
     /* ------------------------------------------------------------ */
     public FilterHolder getFilter(String name)
     {
@@ -869,7 +943,7 @@
      */
     public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,EnumSet<DispatcherType> dispatches)
     {
-        FilterHolder holder = newFilterHolder();
+        FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
         holder.setHeldClass(filter);
         addFilterWithMapping(holder,pathSpec,dispatches);
         
@@ -885,7 +959,7 @@
      */
     public FilterHolder addFilterWithMapping (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
     {
-        FilterHolder holder = newFilterHolder();
+        FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
         holder.setClassName(className);
         
         addFilterWithMapping(holder,pathSpec,dispatches);
@@ -912,7 +986,9 @@
             mapping.setFilterName(holder.getName());
             mapping.setPathSpec(pathSpec);
             mapping.setDispatcherTypes(dispatches);
-            setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
+            //setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
+            addFilterMapping(mapping);
+            
         }
         catch (RuntimeException e)
         {
@@ -927,7 +1003,6 @@
             
     }
     
-    
     /* ------------------------------------------------------------ */
     /** Convenience method to add a filter.
      * @param filter  class of filter to create
@@ -937,7 +1012,8 @@
      */
     public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,int dispatches)
     {
-        FilterHolder holder = newFilterHolder(filter);
+        FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
+        holder.setHeldClass(filter);
         addFilterWithMapping(holder,pathSpec,dispatches);
         
         return holder;
@@ -952,7 +1028,7 @@
      */
     public FilterHolder addFilterWithMapping (String className,String pathSpec,int dispatches)
     {
-        FilterHolder holder = newFilterHolder(null);
+        FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
         holder.setClassName(className);
         
         addFilterWithMapping(holder,pathSpec,dispatches);
@@ -979,7 +1055,8 @@
             mapping.setFilterName(holder.getName());
             mapping.setPathSpec(pathSpec);
             mapping.setDispatches(dispatches);
-            setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
+            //setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
+            addFilterMapping(mapping);
         }
         catch (RuntimeException e)
         {
@@ -994,14 +1071,13 @@
             
     }
     
-    
     /* ------------------------------------------------------------ */
     /** Convenience method to add a filter with a mapping
      * @param className
      * @param pathSpec
      * @param dispatches
      * @return the filter holder created
-     * @deprecated use {@link #addFilterWithMapping(Class, String, int)} instead
+     * @deprecated use {@link #addFilterWithMapping(Class, String, EnumSet<DispatcherType>)} instead
      */
     public FilterHolder addFilter (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
     {
@@ -1019,7 +1095,8 @@
         if (filter != null)
             setFilters((FilterHolder[])LazyList.addToArray(getFilters(), filter, FilterHolder.class));
         if (filterMapping != null)
-            setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), filterMapping, FilterMapping.class));
+            //setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), filterMapping, FilterMapping.class));
+            addFilterMapping(filterMapping);
     }
     
     /* ------------------------------------------------------------ */  
@@ -1039,9 +1116,43 @@
     public void addFilterMapping (FilterMapping mapping)
     {
         if (mapping != null)
-            setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
+        { 
+            Source source = (mapping.getFilterHolder()==null?null:mapping.getFilterHolder().getSource());
+            FilterMapping[] mappings =getFilterMappings();
+            if (mappings==null || mappings.length==0)
+            {
+                setFilterMappings(insertFilterMapping(mapping,0,false));
+                if (source != null && source == Source.JAVAX_API)
+                    _matchAfterIndex = 0;
+            }
+            else
+            {
+                //there are existing entries. If this is a programmatic filtermapping, it is added at the end of the list.
+                //If this is a normal filtermapping, it is inserted after all the other filtermappings (matchBefores and normals), 
+                //but before the first matchAfter filtermapping.
+                if (source != null && Source.JAVAX_API == source)
+                {
+                    setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
+                    if (_matchAfterIndex < 0)
+                        _matchAfterIndex = getFilterMappings().length-1;
+                }
+                else
+                {
+                    //insert non-programmatic filter mappings before any matchAfters, if any
+                    if (_matchAfterIndex < 0)
+                        setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
+                    else
+                    {
+                        FilterMapping[] new_mappings = insertFilterMapping(mapping, _matchAfterIndex, true);
+                        ++_matchAfterIndex;
+                        setFilterMappings(new_mappings);
+                    }
+                }
+            }
+        }
     }
     
+    
     /* ------------------------------------------------------------ */
     /** Convenience method to add a preconstructed FilterMapping
      * @param mapping
@@ -1050,20 +1161,100 @@
     {
         if (mapping != null)
         {
-            FilterMapping[] mappings =getFilterMappings();
+            Source source = mapping.getFilterHolder().getSource();
+            
+            FilterMapping[] mappings = getFilterMappings();
             if (mappings==null || mappings.length==0)
-                setFilterMappings(new FilterMapping[] {mapping});
+            {
+                setFilterMappings(insertFilterMapping(mapping, 0, false));
+                if (source != null && Source.JAVAX_API == source)
+                    _matchBeforeIndex = 0;
+            }
             else
             {
+                if (source != null && Source.JAVAX_API == source)
+                {
+                    //programmatically defined filter mappings are prepended to mapping list in the order
+                    //in which they were defined. In other words, insert this mapping at the tail of the 
+                    //programmatically prepended filter mappings, BEFORE the first web.xml defined filter mapping.
 
-                FilterMapping[] new_mappings=new FilterMapping[mappings.length+1];
-                System.arraycopy(mappings,0,new_mappings,1,mappings.length);
-                new_mappings[0]=mapping;
-                setFilterMappings(new_mappings);
+                    if (_matchBeforeIndex < 0)
+                    { 
+                        //no programmatically defined prepended filter mappings yet, prepend this one
+                        _matchBeforeIndex = 0;
+                        FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
+                        setFilterMappings(new_mappings);
+                    }
+                    else
+                    {
+                        FilterMapping[] new_mappings = insertFilterMapping(mapping,_matchBeforeIndex, false);
+                        ++_matchBeforeIndex;
+                        setFilterMappings(new_mappings);
+                    }
+                }
+                else
+                {
+                    //non programmatically defined, just prepend to list
+                    FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
+                    setFilterMappings(new_mappings);
+                }
+                
+                //adjust matchAfterIndex ptr to take account of the mapping we just prepended
+                if (_matchAfterIndex >= 0)
+                    ++_matchAfterIndex;
             }
         }
     }
+    
+    
+    
+    /**
+     * Insert a filtermapping in the list
+     * @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
+     */
+    protected FilterMapping[] insertFilterMapping (FilterMapping mapping, int pos, boolean before)
+    {
+        if (pos < 0)
+            throw new IllegalArgumentException("FilterMapping insertion pos < 0");
+        FilterMapping[] mappings = getFilterMappings();
+        
+        if (mappings==null || mappings.length==0)
+        {
+            return new FilterMapping[] {mapping};
+        }
+        FilterMapping[] new_mappings = new FilterMapping[mappings.length+1];
 
+    
+        if (before)
+        {
+            //copy existing filter mappings up to but not including the pos
+            System.arraycopy(mappings,0,new_mappings,0,pos);
+
+            //add in the new mapping
+            new_mappings[pos] = mapping; 
+
+            //copy the old pos mapping and any remaining existing mappings
+            System.arraycopy(mappings,pos,new_mappings,pos+1, mappings.length-pos);
+
+        }
+        else
+        {
+            //copy existing filter mappings up to and including the pos
+            System.arraycopy(mappings,0,new_mappings,0,pos+1);
+            //add in the new mapping after the pos
+            new_mappings[pos+1] = mapping;   
+
+            //copy the remaining existing mappings
+            if (mappings.length > pos+1)
+                System.arraycopy(mappings,pos+1,new_mappings,pos+2, mappings.length-(pos+1));
+        }
+        return new_mappings;
+    }
+    
+    
     /* ------------------------------------------------------------ */
     protected synchronized void updateNameMappings()
     {   
@@ -1140,7 +1331,7 @@
                 ServletHolder servlet_holder = (ServletHolder)_servletNameMap.get(_servletMappings[i].getServletName());
                 if (servlet_holder==null)
                     throw new IllegalStateException("No such servlet: "+_servletMappings[i].getServletName());
-                else if (_servletMappings[i].getPathSpecs()!=null)
+                else if (servlet_holder.isEnabled() && _servletMappings[i].getPathSpecs()!=null)
                 {
                     String[] pathSpecs = _servletMappings[i].getPathSpecs();
                     for (int j=0;j<pathSpecs.length;j++)
@@ -1173,7 +1364,7 @@
         
         try
         {
-            if (isStarted())
+            if (_contextHandler!=null && _contextHandler.isStarted() || _contextHandler==null && isStarted())
                 initialize();
         }
         catch (Exception e)
@@ -1250,23 +1441,22 @@
         invalidateChainsCache();
     }
 
-
     /* ------------------------------------------------------------ */
     /* ------------------------------------------------------------ */
-    private class CachedChain implements FilterChain
+    protected class CachedChain implements FilterChain
     {
         FilterHolder _filterHolder;
         CachedChain _next;
         ServletHolder _servletHolder;
 
         /* ------------------------------------------------------------ */
-        CachedChain(Object filters, ServletHolder servletHolder)
+        protected CachedChain(Object filters, ServletHolder servletHolder)
         {
             if (LazyList.size(filters)>0)
             {
                 _filterHolder=(FilterHolder)LazyList.get(filters, 0);
                 filters=LazyList.remove(filters,0);
-                _next=new CachedChain(filters,servletHolder);
+                _next=newCachedChain(filters,servletHolder);
             }
             else
                 _servletHolder=servletHolder;
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 dc6df80..b416170 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
@@ -19,9 +19,6 @@
 package org.eclipse.jetty.servlet;
 
 import java.io.IOException;
-import java.io.PrintStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -33,12 +30,15 @@
 import java.util.Set;
 import java.util.Stack;
 
+import javax.servlet.MultipartConfigElement;
 import javax.servlet.Servlet;
 import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.ServletSecurityElement;
 import javax.servlet.SingleThreadModel;
 import javax.servlet.UnavailableException;
 
@@ -47,7 +47,6 @@
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.servlet.api.ServletRegistration;
 import org.eclipse.jetty.util.Loader;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -82,6 +81,7 @@
     private transient Servlet _servlet;
     private transient Config _config;
     private transient long _unavailable;
+    private transient boolean _enabled = true;
     private transient UnavailableException _unavailableEx;
     public static final Map<String,String> NO_MAPPED_ROLES = Collections.emptyMap();
 
@@ -90,32 +90,32 @@
      */
     public ServletHolder()
     {
+        this(Source.EMBEDDED);
     }
-
     
     /* ---------------------------------------------------------------- */
-    /** Constructor for existing servlet.
+    /** Constructor .
      */
-    public ServletHolder(String name,Servlet servlet)
+    public ServletHolder(Holder.Source creator)
     {
-        setName(name);
-        setServlet(servlet);
+        super(creator);
     }
-
     
     /* ---------------------------------------------------------------- */
     /** Constructor for existing servlet.
      */
     public ServletHolder(Servlet servlet)
     {
+        this(Source.EMBEDDED);
         setServlet(servlet);
     }
 
     /* ---------------------------------------------------------------- */
     /** Constructor for servlet class.
      */
-    public ServletHolder(String name,Class<? extends Servlet> servlet)
+    public ServletHolder(String name, Class<? extends Servlet> servlet)
     {
+        this(Source.EMBEDDED);
         setName(name);
         setHeldClass(servlet);
     }
@@ -123,8 +123,19 @@
     /* ---------------------------------------------------------------- */
     /** Constructor for servlet class.
      */
+    public ServletHolder(String name, Servlet servlet)
+    {
+        this(Source.EMBEDDED);
+        setName(name);
+        setServlet(servlet);
+    }
+    
+    /* ---------------------------------------------------------------- */
+    /** Constructor for servlet class.
+     */
     public ServletHolder(Class<? extends Servlet> servlet)
     {
+        this(Source.EMBEDDED);
         setHeldClass(servlet);
     }
 
@@ -260,20 +271,62 @@
         _forcedPath = forcedPath;
     }
     
+    public boolean isEnabled()
+    {
+        return _enabled;
+    }
+
+
+    public void setEnabled(boolean enabled)
+    {
+        _enabled = enabled;
+    }
+
+
     /* ------------------------------------------------------------ */
     public void doStart()
         throws Exception
     {
         _unavailable=0;
+        if (!_enabled)
+            return;
+        
+        
+        //check servlet has a class (ie is not a preliminary registration). If preliminary, fail startup.
         try
         {
             super.doStart();
+        } 
+        catch (UnavailableException ue)
+        {
+            makeUnavailable(ue);
+            if (_servletHandler.isStartWithUnavailable())
+            {
+                LOG.ignore(ue);
+                return;
+            }
+            else
+                throw ue;
+        }
+
+
+        //servlet is not an instance of javax.servlet.Servlet
+        try
+        {
             checkServletType();
         }
         catch (UnavailableException ue)
         {
             makeUnavailable(ue);
+            if (_servletHandler.isStartWithUnavailable())
+            {
+                LOG.ignore(ue);
+                return;
+            }
+            else
+                throw ue;
         }
+        
 
         _identityService = _servletHandler.getIdentityService();
         if (_identityService!=null && _runAsRole!=null)
@@ -470,12 +523,13 @@
             
             // Handle configuring servlets that implement org.apache.jasper.servlet.JspServlet
             if (isJspServlet())
+            {
                 initJspServlet();
+            }
 
-            _servlet.init(_config);
+            initMultiPart();
             
-            if (isJspServlet())
-               postInitJspServlet();
+            _servlet.init(_config);
         }
         catch (UnavailableException e)
         {
@@ -531,52 +585,26 @@
         }
     }
     
-    protected void postInitJspServlet() throws Exception
+    /* ------------------------------------------------------------ */
+    /**
+     * Register a ServletRequestListener that will ensure tmp multipart
+     * files are deleted when the request goes out of scope.
+     * 
+     * @throws Exception
+     */
+    protected void initMultiPart () throws Exception
     {
-        try
+        //if this servlet can handle multipart requests, ensure tmp files will be
+        //cleaned up correctly
+        if (((Registration)getRegistration()).getMultipartConfig() != null)
         {
-            //Check that jasper's SystemLogHandler class is on the classpath
-            Class systemLogHandlerClass = Loader.loadClass(this.getClass(), "org.apache.jasper.util.SystemLogHandler");
-            PrintStream rootSystemLogHandler = null;
-            while (systemLogHandlerClass.isAssignableFrom(System.err.getClass()))
-            {
-                rootSystemLogHandler = System.err;
-                Method getWrapped = systemLogHandlerClass.getMethod("getWrapped", new Class[]{});
-                PrintStream ps = (PrintStream)getWrapped.invoke(System.err, new Object[]{});
-                System.setErr(ps);
-            }
-            
-            if (rootSystemLogHandler != null)
-                System.setErr(rootSystemLogHandler);
+            //Register a listener to delete tmp files that are created as a result of this
+            //servlet calling Request.getPart() or Request.getParts()
+            ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler();
+            ch.addEventListener(new Request.MultiPartCleanerListener());
         }
-        catch (ClassNotFoundException e)
-        {
-            //jasper not on classpath, ignore
-        }
-        catch (NoSuchMethodException e)
-        {
-            LOG.info("Problem unwrapping SystemLogHandler from System.err", e);
-        }
-        catch (SecurityException e)
-        {
-            LOG.warn("Problem unwrapping SystemLogHandler from System.err", e);
-        }
-        catch (IllegalAccessException e)
-        {
-            LOG.warn("Problem unwrapping SystemLogHandler from System.err", e);
-        }
-        catch (IllegalArgumentException e)
-        {
-            LOG.warn("Problem unwrapping SystemLogHandler from System.err", e);
-        }
-        catch (InvocationTargetException e)
-        {
-            LOG.warn("Problem unwrapping SystemLogHandler from System.err", e);
-        }
-        
     }
     
-    
     /* ------------------------------------------------------------ */
     /**
      * @see org.eclipse.jetty.server.UserIdentity.Scope#getContextPath()
@@ -645,10 +673,14 @@
             // Handle run as
             if (_identityService!=null)
                 old_run_as=_identityService.setRunAs(baseRequest.getResolvedUserIdentity(),_runAsToken);
-            
+
             if (!isAsyncSupported())
                 baseRequest.setAsyncSupported(false);
-            
+
+            MultipartConfigElement mpce = ((Registration)getRegistration()).getMultipartConfig();
+            if (mpce != null)
+                request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce);
+
             servlet.service(request,response);
             servlet_error=false;
         }
@@ -717,24 +749,33 @@
     /* -------------------------------------------------------- */
     /* -------------------------------------------------------- */
     public class Registration extends HolderRegistration implements ServletRegistration.Dynamic
-    {         
+    {
+        protected MultipartConfigElement _multipartConfig;       
+        
         public Set<String> addMapping(String... urlPatterns)
         {
             illegalStateIfContextStarted();
             Set<String> clash=null;
             for (String pattern : urlPatterns)
             {
-                if (_servletHandler.getServletMapping(pattern)!=null)
+                ServletMapping mapping = _servletHandler.getServletMapping(pattern);
+                if (mapping!=null)
                 {
-                    if (clash==null)
-                        clash=new HashSet<String>();
-                    clash.add(pattern);
+                    //if the servlet mapping was from a default descriptor, then allow it to be overridden
+                    if (!mapping.isDefault())
+                    {
+                        if (clash==null)
+                            clash=new HashSet<String>();
+                        clash.add(pattern);
+                    }
                 }
             }
             
+            //if there were any clashes amongst the urls, return them
             if (clash!=null)
                 return clash;
             
+            //otherwise apply all of them
             ServletMapping mapping = new ServletMapping();
             mapping.setServletName(ServletHolder.this.getName());
             mapping.setPathSpecs(urlPatterns);
@@ -747,22 +788,27 @@
         {
             ServletMapping[] mappings =_servletHandler.getServletMappings();
             List<String> patterns=new ArrayList<String>();
-            for (ServletMapping mapping : mappings)
+            if (mappings!=null)
             {
-                if (!mapping.getServletName().equals(getName()))
-                    continue;
-                String[] specs=mapping.getPathSpecs();
-                if (specs!=null && specs.length>0)
-                    patterns.addAll(Arrays.asList(specs));
+                for (ServletMapping mapping : mappings)
+                {
+                    if (!mapping.getServletName().equals(getName()))
+                        continue;
+                    String[] specs=mapping.getPathSpecs();
+                    if (specs!=null && specs.length>0)
+                        patterns.addAll(Arrays.asList(specs));
+                }
             }
             return patterns;
         }
 
+        @Override
         public String getRunAsRole() 
         {
             return _runAsRole;
         }
 
+        @Override
         public void setLoadOnStartup(int loadOnStartup)
         {
             illegalStateIfContextStarted();
@@ -773,17 +819,35 @@
         {
             return ServletHolder.this.getInitOrder();
         }
- 
+
+        @Override
+        public void setMultipartConfig(MultipartConfigElement element) 
+        {
+            _multipartConfig = element;
+        }
+        
+        public MultipartConfigElement getMultipartConfig()
+        {
+            return _multipartConfig;
+        }
+
+        @Override
         public void setRunAsRole(String role) 
         {
             _runAsRole = role;
         }
+
+        @Override
+        public Set<String> setServletSecurity(ServletSecurityElement securityElement) 
+        {
+            return _servletHandler.setServletSecurity(this, securityElement);
+        }
     }
     
     public ServletRegistration.Dynamic getRegistration()
     {
         if (_registration == null)
-            _registration =  new Registration();
+            _registration = new Registration();
         return _registration;
     }
     
@@ -903,8 +967,3 @@
         }
     }
 }
-
-
-
-
-
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 5537e36..f2468bd 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
@@ -26,6 +26,8 @@
 {
     private String[] _pathSpecs;
     private String _servletName;
+    private boolean _default;
+    
 
     /* ------------------------------------------------------------ */
     public ServletMapping()
@@ -77,6 +79,25 @@
         _servletName = servletName;
     }
     
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @return
+     */
+    public boolean isDefault()
+    {
+        return _default;
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param default1
+     */
+    public void setDefault(boolean fromDefault)
+    {
+        _default = fromDefault;
+    }
 
     /* ------------------------------------------------------------ */
     public String toString()
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/FilterRegistration.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/FilterRegistration.java
deleted file mode 100644
index 37d9ae7..0000000
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/FilterRegistration.java
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      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.api;
-
-import java.util.Collection;
-import java.util.EnumSet;
-
-import org.eclipse.jetty.server.DispatcherType;
-
-/**
- * FilterRegistration
- * 
- * Mimics the javax.servlet.FilterRegistration class to ease
- * jetty-7/jetty-8 compatibility
- */
-public interface FilterRegistration
-{
-    public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... servletNames);
-
-    public Collection<String> getServletNameMappings();
-
-    public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... urlPatterns);
-
-    public Collection<String> getUrlPatternMappings();
-
-    interface Dynamic extends FilterRegistration, Registration.Dynamic
-    {
-    }
-}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/Registration.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/Registration.java
deleted file mode 100644
index 7555001..0000000
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/Registration.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.servlet.api;
-
-import java.util.Map;
-import java.util.Set;
-
-public interface Registration
-{
-
-    public String getName();
-
-    public String getClassName();
-
-    public boolean setInitParameter(String name, String value);
-
-    public String getInitParameter(String name);
-
-    public Set<String> setInitParameters(Map<String, String> initParameters);
-
-    public Map<String, String> getInitParameters();
-
-    interface Dynamic extends Registration 
-    {
-        public void setAsyncSupported(boolean isAsyncSupported);
-    }
-}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/ServletRegistration.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/ServletRegistration.java
deleted file mode 100644
index 4a1502b..0000000
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/ServletRegistration.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.servlet.api;
-
-import java.util.Collection;
-import java.util.Set;
-
-public interface ServletRegistration
-{
-    public Set<String> addMapping(String... urlPatterns);
-   
-    public Collection<String> getMappings();
-
-    public String getRunAsRole();
-
-    interface Dynamic extends ServletRegistration, Registration.Dynamic 
-    {
-        public void setLoadOnStartup(int loadOnStartup);
-
-        public void setRunAsRole(String roleName);
-    }
-
-}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/listener/ELContextCleaner.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/listener/ELContextCleaner.java
index 42943d2..16199be 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/listener/ELContextCleaner.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/listener/ELContextCleaner.java
@@ -20,6 +20,7 @@
 
 import java.lang.reflect.Field;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import javax.servlet.ServletContextEvent;
@@ -105,7 +106,7 @@
         if (!properties.isAccessible())
             properties.setAccessible(true);
 
-        ConcurrentHashMap map = (ConcurrentHashMap) properties.get(null);
+        Map map = (Map) properties.get(null);
         if (map == null)
             return;
         
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 d9f8668..cc32240 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
@@ -27,19 +27,19 @@
 import java.io.IOException;
 import java.io.StringReader;
 
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
+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.HttpServletResponseWrapper;
 
-import junit.framework.Assert;
-
-import org.eclipse.jetty.continuation.ContinuationSupport;
-import org.eclipse.jetty.server.AsyncContext;
-import org.eclipse.jetty.server.AsyncContinuation;
+import org.junit.Assert;
 import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.LocalConnector;
 import org.eclipse.jetty.server.Request;
@@ -65,16 +65,25 @@
     @Before
     public void setUp() throws Exception
     {
-        _connector.setMaxIdleTime(30000);
+        _connector.setMaxIdleTime(5000);
         _server.setConnectors(new Connector[]
         { _connector });
 
-        _contextHandler.setContextPath("/");
+        _contextHandler.setContextPath("/ctx");
         _contextHandler.addServlet(new ServletHolder(new TestServlet()),"/servletPath");
         _contextHandler.addServlet(new ServletHolder(new TestServlet()),"/path with spaces/servletPath");
         _contextHandler.addServlet(new ServletHolder(new TestServlet2()),"/servletPath2");
+        _contextHandler.addServlet(new ServletHolder(new TestStartThrowServlet()),"/startthrow/*");
         _contextHandler.addServlet(new ServletHolder(new ForwardingServlet()),"/forward");
         _contextHandler.addServlet(new ServletHolder(new AsyncDispatchingServlet()),"/dispatchingServlet");
+        _contextHandler.addServlet(new ServletHolder(new ExpireServlet()),"/expire/*");
+        _contextHandler.addServlet(new ServletHolder(new BadExpireServlet()),"/badexpire/*");
+        _contextHandler.addServlet(new ServletHolder(new ErrorServlet()),"/error/*");
+        
+        ErrorPageErrorHandler error_handler = new ErrorPageErrorHandler();
+        _contextHandler.setErrorHandler(error_handler);
+        error_handler.addErrorPage(500,"/error/500");
+        error_handler.addErrorPage(IOException.class.getName(),"/error/IOE");
 
         HandlerList handlers = new HandlerList();
         handlers.setHandlers(new Handler[]
@@ -87,11 +96,11 @@
     @Test
     public void testSimpleAsyncContext() throws Exception
     {
-        String request = "GET /servletPath HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+        String request = "GET /ctx/servletPath 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);
 
+
         BufferedReader br = parseHeader(responseString);
 
         Assert.assertEquals("servlet gets right path","doGet:getServletPath:/servletPath",br.readLine());
@@ -100,9 +109,93 @@
     }
 
     @Test
+    public void testStartThrow() throws Exception
+    {
+        String request = 
+          "GET /ctx/startthrow HTTP/1.1\r\n" + 
+          "Host: localhost\r\n" + 
+          "Connection: close\r\n" + 
+          "\r\n";
+        String responseString = _connector.getResponses(request);
+
+        BufferedReader br = new BufferedReader(new StringReader(responseString));
+
+        assertEquals("HTTP/1.1 500 Server Error",br.readLine());
+        br.readLine();// connection close
+        br.readLine();// server
+        br.readLine();// empty
+
+        Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
+        Assert.assertEquals("error servlet","PathInfo= /IOE",br.readLine());
+        Assert.assertEquals("error servlet","EXCEPTION: java.io.IOException: Test",br.readLine());
+    }
+
+    @Test
+    public void testStartDispatchThrow() throws Exception
+    {
+        String request = "GET /ctx/startthrow?dispatch=true 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);
+
+        BufferedReader br = new BufferedReader(new StringReader(responseString));
+
+        assertEquals("HTTP/1.1 500 Server Error",br.readLine());
+        br.readLine();// connection close
+        br.readLine();// server
+        br.readLine();// empty
+        Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
+        Assert.assertEquals("error servlet","PathInfo= /IOE",br.readLine());
+        Assert.assertEquals("error servlet","EXCEPTION: java.io.IOException: Test",br.readLine());
+    }
+    
+    @Test
+    public void testStartCompleteThrow() throws Exception
+    {
+        String request = "GET /ctx/startthrow?complete=true 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);
+
+        BufferedReader br = new BufferedReader(new StringReader(responseString));
+
+        assertEquals("HTTP/1.1 500 Server Error",br.readLine());
+        br.readLine();// connection close
+        br.readLine();// server
+        br.readLine();// empty
+        Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
+        Assert.assertEquals("error servlet","PathInfo= /IOE",br.readLine());
+        Assert.assertEquals("error servlet","EXCEPTION: java.io.IOException: Test",br.readLine());
+    }
+    
+    @Test
+    public void testStartFlushCompleteThrow() throws Exception
+    {
+        String request = "GET /ctx/startthrow?flush=true&complete=true 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);
+
+        BufferedReader br = new BufferedReader(new StringReader(responseString));
+
+        assertEquals("HTTP/1.1 200 OK",br.readLine());
+        br.readLine();// connection close
+        br.readLine();// server
+        br.readLine();// empty
+
+        Assert.assertEquals("error servlet","completeBeforeThrow",br.readLine());
+    }
+    
+    @Test
     public void testDispatchAsyncContext() throws Exception
     {
-        String request = "GET /servletPath?dispatch=true HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+        String request = "GET /ctx/servletPath?dispatch=true 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);
 
@@ -113,14 +206,14 @@
         Assert.assertEquals("servlet path attr is original","async:run:attr:servletPath:/servletPath",br.readLine());
         Assert.assertEquals("path info attr is correct","async:run:attr:pathInfo:null",br.readLine());
         Assert.assertEquals("query string attr is correct","async:run:attr:queryString:dispatch=true",br.readLine());
-        Assert.assertEquals("context path attr is correct","async:run:attr:contextPath:",br.readLine());
-        Assert.assertEquals("request uri attr is correct","async:run:attr:requestURI:/servletPath",br.readLine());
+        Assert.assertEquals("context path attr is correct","async:run:attr:contextPath:/ctx",br.readLine());
+        Assert.assertEquals("request uri attr is correct","async:run:attr:requestURI:/ctx/servletPath",br.readLine());
     }
     
     @Test
     public void testDispatchAsyncContextEncodedPathAndQueryString() throws Exception
     {
-        String request = "GET /path%20with%20spaces/servletPath?dispatch=true&queryStringWithEncoding=space%20space HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+        String request = "GET /ctx/path%20with%20spaces/servletPath?dispatch=true&queryStringWithEncoding=space%20space 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);
         
@@ -131,16 +224,14 @@
         assertThat("servlet path attr is original",br.readLine(),equalTo("async:run:attr:servletPath:/path with spaces/servletPath"));
         assertThat("path info attr is correct",br.readLine(),equalTo("async:run:attr:pathInfo:null"));
         assertThat("query string attr is correct",br.readLine(),equalTo("async:run:attr:queryString:dispatch=true&queryStringWithEncoding=space%20space"));
-        assertThat("context path attr is correct",br.readLine(),equalTo("async:run:attr:contextPath:"));
-        assertThat("request uri attr is correct",br.readLine(),equalTo("async:run:attr:requestURI:/path%20with%20spaces/servletPath"));
+        assertThat("context path attr is correct",br.readLine(),equalTo("async:run:attr:contextPath:/ctx"));
+        assertThat("request uri attr is correct",br.readLine(),equalTo("async:run:attr:requestURI:/ctx/path%20with%20spaces/servletPath"));
     }
 
     @Test
     public void testSimpleWithContextAsyncContext() throws Exception
     {
-        _contextHandler.setContextPath("/foo");
-
-        String request = "GET /foo/servletPath HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+        String request = "GET /ctx/servletPath 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);
@@ -155,9 +246,7 @@
     @Test
     public void testDispatchWithContextAsyncContext() throws Exception
     {
-        _contextHandler.setContextPath("/foo");
-
-        String request = "GET /foo/servletPath?dispatch=true HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+        String request = "GET /ctx/servletPath?dispatch=true 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);
@@ -169,14 +258,14 @@
         Assert.assertEquals("servlet path attr is original","async:run:attr:servletPath:/servletPath",br.readLine());
         Assert.assertEquals("path info attr is correct","async:run:attr:pathInfo:null",br.readLine());
         Assert.assertEquals("query string attr is correct","async:run:attr:queryString:dispatch=true",br.readLine());
-        Assert.assertEquals("context path attr is correct","async:run:attr:contextPath:/foo",br.readLine());
-        Assert.assertEquals("request uri attr is correct","async:run:attr:requestURI:/foo/servletPath",br.readLine());
+        Assert.assertEquals("context path attr is correct","async:run:attr:contextPath:/ctx",br.readLine());
+        Assert.assertEquals("request uri attr is correct","async:run:attr:requestURI:/ctx/servletPath",br.readLine());
     }
 
     @Test
     public void testDispatch() throws Exception
     {
-        String request = "GET /forward HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Connection: close\r\n"
+        String request = "GET /ctx/forward 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);
@@ -189,7 +278,7 @@
     @Test
     public void testDispatchRequestResponse() throws Exception
     {
-        String request = "GET /forward?dispatchRequestResponse=true HTTP/1.1\r\n" + "Host: localhost\r\n"
+        String request = "GET /ctx/forward?dispatchRequestResponse=true 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);
@@ -261,6 +350,49 @@
         }
     }
 
+    @Test
+    public void testExpire() throws Exception
+    {
+        String request = "GET /ctx/expire 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);
+               
+        BufferedReader br = new BufferedReader(new StringReader(responseString));
+
+        assertEquals("HTTP/1.1 500 Async Timeout",br.readLine());
+
+        br.readLine();// connection close
+        br.readLine();// server
+        br.readLine();// empty
+
+        Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
+    }
+
+    @Test
+    public void testBadExpire() throws Exception
+    {
+        String request = "GET /ctx/badexpire 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);
+        
+        BufferedReader br = new BufferedReader(new StringReader(responseString));
+
+        assertEquals("HTTP/1.1 500 Async Exception",br.readLine());
+        br.readLine();// connection close
+        br.readLine();// server
+        br.readLine();// empty
+
+        Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
+        Assert.assertEquals("error servlet","PathInfo= /500",br.readLine());
+        Assert.assertEquals("error servlet","EXCEPTION: java.io.IOException: TEST",br.readLine());
+    }
+
     private class DispatchingRunnable implements Runnable
     {
         private AsyncContext asyncContext;
@@ -287,6 +419,74 @@
         _server.join();
     }
 
+
+    private class ErrorServlet extends HttpServlet
+    {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            response.getOutputStream().print("ERROR: " + request.getServletPath() + "\n");
+            response.getOutputStream().print("PathInfo= " + request.getPathInfo() + "\n");
+            if (request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)!=null)
+                response.getOutputStream().print("EXCEPTION: " + request.getAttribute(RequestDispatcher.ERROR_EXCEPTION) + "\n");
+        }
+    }
+    
+    private class ExpireServlet extends HttpServlet
+    {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            if (request.getDispatcherType()==DispatcherType.REQUEST)
+            {
+                AsyncContext asyncContext = request.startAsync();
+                asyncContext.setTimeout(100);
+            }
+        }
+    }
+    
+    private class BadExpireServlet extends HttpServlet
+    {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            if (request.getDispatcherType()==DispatcherType.REQUEST)
+            {
+                AsyncContext asyncContext = request.startAsync();
+                asyncContext.addListener(new AsyncListener()
+                {
+                    @Override
+                    public void onTimeout(AsyncEvent event) throws IOException
+                    {
+                        throw new IOException("TEST");
+                    }
+                    
+                    @Override
+                    public void onStartAsync(AsyncEvent event) throws IOException
+                    {                      
+                    }
+                    
+                    @Override
+                    public void onError(AsyncEvent event) throws IOException
+                    {                        
+                    }
+                    
+                    @Override
+                    public void onComplete(AsyncEvent event) throws IOException
+                    {                        
+                    }
+                });
+                asyncContext.setTimeout(100);
+            }
+        }
+    }
+    
     private class TestServlet extends HttpServlet
     {
         private static final long serialVersionUID = 1L;
@@ -294,27 +494,18 @@
         @Override
         protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
         {
-            AsyncContinuation continuation = (AsyncContinuation)ContinuationSupport.getContinuation(request);
-
             if (request.getParameter("dispatch") != null)
-            {
-                continuation.suspend();
-                continuation.dispatch("/servletPath2");
-                // AsyncContext asyncContext = request.startAsync(request,response);
+            {                
+                AsyncContext asyncContext = request.startAsync(request,response);
+                asyncContext.dispatch("/servletPath2");
             }
             else
             {
                 response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
+                AsyncContext asyncContext = request.startAsync(request,response);
+                response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)asyncContext.getRequest()).getServletPath() + "\n");
+                asyncContext.start(new AsyncRunnable(asyncContext));
 
-                continuation.suspend();
-
-                // AsyncContext asyncContext = request.startAsync(request,response);
-
-                response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)continuation.getRequest()).getServletPath() + "\n");
-
-                Runnable runable = new AsyncRunnable(continuation);
-                new Thread(runable).start();
-                // asyncContext.start(new AsyncRunnable(asyncContext));
             }
             return;
 
@@ -328,49 +519,70 @@
         @Override
         protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
         {
-            AsyncContinuation continuation = (AsyncContinuation)ContinuationSupport.getContinuation(request);
-
             response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
-
-            continuation.suspend();
-            // AsyncContext asyncContext = request.startAsync(request, response);
-
-            response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)continuation.getRequest()).getServletPath() + "\n");
-            Runnable runable = new AsyncRunnable(continuation);
-            new Thread(runable).start();
-            // asyncContext.start(new AsyncRunnable(asyncContext));
-
+            AsyncContext asyncContext = request.startAsync(request, response);
+            response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)asyncContext.getRequest()).getServletPath() + "\n");         
+            asyncContext.start(new AsyncRunnable(asyncContext));
             return;
         }
     }
+    
+    private class TestStartThrowServlet extends HttpServlet
+    {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            if (request.getDispatcherType()==DispatcherType.REQUEST)
+            {
+                request.startAsync(request, response);
+                
+                if (Boolean.valueOf(request.getParameter("dispatch")))
+                {
+                    request.getAsyncContext().dispatch();
+                }
+
+                if (Boolean.valueOf(request.getParameter("complete")))
+                {
+                    response.getOutputStream().write("completeBeforeThrow".getBytes());
+                    if (Boolean.valueOf(request.getParameter("flush")))
+                        response.flushBuffer();
+                    request.getAsyncContext().complete();
+                }
+                    
+                throw new IOException("Test");
+            }
+        }
+    }
 
     private class AsyncRunnable implements Runnable
     {
-        private AsyncContinuation _continuation;
+        private AsyncContext _context;
 
-        public AsyncRunnable(AsyncContinuation continuation)
+        public AsyncRunnable(AsyncContext context)
         {
-            _continuation = continuation;
+            _context = context;
         }
 
+        @Override
         public void run()
         {
-            HttpServletRequest req = (HttpServletRequest)_continuation.getRequest();
-
+            HttpServletRequest req = (HttpServletRequest)_context.getRequest();         
+                        
             try
             {
-                _continuation.getResponse().getOutputStream().print("async:run:attr:servletPath:" + req.getAttribute(AsyncContext.ASYNC_SERVLET_PATH) + "\n");
-                _continuation.getResponse().getOutputStream().print("async:run:attr:pathInfo:" + req.getAttribute(AsyncContext.ASYNC_PATH_INFO) + "\n");
-                _continuation.getResponse().getOutputStream().print("async:run:attr:queryString:" + req.getAttribute(AsyncContext.ASYNC_QUERY_STRING) + "\n");
-                _continuation.getResponse().getOutputStream().print("async:run:attr:contextPath:" + req.getAttribute(AsyncContext.ASYNC_CONTEXT_PATH) + "\n");
-                _continuation.getResponse().getOutputStream().print("async:run:attr:requestURI:" + req.getAttribute(AsyncContext.ASYNC_REQUEST_URI) + "\n");
+                _context.getResponse().getOutputStream().print("async:run:attr:servletPath:" + req.getAttribute(AsyncContext.ASYNC_SERVLET_PATH) + "\n");
+                _context.getResponse().getOutputStream().print("async:run:attr:pathInfo:" + req.getAttribute(AsyncContext.ASYNC_PATH_INFO) + "\n");              
+                _context.getResponse().getOutputStream().print("async:run:attr:queryString:" + req.getAttribute(AsyncContext.ASYNC_QUERY_STRING) + "\n");              
+                _context.getResponse().getOutputStream().print("async:run:attr:contextPath:" + req.getAttribute(AsyncContext.ASYNC_CONTEXT_PATH) + "\n");              
+                _context.getResponse().getOutputStream().print("async:run:attr:requestURI:" + req.getAttribute(AsyncContext.ASYNC_REQUEST_URI) + "\n");              
             }
             catch (IOException e)
             {
                 e.printStackTrace();
             }
-
-            _continuation.complete();
+            _context.complete();         
         }
     }
 
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
new file mode 100644
index 0000000..f5968e2
--- /dev/null
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java
@@ -0,0 +1,775 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequestWrapper;
+import javax.servlet.ServletResponseWrapper;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.eclipse.jetty.util.IO;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class AsyncServletTest 
+{    
+
+    protected AsyncServlet _servlet=new AsyncServlet();
+    protected int _port;
+
+    protected Server _server = new Server();
+    protected ServletHandler _servletHandler;
+    protected SelectChannelConnector _connector;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        _connector = new SelectChannelConnector();
+        _server.setConnectors(new Connector[]{ _connector });
+        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SECURITY|ServletContextHandler.NO_SESSIONS);
+        context.setContextPath("/ctx");
+        _server.setHandler(context);
+        _servletHandler=context.getServletHandler();
+        ServletHolder holder=new ServletHolder(_servlet);
+        holder.setAsyncSupported(true);
+        _servletHandler.addServletWithMapping(holder,"/path/*");
+        _servletHandler.addServletWithMapping(holder,"/path1/*");
+        _servletHandler.addServletWithMapping(holder,"/path2/*");
+        _servletHandler.addServletWithMapping(new ServletHolder(new FwdServlet()),"/fwd/*");
+        _server.start();
+        _port=_connector.getLocalPort();
+    }
+
+    @After
+    public void tearDown() throws Exception
+    {
+        _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 /path\r\n"+
+                "history: initial\r\n",response);
+        assertContains("NORMAL",response);
+        assertNotContains("history: onTimeout",response);
+        assertNotContains("history: onComplete",response);
+    }
+
+    @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 /path\r\n"+
+                "history: initial\r\n",response);
+        assertContains("SLEPT",response);
+        assertNotContains("history: onTimeout",response);
+        assertNotContains("history: onComplete",response);
+    }
+
+    @Test
+    public void testSuspend() throws Exception
+    {
+        String response=process("suspend=200",null);
+        assertEquals("HTTP/1.1 500 Async Timeout",response.substring(0,26));
+        assertContains(
+            "history: REQUEST /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: onTimeout\r\n"+
+            "history: ERROR /path\r\n"+
+            "history: !initial\r\n"+
+            "history: onComplete\r\n",response);
+                    
+        assertContains("ERROR: /ctx/path/info",response);
+    }
+    
+    @Test
+    public void testSuspendOnTimeoutDispatch() throws Exception
+    {
+        String response=process("suspend=200&timeout=dispatch",null);
+        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
+        assertContains(
+            "history: REQUEST /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: onTimeout\r\n"+
+            "history: dispatch\r\n"+
+            "history: ASYNC /path\r\n"+
+            "history: !initial\r\n"+
+            "history: onComplete\r\n",response);
+                    
+        assertContains("DISPATCHED",response);
+    }
+    
+    @Test
+    public void testSuspendOnTimeoutComplete() throws Exception
+    {
+        String response=process("suspend=200&timeout=complete",null);
+        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
+        assertContains(
+            "history: REQUEST /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: onTimeout\r\n"+
+            "history: complete\r\n"+
+            "history: onComplete\r\n",response);
+                    
+        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 /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path\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 /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path\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 /path\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 /path\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 /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path\r\n"+
+            "history: !initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path\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 /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path\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
+    {
+        String response=process("suspend=1000&resume=10&suspend2=10",null);
+        assertEquals("HTTP/1.1 500 Async Timeout",response.substring(0,26));
+        assertContains(
+            "history: REQUEST /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path\r\n"+
+            "history: !initial\r\n"+
+            "history: suspend\r\n"+
+            "history: onTimeout\r\n"+
+            "history: ERROR /path\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 /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: onTimeout\r\n"+
+            "history: ERROR /path\r\n"+
+            "history: !initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path\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 /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: onTimeout\r\n"+
+            "history: ERROR /path\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
+    {
+        String response=process("suspend=10&suspend2=10",null);
+        assertContains(
+            "history: REQUEST /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: onTimeout\r\n"+
+            "history: ERROR /path\r\n"+
+            "history: !initial\r\n"+
+            "history: suspend\r\n"+
+            "history: onTimeout\r\n"+
+            "history: ERROR /path\r\n"+
+            "history: !initial\r\n"+
+            "history: onComplete\r\n",response);
+        assertContains("ERROR: /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 /path\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path\r\n"+
+            "history: wrapped REQ RSP\r\n"+
+            "history: !initial\r\n"+
+            "history: onComplete\r\n",response);
+        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 /fwd\r\n"+
+            "history: FORWARD /path1\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: FWD ASYNC /fwd\r\n"+
+            "history: FORWARD /path1\r\n"+
+            "history: !initial\r\n",response);
+        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 /fwd\r\n"+
+            "history: FORWARD /path1\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path2\r\n"+
+            "history: !initial\r\n"+
+            "history: onComplete\r\n",response);
+        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 /fwd\r\n"+
+            "history: FORWARD /path1\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path1\r\n"+
+            "history: wrapped REQ RSP\r\n"+
+            "history: !initial\r\n"+
+            "history: onComplete\r\n",response);
+        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 /fwd\r\n"+
+            "history: FORWARD /path1\r\n"+
+            "history: initial\r\n"+
+            "history: suspend\r\n"+
+            "history: resume\r\n"+
+            "history: ASYNC /path2\r\n"+
+            "history: wrapped REQ RSP\r\n"+
+            "history: !initial\r\n"+
+            "history: onComplete\r\n",response);
+        assertContains("DISPATCHED",response);
+    }
+    
+    
+    
+    protected void assertContains(String content,String response)
+    {
+        Assert.assertThat(response,Matchers.containsString(content));
+    }
+    
+    protected void assertNotContains(String content,String response)
+    {
+        Assert.assertThat(response,Matchers.not(Matchers.containsString(content)));
+    }
+    
+    public synchronized String process(String query,String content) throws Exception
+    {
+        return process("path",query,content);
+    }
+    
+    public synchronized String process(String path,String query,String content) throws Exception
+    {
+        String request = "GET /ctx/"+path+"/info";
+        
+        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(1000000);
+            socket.getOutputStream().write(request.getBytes("UTF-8"));
+
+            response = IO.toString(socket.getInputStream());
+        }
+        catch(Exception e)
+        {
+            System.err.println("failed on port "+port);
+            e.printStackTrace();
+            throw e;
+        }
+        return response;
+    }
+
+    private static class FwdServlet extends HttpServlet
+    {
+        @Override
+        public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+        {
+            response.addHeader("history","FWD "+request.getDispatcherType()+" "+request.getServletPath());
+            if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper)
+                response.addHeader("history","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;
+        private Timer _timer=new Timer();
+        
+        public AsyncServlet()
+        {}
+        
+        /* ------------------------------------------------------------ */
+        @Override
+        public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+        {
+            response.addHeader("history",request.getDispatcherType()+" "+request.getServletPath());
+            if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper)
+                response.addHeader("history","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 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"));
+            final String path=request.getParameter("path");
+            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.getAttribute("State")==null)
+            {
+                request.setAttribute("State",new Integer(1));
+                
+                ((HttpServletResponse)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)
+                {
+                    final AsyncContext async=wrap?request.startAsync(new HttpServletRequestWrapper(request),new HttpServletResponseWrapper(response)):request.startAsync();
+                    if (suspend_for>0)
+                        async.setTimeout(suspend_for);
+                    async.addListener(__listener);
+                    ((HttpServletResponse)response).addHeader("history","suspend");
+                    
+                    if (complete_after>0)
+                    {
+                        TimerTask complete = new TimerTask()
+                        {
+                            @Override
+                            public void run()
+                            {
+                                try
+                                {
+                                    response.setStatus(200);
+                                    response.getOutputStream().println("COMPLETED\n");
+                                    response.addHeader("history","complete");
+                                    async.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");
+                        response.addHeader("history","complete");
+                        async.complete();
+                    }
+                    else if (resume_after>0)
+                    {
+                        TimerTask resume = new TimerTask()
+                        {
+                            @Override
+                            public void run()
+                            {
+                                ((HttpServletResponse)async.getResponse()).addHeader("history","resume");
+                                if (path!=null)             
+                                    async.dispatch(path);
+                                else
+                                    async.dispatch();
+                            }
+                        };
+                        synchronized (_timer)
+                        {
+                            _timer.schedule(resume,resume_after);
+                        }
+                    }
+                    else if (resume_after==0)
+                    {
+                        ((HttpServletResponse)async.getResponse()).addHeader("history","resume");
+                        if (path!=null)             
+                            async.dispatch(path);
+                        else
+                            async.dispatch();
+                    }
+                    
+                }
+                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
+            {
+                ((HttpServletResponse)response).addHeader("history","!initial");
+
+                if (suspend2_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)
+                    {
+                        async.setTimeout(suspend2_for);
+                    }
+                    // continuation.addContinuationListener(__listener);
+                    ((HttpServletResponse)response).addHeader("history","suspend");
+
+                    if (complete2_after>0)
+                    {
+                        TimerTask complete = new TimerTask()
+                        {
+                            @Override
+                            public void run()
+                            {
+                                try
+                                {
+                                    response.setStatus(200);
+                                    response.getOutputStream().println("COMPLETED\n");
+                                    response.addHeader("history","complete");
+                                    async.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");
+                        response.addHeader("history","complete");
+                        async.complete();
+                    }
+                    else if (resume2_after>0)
+                    {
+                        TimerTask resume = new TimerTask()
+                        {
+                            @Override
+                            public void run()
+                            {
+                                ((HttpServletResponse)response).addHeader("history","resume");
+                                async.dispatch();
+                            }
+                        };
+                        synchronized (_timer)
+                        {
+                            _timer.schedule(resume,resume2_after);
+                        }
+                    }
+                    else if (resume2_after==0)
+                    {
+                        ((HttpServletResponse)response).addHeader("history","dispatch");
+                        async.dispatch();
+                    }
+                }
+                else if(request.getDispatcherType()==DispatcherType.ERROR)
+                {
+                    response.getOutputStream().println("ERROR: "+request.getContextPath()+request.getServletPath()+request.getPathInfo());
+                }
+                else
+                {
+                    response.setStatus(200);
+                    response.getOutputStream().println("DISPATCHED");
+                }
+            }
+        }
+    }
+    
+    
+    private static AsyncListener __listener = new AsyncListener()
+    {
+        @Override
+        public void onTimeout(AsyncEvent event) throws IOException
+        {            
+            ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history","onTimeout");
+            String action=((HttpServletRequest)event.getSuppliedRequest()).getParameter("timeout");
+            if (action!=null)
+            {
+                ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history",action);
+                if ("dispatch".equals(action))
+                    event.getAsyncContext().dispatch();
+                if ("complete".equals(action))
+                {
+                    ((HttpServletResponse)event.getSuppliedResponse()).getOutputStream().println("COMPLETED\n");
+                    event.getAsyncContext().complete();
+                }
+            }
+        }
+        
+        @Override
+        public void onStartAsync(AsyncEvent event) throws IOException
+        {
+            // TODO Auto-generated method stub
+            
+        }
+        
+        @Override
+        public void onError(AsyncEvent event) throws IOException
+        {
+            // TODO Auto-generated method stub
+            
+        }
+        
+        @Override
+        public void onComplete(AsyncEvent event) throws IOException
+        {
+            ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history","onComplete");
+        }
+    };
+
+}
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 ce403ba..9983ea8 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,9 +23,10 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.EnumSet;
+import javax.servlet.DispatcherType;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
@@ -42,7 +43,6 @@
 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.DateCache;
 import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.StringUtil;
 import org.hamcrest.Matchers;
@@ -659,7 +659,7 @@
         assertResponseContains("Content-Length: 12", response);
         assertResponseNotContains("Extra Info", response);
 
-        context.addFilter(OutputFilter.class, "/*", 0);
+        context.addFilter(OutputFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
         response = connector.getResponses("GET /context/data0.txt HTTP/1.1\r\nHost:localhost:8080\r\n\r\n");
         assertResponseContains("Content-Length: 2", response); // 20 something long
         assertResponseContains("Extra Info", response);
@@ -668,7 +668,7 @@
         context.getServletHandler().setFilterMappings(new FilterMapping[]{});
         context.getServletHandler().setFilters(new FilterHolder[]{});
 
-        context.addFilter(WriterFilter.class, "/*", 0);
+        context.addFilter(WriterFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
         response = connector.getResponses("GET /context/data0.txt HTTP/1.1\r\nHost:localhost:8080\r\n\r\n");
         assertResponseContains("Content-Length: 2", response); // 20 something long
         assertResponseContains("Extra Info", response);
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 b31eaf4..ceec453 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
@@ -26,9 +26,11 @@
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Enumeration;
+import java.util.EnumSet;
+import java.util.HashMap;
 import java.util.List;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
@@ -225,6 +227,32 @@
     }
     
     @Test
+    public void testServletForwardDotDot() throws Exception
+    {
+        _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*");
+        _contextHandler.addServlet(RogerThatServlet.class, "/roger/that");
+
+        String requests="GET /context/dispatch/test?forward=/%2e%2e/roger/that HTTP/1.0\n" + "Host: localhost\n\n";
+
+        String responses = _connector.getResponses(requests);
+
+        assertThat(responses,startsWith("HTTP/1.1 404 "));
+    }
+    
+    @Test
+    public void testServletForwardEncodedDotDot() throws Exception
+    {
+        _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*");
+        _contextHandler.addServlet(RogerThatServlet.class, "/roger/that");
+
+        String requests="GET /context/dispatch/test?forward=/%252e%252e/roger/that HTTP/1.0\n" + "Host: localhost\n\n";
+
+        String responses = _connector.getResponses(requests);
+
+        assertThat(responses,startsWith("HTTP/1.1 404 "));
+    }
+    
+    @Test
     public void testServletInclude() throws Exception
     {
         _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*");
@@ -301,7 +329,7 @@
         _contextHandler.addServlet(RogerThatServlet.class, "/*");
         _contextHandler.addServlet(ReserveEchoServlet.class,"/recho/*");
         _contextHandler.addServlet(EchoServlet.class, "/echo/*");
-        _contextHandler.addFilter(ForwardFilter.class, "/*", FilterMapping.REQUEST);
+        _contextHandler.addFilter(ForwardFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         String rogerResponse = _connector.getResponses("GET /context/ HTTP/1.0\n" + "Host: localhost\n\n");
 
@@ -416,7 +444,10 @@
             else if(request.getParameter("forward")!=null)
             {
                 dispatcher = getServletContext().getRequestDispatcher(request.getParameter("forward"));
-                dispatcher.forward(new ServletRequestWrapper(request), new ServletResponseWrapper(response));
+                if (dispatcher!=null)
+                    dispatcher.forward(new ServletRequestWrapper(request), new ServletResponseWrapper(response));
+                else
+                    response.sendError(404);
             }
             
         }
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/HolderTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/HolderTest.java
new file mode 100644
index 0000000..a6a3256
--- /dev/null
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/HolderTest.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.
+//  ========================================================================
+//
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.eclipse.jetty.servlet;
+
+import java.util.Collections;
+import java.util.Set;
+
+import javax.servlet.Registration;
+import javax.servlet.ServletRegistration;
+import org.junit.Test;
+
+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 static org.junit.Assert.fail;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class HolderTest {
+    
+    @Test
+    public void testInitParams() throws Exception {
+        ServletHolder holder = new ServletHolder(Holder.Source.JAVAX_API);
+        ServletRegistration reg = holder.getRegistration();
+        try {
+            reg.setInitParameter(null, "foo");
+            fail("null name accepted");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            reg.setInitParameter("foo", null);
+            fail("null value accepted");
+        } catch (IllegalArgumentException e) {
+        }
+        reg.setInitParameter("foo", "bar");
+        assertFalse(reg.setInitParameter("foo", "foo"));
+
+        Set<String> clash = reg.setInitParameters(Collections.singletonMap("foo", "bax"));
+        assertTrue("should be one clash", clash != null && clash.size() == 1);
+
+        try {
+            reg.setInitParameters(Collections.singletonMap((String)null, "bax"));
+            fail("null name in map accepted");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            reg.setInitParameters(Collections.singletonMap("foo", (String)null));
+            fail("null value in map accepted");
+        } catch (IllegalArgumentException e) {
+        }
+
+        Set<String> clash2 = reg.setInitParameters(Collections.singletonMap("FOO", "bax"));
+        assertTrue("should be no clash", clash2.isEmpty());
+        assertEquals("setInitParameters should not replace existing non-clashing init parameters", 2, reg.getInitParameters().size());
+
+    }
+}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java
new file mode 100644
index 0000000..05acf62
--- /dev/null
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java
@@ -0,0 +1,425 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.servlet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
+
+import org.eclipse.jetty.servlet.Holder.Source;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ServletHandlerTest
+{
+    FilterHolder fh1 = new FilterHolder(Holder.Source.DESCRIPTOR);
+    FilterMapping fm1 = new FilterMapping();
+    
+    FilterHolder fh2 = new FilterHolder(Holder.Source.DESCRIPTOR);
+    FilterMapping fm2 = new FilterMapping();
+    
+    FilterHolder fh3 = new FilterHolder(Holder.Source.JAVAX_API);
+    FilterMapping fm3 = new FilterMapping();
+    
+    FilterHolder fh4 = new FilterHolder(Holder.Source.JAVAX_API);
+    FilterMapping fm4 = new FilterMapping();
+    
+    FilterHolder fh5 = new FilterHolder(Holder.Source.JAVAX_API);
+    FilterMapping fm5 = new FilterMapping();
+    
+    
+
+    @Before
+    public void initMappings()
+    {
+        fh1.setName("fh1");
+        fm1.setPathSpec("/*");
+        fm1.setFilterHolder(fh1);
+
+        fh2.setName("fh2");
+        fm2.setPathSpec("/*");
+        fm2.setFilterHolder(fh2);
+        
+        fh3.setName("fh3");
+        fm3.setPathSpec("/*");
+        fm3.setFilterHolder(fh3);
+
+        fh4.setName("fh4");
+        fm4.setPathSpec("/*");
+        fm4.setFilterHolder(fh4);
+        
+        fh5.setName("fh5");
+        fm5.setPathSpec("/*");
+        fm5.setFilterHolder(fh5);
+    }
+
+    @Test
+    public void testAllNonProgrammaticFilterMappings() throws Exception
+    {
+        ServletHandler handler = new ServletHandler(); 
+        handler.addFilter(fh1);
+        handler.addFilter(fh2);
+        
+        //add some ordinary filter mappings
+        handler.addFilterMapping(fm1);
+        handler.addFilterMapping(fm2);
+        
+        FilterMapping[] mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertTrue(fm1 == mappings[0]);
+        assertTrue(fm2 == mappings[1]);
+        
+        //add another ordinary mapping
+        FilterHolder of1 = new FilterHolder(Source.DESCRIPTOR);
+        FilterMapping ofm1 = new FilterMapping();
+        ofm1.setFilterHolder(of1);
+        ofm1.setPathSpec("/*");
+        handler.addFilter(of1);
+        handler.addFilterMapping(ofm1);
+        
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertTrue(fm1 == mappings[0]);
+        assertTrue(fm2 == mappings[1]);
+        assertTrue(ofm1 == mappings[2]);
+    }
+    
+    
+    
+    @Test
+    public void testAllBeforeFilterMappings() throws Exception
+    {
+        ServletHandler handler = new ServletHandler(); 
+        
+        //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=false)
+        handler.addFilter(fh4);
+        handler.prependFilterMapping(fm4);
+        
+        FilterMapping[] mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(1, mappings.length);
+        
+        //add another with isMatchAfter=false
+        handler.addFilter(fh5);
+        handler.prependFilterMapping(fm5);
+        
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(2, mappings.length);
+        
+        assertTrue(fm4 == mappings[0]);
+        assertTrue(fm5 == mappings[1]);
+    }
+    
+    @Test
+    public void testAllAfterFilterMappings() throws Exception
+    {
+        ServletHandler handler = new ServletHandler(); 
+        //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
+        handler.addFilter(fh4);
+        handler.addFilterMapping(fm4);
+        FilterMapping[] mappings = handler.getFilterMappings();
+        assertEquals(1, mappings.length);
+        assertTrue(fm4 == mappings[0]);
+        
+        //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
+        handler.addFilter(fh5);
+        handler.addFilterMapping(fm5);
+        mappings = handler.getFilterMappings();
+        assertEquals(2, mappings.length);
+        assertTrue(fm4 == mappings[0]);
+        assertTrue(fm5 == mappings[1]);
+    }
+    
+    
+    @Test
+    public void testMatchAfterAndBefore() throws Exception
+    {
+        ServletHandler handler = new ServletHandler();
+        
+        //add a programmatic one, isMatchAfter=true
+        handler.addFilter(fh3);
+        handler.addFilterMapping(fm3);
+        FilterMapping[]  mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(1, mappings.length);
+        assertTrue(fm3 == mappings[0]);
+        
+        //add a programmatic one, isMatchAfter=false
+        handler.addFilter(fh4);
+        handler.prependFilterMapping(fm4);
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(2, mappings.length);
+        assertTrue(fm4 == mappings[0]);
+        assertTrue(fm3 == mappings[1]);  
+    }
+    
+    
+    @Test
+    public void testMatchBeforeAndAfter() throws Exception
+    {
+        ServletHandler handler = new ServletHandler();
+        
+        //add a programmatic one, isMatchAfter=false
+        handler.addFilter(fh3);
+        handler.prependFilterMapping(fm3);
+        FilterMapping[]  mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(1, mappings.length);
+        assertTrue(fm3 == mappings[0]);
+        
+        //add a programmatic one, isMatchAfter=true
+        handler.addFilter(fh4);
+        handler.addFilterMapping(fm4);
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(2, mappings.length);
+        assertTrue(fm3 == mappings[0]); 
+        assertTrue(fm4 == mappings[1]);
+    }
+    
+    
+    @Test
+    public void testExistingFilterMappings() throws Exception
+    {
+        ServletHandler handler = new ServletHandler();
+        handler.addFilter(fh1);
+        handler.addFilter(fh2);
+        
+        //add some ordinary filter mappings first
+        handler.addFilterMapping(fm1);
+        handler.addFilterMapping(fm2);
+        
+        FilterMapping[] mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertTrue(fm1 == mappings[0]);
+        assertTrue(fm2 == mappings[1]);
+        
+        //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=false)
+        handler.addFilter(fh4);
+        handler.prependFilterMapping(fm4);
+        mappings = handler.getFilterMappings();
+        assertEquals(3, mappings.length);
+        assertTrue(fm4 == mappings[0]);
+        
+        //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
+        handler.addFilter(fh5);
+        handler.addFilterMapping(fm5);
+        mappings = handler.getFilterMappings();
+        assertEquals(4, mappings.length);
+        assertTrue(fm5 == mappings[mappings.length-1]);
+    }
+    
+    @Test
+    public void testFilterMappingsMix() throws Exception
+    {
+        ServletHandler handler = new ServletHandler();
+
+        //add a non-programmatic one to begin with
+        handler.addFilter(fh1);
+        handler.addFilterMapping(fm1); 
+        FilterMapping[] mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertTrue(fm1 == mappings[0]);
+
+        //add a programmatic one, isMatchAfter=false
+        handler.addFilter(fh4);
+        handler.prependFilterMapping(fm4);
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(2, mappings.length);
+        assertTrue(fm4 == mappings[0]);
+        assertTrue(fm1 == mappings[1]);
+        
+        //add a programmatic one, isMatchAfter=true
+        handler.addFilter(fh3);
+        handler.addFilterMapping(fm3);
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(3, mappings.length);
+        assertTrue(fm4 == mappings[0]);
+        assertTrue(fm1 == mappings[1]);
+        assertTrue(fm3 == mappings[2]);
+        
+        //add a programmatic one, isMatchAfter=false
+        handler.addFilter(fh5);
+        handler.prependFilterMapping(fm5);
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(4, mappings.length);
+        assertTrue(fm4 == mappings[0]);//isMatchAfter = false;
+        assertTrue(fm5 == mappings[1]);//isMatchAfter = false;
+        assertTrue(fm1 == mappings[2]);//ordinary
+        assertTrue(fm3 == mappings[3]);//isMatchAfter = true;
+           
+        //add a non-programmatic one
+        FilterHolder f = new FilterHolder(Source.EMBEDDED);
+        f.setName("non-programmatic");
+        FilterMapping fm = new FilterMapping();
+        fm.setFilterHolder(f);
+        fm.setPathSpec("/*");
+        handler.addFilter(f);
+        handler.addFilterMapping(fm);
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(5, mappings.length);
+        assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
+        assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
+        assertTrue(fm1 == mappings[2]); //ordinary
+        assertTrue(fm == mappings[3]);  //ordinary
+        assertTrue(fm3 == mappings[4]); //isMatchAfter = true;
+        
+        //add a programmatic one, isMatchAfter=true
+        FilterHolder pf = new FilterHolder(Source.JAVAX_API);
+        pf.setName("programmaticA");
+        FilterMapping pfm = new FilterMapping();
+        pfm.setFilterHolder(pf);
+        pfm.setPathSpec("/*");
+        handler.addFilter(pf);
+        handler.addFilterMapping(pfm);
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(6, mappings.length);
+        assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
+        assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
+        assertTrue(fm1 == mappings[2]); //ordinary
+        assertTrue(fm == mappings[3]);  //ordinary
+        assertTrue(fm3 == mappings[4]); //isMatchAfter = true;
+        assertTrue(pfm == mappings[5]); //isMatchAfter = true;
+        
+        //add a programmatic one, isMatchAfter=false
+        FilterHolder pf2 = new FilterHolder(Source.JAVAX_API);
+        pf2.setName("programmaticB");
+        FilterMapping pfm2 = new FilterMapping();
+        pfm2.setFilterHolder(pf2);
+        pfm2.setPathSpec("/*");
+        handler.addFilter(pf2);
+        handler.prependFilterMapping(pfm2);
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(7, mappings.length);
+        assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
+        assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
+        assertTrue(pfm2 == mappings[2]);//isMatchAfter = false;
+        assertTrue(fm1 == mappings[3]); //ordinary
+        assertTrue(fm == mappings[4]);  //ordinary
+        assertTrue(fm3 == mappings[5]); //isMatchAfter = true;
+        assertTrue(pfm == mappings[6]); //isMatchAfter = true;
+    }
+  
+    @Test
+    public void testAddFilterWithMappingAPI() throws Exception
+    {
+        ServletHandler handler = new ServletHandler();
+
+        //add a non-programmatic one to begin with
+        handler.addFilterWithMapping(fh1, "/*", EnumSet.allOf(DispatcherType.class));           
+        FilterMapping[] mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertTrue(fh1 == mappings[0].getFilterHolder());
+
+        //add a programmatic one, isMatchAfter=false
+        fh4.setServletHandler(handler);
+        handler.addFilter(fh4);
+        fh4.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(2, mappings.length);
+        assertTrue(fh4 == mappings[0].getFilterHolder());
+        assertTrue(fh1 == mappings[1].getFilterHolder());
+        
+        //add a programmatic one, isMatchAfter=true
+        fh3.setServletHandler(handler);
+        handler.addFilter(fh3);
+        fh3.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(3, mappings.length);
+        assertTrue(fh4 == mappings[0].getFilterHolder());
+        assertTrue(fh1 == mappings[1].getFilterHolder());
+        assertTrue(fh3 == mappings[2].getFilterHolder());
+        
+        //add a programmatic one, isMatchAfter=false
+        fh5.setServletHandler(handler);
+        handler.addFilter(fh5);
+        fh5.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(4, mappings.length);
+        assertTrue(fh4 == mappings[0].getFilterHolder());//isMatchAfter = false;
+        assertTrue(fh5 == mappings[1].getFilterHolder());//isMatchAfter = false;
+        assertTrue(fh1 == mappings[2].getFilterHolder());//ordinary
+        assertTrue(fh3 == mappings[3].getFilterHolder());//isMatchAfter = true;
+           
+        //add a non-programmatic one
+        FilterHolder f = new FilterHolder(Source.EMBEDDED);
+        f.setName("non-programmatic");     
+        handler.addFilterWithMapping(f, "/*", EnumSet.allOf(DispatcherType.class));
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(5, mappings.length);
+        assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
+        assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
+        assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary
+        assertTrue(f == mappings[3].getFilterHolder());  //ordinary
+        assertTrue(fh3 == mappings[4].getFilterHolder()); //isMatchAfter = true;
+        
+        //add a programmatic one, isMatchAfter=true
+        FilterHolder pf = new FilterHolder(Source.JAVAX_API);
+        pf.setServletHandler(handler);
+        pf.setName("programmaticA");
+        handler.addFilter(pf);
+        pf.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
+        mappings = handler.getFilterMappings();
+        assertNotNull(mappings);
+        assertEquals(6, mappings.length);
+        assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
+        assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
+        assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary
+        assertTrue(f == mappings[3].getFilterHolder());  //ordinary
+        assertTrue(fh3 == mappings[4].getFilterHolder()); //isMatchAfter = true;
+        assertTrue(pf == mappings[5].getFilterHolder()); //isMatchAfter = true;
+        
+        //add a programmatic one, isMatchAfter=false
+        FilterHolder pf2 = new FilterHolder(Source.JAVAX_API);
+        pf2.setServletHandler(handler);
+        pf2.setName("programmaticB");
+        handler.addFilter(pf2);
+        pf2.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
+        mappings = handler.getFilterMappings();
+
+        assertNotNull(mappings);
+        assertEquals(7, mappings.length);
+        assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
+        assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
+        assertTrue(pf2 == mappings[2].getFilterHolder());//isMatchAfter = false;
+        assertTrue(fh1 == mappings[3].getFilterHolder()); //ordinary
+        assertTrue(f == mappings[4].getFilterHolder());  //ordinary
+        assertTrue(fh3 == mappings[5].getFilterHolder()); //isMatchAfter = true;
+        assertTrue(pf == mappings[6].getFilterHolder()); //isMatchAfter = true;
+    }
+  
+    
+    
+}
diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml
index c21ec42..50b69df 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-servlets</artifactId>
@@ -24,6 +24,11 @@
             <goals>
               <goal>manifest</goal>
             </goals>
+            <configuration>
+              <instructions>
+                <Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
+              </instructions>
+            </configuration>
           </execution>
         </executions>
       </plugin>
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 4de1fa9..d8a5e19 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
@@ -347,7 +347,6 @@
             }
 
             // We are over the limit.
-            LOG.warn("DOS ALERT: ip=" + request.getRemoteAddr() + ",session=" + request.getRequestedSessionId() + ",user=" + request.getUserPrincipal());
 
             // So either reject it, delay it or throttle it
             long delayMs = getDelayMs();
@@ -357,6 +356,7 @@
                 case -1:
                 {
                     // Reject this request
+                    LOG.warn("DOS ALERT: Request rejected ip=" + request.getRemoteAddr() + ",session=" + request.getRequestedSessionId() + ",user=" + request.getUserPrincipal());
                     if (insertHeaders)
                         response.addHeader("DoSFilter", "unavailable");
                     response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
@@ -365,12 +365,14 @@
                 case 0:
                 {
                     // fall through to throttle code
+                    LOG.warn("DOS ALERT: Request throttled ip=" + request.getRemoteAddr() + ",session=" + request.getRequestedSessionId() + ",user=" + request.getUserPrincipal());
                     request.setAttribute(__TRACKER, tracker);
                     break;
                 }
                 default:
                 {
                     // insert a delay before throttling the request
+                    LOG.warn("DOS ALERT: Request delayed="+delayMs+"ms ip=" + request.getRemoteAddr() + ",session=" + request.getRequestedSessionId() + ",user=" + request.getUserPrincipal());
                     if (insertHeaders)
                         response.addHeader("DoSFilter", "delayed");
                     Continuation continuation = ContinuationSupport.getContinuation(request);
@@ -714,6 +716,7 @@
 
     public void destroy()
     {
+        LOG.debug("Destroy {}",this);
         _running = false;
         _timerThread.interrupt();
         _requestTimeoutQ.cancelAll();
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 044d314..b51afbd 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
@@ -433,7 +433,30 @@
                         @Override
                         protected DeflaterOutputStream createStream() throws IOException
                         {
-                            return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
+                            return new GZIPOutputStream(_response.getOutputStream(),_bufferSize)
+                            {
+                                /**
+                                 * Work around a bug in the jvm GzipOutputStream whereby it is not
+                                 * thread safe when thread A calls finish, but thread B is writing
+                                 * @see java.util.zip.GZIPOutputStream#finish()
+                                 */
+                                @Override
+                                public synchronized void finish() throws IOException
+                                {
+                                    super.finish();
+                                }
+                                
+                                /**
+                                 * Work around a bug in the jvm GzipOutputStream whereby it is not
+                                 * thread safe when thread A calls close(), but thread B is writing
+                                 * @see java.util.zip.GZIPOutputStream#close()
+                                 */
+                                @Override
+                                public synchronized void close() throws IOException
+                                {
+                                    super.close();
+                                }           
+                            };
                         }
                     };
                 }
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 065eb0e..8d6e16d 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
@@ -18,18 +18,17 @@
 
 package org.eclipse.jetty.servlets;
 
+import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
-import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -41,20 +40,22 @@
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
+import javax.servlet.MultipartConfigElement;
 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.HttpServletRequestWrapper;
+import javax.servlet.http.Part;
 
+import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.io.ByteArrayBuffer;
-import org.eclipse.jetty.util.B64Code;
 import org.eclipse.jetty.util.LazyList;
 import org.eclipse.jetty.util.MultiMap;
+import org.eclipse.jetty.util.MultiPartInputStream;
 import org.eclipse.jetty.util.QuotedStringTokenizer;
-import org.eclipse.jetty.util.ReadLineInputStream;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.util.log.Log;
@@ -79,16 +80,22 @@
  * The init parameter deleteFiles controls if uploaded files are automatically deleted after the request
  * completes.
  * 
+ * Use init parameter "maxFileSize" to set the max size file that can be uploaded.
+ * 
+ * Use init parameter "maxRequestSize" to limit the size of the multipart request.
+ * 
  */
 public class MultiPartFilter implements Filter
 {
     private static final Logger LOG = Log.getLogger(MultiPartFilter.class);
     public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
-    private final static String FILES ="org.eclipse.jetty.servlet.MultiPartFilter.files";
+    private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
     private File tempdir;
     private boolean _deleteFiles;
     private ServletContext _context;
     private int _fileOutputBuffer = 0;
+    private long _maxFileSize = -1L;
+    private long _maxRequestSize = -1L;
     private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",1000).intValue();
 
     /* ------------------------------------------------------------------------------- */
@@ -102,6 +109,13 @@
         String fileOutputBuffer = filterConfig.getInitParameter("fileOutputBuffer");
         if(fileOutputBuffer!=null)
             _fileOutputBuffer = Integer.parseInt(fileOutputBuffer);
+        String maxFileSize = filterConfig.getInitParameter("maxFileSize");
+        if (maxFileSize != null)
+            _maxFileSize = Long.parseLong(maxFileSize.trim());
+        String maxRequestSize = filterConfig.getInitParameter("maxRequestSize");
+        if (maxRequestSize != null)
+            _maxRequestSize = Long.parseLong(maxRequestSize.trim());
+        
         _context=filterConfig.getServletContext();
         String mfks = filterConfig.getInitParameter("maxFormKeys");
         if (mfks!=null)
@@ -123,27 +137,14 @@
             return;
         }
 
-        InputStream in = new ReadLineInputStream(request.getInputStream());
+        InputStream in = new BufferedInputStream(request.getInputStream());
         String content_type=srequest.getContentType();
-
-        // TODO - handle encodings
-        String contentTypeBoundary = "";
-        int bstart = content_type.indexOf("boundary=");
-        if (bstart >= 0)
-        {
-            int bend = content_type.indexOf(";", bstart);
-            bend = (bend < 0? content_type.length(): bend);
-            contentTypeBoundary = QuotedStringTokenizer.unquote(value(content_type.substring(bstart,bend)).trim());
-        }
-
-        String boundary="--"+contentTypeBoundary;
         
-        byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1);
-        
-        MultiMap params = new MultiMap();
-        for (Iterator i = request.getParameterMap().entrySet().iterator();i.hasNext();)
+        //Get current parameters so we can merge into them
+        MultiMap<String> params = new MultiMap<String>();
+        for (Iterator<Map.Entry<String,String[]>> i = request.getParameterMap().entrySet().iterator();i.hasNext();)
         {
-            Map.Entry entry=(Map.Entry)i.next();
+            Map.Entry<String,String[]> entry=i.next();
             Object value=entry.getValue();
             if (value instanceof String[])
                 params.addValues(entry.getKey(),(String[])value);
@@ -151,327 +152,74 @@
                 params.add(entry.getKey(),value);
         }
         
-        boolean badFormatLogged = false;
+        MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer);
+        MultiPartInputStream mpis = new MultiPartInputStream(in, content_type, config, tempdir);
+        mpis.setDeleteOnExit(_deleteFiles);
+        request.setAttribute(MULTIPART, mpis);
+
         try
         {
-            // Get first boundary
-            String line=((ReadLineInputStream)in).readLine();
-
-            if (line == null)
-                throw new IOException("Missing content for multipart request");
-
-            line = line.trim();
-        
-            while (line != null && !line.equals(boundary))
+            Collection<Part> parts = mpis.getParts();
+            if (parts != null)
             {
-                if (!badFormatLogged)
+                Iterator<Part> itor = parts.iterator();
+                while (itor.hasNext() && params.size() < _maxFormKeys)
                 {
-                    LOG.warn("Badly formatted multipart request");
-                    badFormatLogged = true;
-                }
-                line=((ReadLineInputStream)in).readLine();
-                line=(line==null?line:line.trim());
-            }
-            
-            if (line == null)
-                throw new IOException("Missing initial multi part boundary");
-            
-            // Read each part
-            boolean lastPart=false;
-      
-            outer:while(!lastPart && params.size()<_maxFormKeys)
-            {
-                String type_content=null;
-                String content_disposition=null;
-                String content_transfer_encoding=null;
-                
-                while(true)
-                {
-                    // read a line
-                    line=((ReadLineInputStream)in).readLine();
-                    
-                    //No more input
-                    if (line==null)
-                        break outer;
-                    
-                    // If blank line, end of part headers
-                    if("".equals(line))
-                        break;
-                    
-                    // place part header key and value in map
-                    int c=line.indexOf(':',0);
-                    if(c>0)
+                    Part p = itor.next();
+                    MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p;
+                    if (mp.getFile() != null)
                     {
-                        String key=line.substring(0,c).trim().toLowerCase(Locale.ENGLISH);
-                        String value=line.substring(c+1,line.length()).trim();
-                        if(key.equals("content-disposition"))
-                            content_disposition=value;
-                        else if(key.equals("content-transfer-encoding"))
-                            content_transfer_encoding=value;
-                        else if (key.equals("content-type"))
-                             type_content = value;  
-                    }
-                }
-                // Extract content-disposition
-                boolean form_data=false;
-                if(content_disposition==null)
-                {
-                    throw new IOException("Missing content-disposition");
-                }
-                
-                LOG.debug("Content-Disposition: {}", content_disposition);
-                QuotedStringTokenizer tok=new QuotedStringTokenizer(content_disposition,";",false,true);
-                String name=null;
-                String filename=null;
-                while(tok.hasMoreTokens())
-                {
-                    String t=tok.nextToken().trim();
-                    String tl=t.toLowerCase();
-                    if(t.startsWith("form-data"))
-                        form_data=true;
-                    else if(tl.startsWith("name="))
-                        name=value(t);
-                    else if(tl.startsWith("filename="))
-                        filename=filenameValue(t);
-                }
-                
-                // Check disposition
-                if(!form_data)
-                {
-                    continue;
-                }
-                //It is valid for reset and submit buttons to have an empty name.
-                //If no name is supplied, the browser skips sending the info for that field.
-                //However, if you supply the empty string as the name, the browser sends the
-                //field, with name as the empty string. So, only continue this loop if we
-                //have not yet seen a name field.
-                if(name==null)
-                {
-                    continue;
-                }
-                
-                OutputStream out=null;
-                File file=null;
-                try
-                {
-                    if (filename!=null && filename.length()>0)
-                    {
-                        LOG.debug("filename = \"{}\"", filename);
-                        file = File.createTempFile("MultiPart", "", tempdir);
-                        out = new FileOutputStream(file);
-                        if(_fileOutputBuffer>0)
-                            out = new BufferedOutputStream(out, _fileOutputBuffer);
-                        request.setAttribute(name,file);
-                        params.add(name, filename);
-                        if (type_content != null)
-                            params.add(name+CONTENT_TYPE_SUFFIX, type_content);
-                        
-                        if (_deleteFiles)
+                        request.setAttribute(mp.getName(),mp.getFile());
+                        if (mp.getContentDispositionFilename() != null)
                         {
-                            file.deleteOnExit();
-                            ArrayList files = (ArrayList)request.getAttribute(FILES);
-                            if (files==null)
-                            {
-                                files=new ArrayList();
-                                request.setAttribute(FILES,files);
-                            }
-                            files.add(file);
-                        }   
+                            params.add(mp.getName(), mp.getContentDispositionFilename());
+                            if (mp.getContentType() != null)
+                                params.add(mp.getName()+CONTENT_TYPE_SUFFIX, mp.getContentType());
+                        }
                     }
                     else
                     {
-                        out=new ByteArrayOutputStream();
+                        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+                        IO.copy(p.getInputStream(), bytes);
+                        params.add(p.getName(), bytes.toByteArray());
+                        if (p.getContentType() != null)
+                            params.add(p.getName()+CONTENT_TYPE_SUFFIX, p.getContentType());
                     }
-                    
-                    
-                    if ("base64".equalsIgnoreCase(content_transfer_encoding))
-                    {
-                        in = new Base64InputStream((ReadLineInputStream)in);   
-                    }
-                    else if ("quoted-printable".equalsIgnoreCase(content_transfer_encoding))
-                    {
-                        in = new FilterInputStream(in)
-                        {
-                            @Override
-                            public int read() throws IOException
-                            {
-                                int c = in.read();
-                                if (c >= 0 && c == '=')
-                                {
-                                    int hi = in.read();
-                                    int lo = in.read();
-                                    if (hi < 0 || lo < 0)
-                                    {
-                                        throw new IOException("Unexpected end to quoted-printable byte");
-                                    }
-                                    char[] chars = new char[] { (char)hi, (char)lo };
-                                    c = Integer.parseInt(new String(chars),16);
-                                }
-                                return c;
-                            }
-                        };
-                    }
-
-                    int state=-2;
-                    int c;
-                    boolean cr=false;
-                    boolean lf=false;
-                    
-                    // loop for all lines`
-                    while(true)
-                    {
-                        int b=0;
-                        while((c=(state!=-2)?state:in.read())!=-1)
-                        {
-                            state=-2;
-                            // look for CR and/or LF
-                            if(c==13||c==10)
-                            {
-                                if(c==13)
-                                {
-                                    in.mark(1);
-                                    int tmp=in.read();
-                                    if (tmp!=10)
-                                        in.reset();
-                                    else
-                                        state=tmp;
-                                }
-                                break;
-                            }
-                            // look for boundary
-                            if(b>=0&&b<byteBoundary.length&&c==byteBoundary[b])
-                                b++;
-                            else
-                            {
-                                // this is not a boundary
-                                if(cr)
-                                    out.write(13);
-                                if(lf)
-                                    out.write(10);
-                                cr=lf=false;
-                                if(b>0)
-                                    out.write(byteBoundary,0,b);
-                                b=-1;
-                                out.write(c);
-                            }
-                        }
-                        // check partial boundary
-                        if((b>0&&b<byteBoundary.length-2)||(b==byteBoundary.length-1))
-                        {
-                            if(cr)
-                                out.write(13);
-                            if(lf)
-                                out.write(10);
-                            cr=lf=false;
-                            out.write(byteBoundary,0,b);
-                            b=-1;
-                        }
-                        // boundary match
-                        if(b>0||c==-1)
-                        {
-                            if(b==byteBoundary.length)
-                                lastPart=true;
-                            if(state==10)
-                                state=-2;
-                            break;
-                        }
-                        // handle CR LF
-                        if(cr)
-                            out.write(13);
-                        if(lf)
-                            out.write(10);
-                        cr=(c==13);
-                        lf=(c==10||state==10);
-                        if(state==10)
-                            state=-2;
-                    }
-                }
-                finally
-                {
-                    out.close();
-                }
-                
-                if (file==null)
-                {
-                    byte[] bytes = ((ByteArrayOutputStream)out).toByteArray();
-                    params.add(name,bytes);
-                    if (type_content != null)
-                        params.add(name+CONTENT_TYPE_SUFFIX, type_content);
                 }
             }
-        
+
             // handle request
             chain.doFilter(new Wrapper(srequest,params),response);
         }
-        catch (IOException e)
-        {
-            if (!badFormatLogged)
-                LOG.warn("Badly formatted multipart request");
-            throw e;             
-        }
         finally
         {
             deleteFiles(request);
         }
     }
-
+    
+    
+    /* ------------------------------------------------------------ */
     private void deleteFiles(ServletRequest request)
     {
-        ArrayList files = (ArrayList)request.getAttribute(FILES);
-        if (files!=null)
+        if (!_deleteFiles)
+            return;
+        
+        MultiPartInputStream mpis = (MultiPartInputStream)request.getAttribute(MULTIPART);
+        if (mpis != null)
         {
-            Iterator iter = files.iterator();
-            while (iter.hasNext())
+            try
             {
-                File file=(File)iter.next();
-                try
-                {
-                    file.delete();
-                }
-                catch(Exception e)
-                {
-                    _context.log("failed to delete "+file,e);
-                }
+                mpis.deleteParts();
+            }
+            catch (Exception e)
+            {
+                _context.log("Error deleting multipart tmp files", e);
             }
         }
+        request.removeAttribute(MULTIPART);
     }
     
-    /* ------------------------------------------------------------ */
-    private String value(String nameEqualsValue)
-    {
-        int idx = nameEqualsValue.indexOf('=');
-        String value = nameEqualsValue.substring(idx+1).trim();
-        return QuotedStringTokenizer.unquoteOnly(value);
-    }
-    
-    
-    /* ------------------------------------------------------------ */
-    private String filenameValue(String nameEqualsValue)
-    {
-        int idx = nameEqualsValue.indexOf('=');
-        String value = nameEqualsValue.substring(idx+1).trim();   
-
-        if (value.matches(".??[a-z,A-Z]\\:\\\\[^\\\\].*"))
-        {
-            //incorrectly escaped IE filenames that have the whole path
-            //we just strip any leading & trailing quotes and leave it as is
-            char first=value.charAt(0);
-            if (first=='"' || first=='\'')
-                value=value.substring(1);
-            char last=value.charAt(value.length()-1);
-            if (last=='"' || last=='\'')
-                value = value.substring(0,value.length()-1);
-
-            return value;
-        }
-        else
-            //unquote the string, but allow any backslashes that don't
-            //form a valid escape sequence to remain as many browsers
-            //even on *nix systems will not escape a filename containing
-            //backslashes
-            return QuotedStringTokenizer.unquoteOnly(value, true);
-    }
-
+ 
     /* ------------------------------------------------------------------------------- */
     /**
      * @see javax.servlet.Filter#destroy()
@@ -621,44 +369,4 @@
             return new String(bytes,contentType);
         }
     }
-    
-    private static class Base64InputStream extends InputStream
-    {
-        ReadLineInputStream _in;
-        String _line;
-        byte[] _buffer;
-        int _pos;
-        
-        public Base64InputStream (ReadLineInputStream in)
-        {
-            _in = in;
-        }
-
-        @Override
-        public int read() throws IOException
-        {
-            if (_buffer==null || _pos>= _buffer.length)
-            {
-                _line = _in.readLine();
-                System.err.println("LINE: "+_line);
-                if (_line==null)
-                    return -1;
-                if (_line.startsWith("--"))
-                    _buffer=(_line+"\r\n").getBytes();
-                else if (_line.length()==0)
-                    _buffer="\r\n".getBytes();
-                else
-                {
-                    ByteArrayOutputStream bout = new ByteArrayOutputStream(4*_line.length()/3);  
-                    B64Code.decode(_line, bout);    
-                    bout.write(13);
-                    bout.write(10);
-                    _buffer = bout.toByteArray();
-                }
-                
-                _pos=0;
-            }
-            return _buffer[_pos++];
-        } 
-    }
 }
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java
index e200dd4..e58f582 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java
@@ -561,7 +561,7 @@
                 String connectionHdr = request.getHeader("Connection");
                 if (connectionHdr != null)
                 {
-                    connectionHdr = connectionHdr.toLowerCase();
+                    connectionHdr = connectionHdr.toLowerCase(Locale.ENGLISH);
                     if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0)
                         connectionHdr = null;
                 }
@@ -579,7 +579,7 @@
                 {
                     // TODO could be better than this!
                     String hdr = (String)enm.nextElement();
-                    String lhdr = hdr.toLowerCase();
+                    String lhdr = hdr.toLowerCase(Locale.ENGLISH);
 
                     if ("transfer-encoding".equals(lhdr))
                     {
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 dc13b01..88c8055 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
@@ -23,7 +23,8 @@
 
 import java.io.IOException;
 import java.net.Socket;
-
+import java.util.EnumSet;
+import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.Servlet;
 import javax.servlet.ServletException;
@@ -35,6 +36,7 @@
 import org.eclipse.jetty.servlet.FilterHolder;
 import org.eclipse.jetty.testing.ServletTester;
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.log.Log;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -62,7 +64,7 @@
         _tester.setContextPath("/ctx");
         _tester.addServlet(TestServlet.class, "/*");
 
-        _dosFilter = _tester.addFilter(filter, "/dos/*", 0);
+        _dosFilter = _tester.addFilter(filter, "/dos/*", EnumSet.allOf(DispatcherType.class));
         _dosFilter.setInitParameter("maxRequestsPerSec", "4");
         _dosFilter.setInitParameter("delayMs", "200");
         _dosFilter.setInitParameter("throttledRequests", "1");
@@ -71,7 +73,7 @@
         _dosFilter.setInitParameter("remotePort", "false");
         _dosFilter.setInitParameter("insertHeaders", "true");
 
-        _timeoutFilter = _tester.addFilter(filter, "/timeout/*", 0);
+        _timeoutFilter = _tester.addFilter(filter, "/timeout/*", EnumSet.allOf(DispatcherType.class));
         _timeoutFilter.setInitParameter("maxRequestsPerSec", "4");
         _timeoutFilter.setInitParameter("delayMs", "200");
         _timeoutFilter.setInitParameter("throttledRequests", "1");
@@ -178,8 +180,8 @@
         String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n";
         String responses = doRequests(request+request+request+request+request,2,1100,1100,last);
 
-        assertEquals(11,count(responses,"HTTP/1.1 200 OK"));
         assertEquals(2,count(responses,"DoSFilter: delayed"));
+        assertEquals(11,count(responses,"HTTP/1.1 200 OK"));
     }
 
     @Test
@@ -209,7 +211,7 @@
         String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n";
         String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n";
         String responses = doRequests(request+request+request+request,1,0,0,last);
-        //System.out.println("responses are " + responses);
+        System.out.println("responses are " + responses);
         assertEquals("200 OK responses", 5,count(responses,"HTTP/1.1 200 OK"));
         assertEquals("delayed responses", 1,count(responses,"DoSFilter: delayed"));
         assertEquals("throttled responses", 1,count(responses,"DoSFilter: throttled"));
@@ -246,6 +248,8 @@
         String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n";
         String responses = doRequests(request+request+request+request,1,0,0,last);
 
+        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,"DoSFilter: delayed"));
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java
index 0c6d9f4..047b804 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java
@@ -18,6 +18,10 @@
 
 package org.eclipse.jetty.servlets;
 
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
+
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.nio.SelectChannelConnector;
@@ -37,7 +41,7 @@
         ServletHandler handler=new ServletHandler();
         server.setHandler(handler);
         
-        //FilterHolder gzip = handler.addFilterWithMapping("org.eclipse.jetty.servlets.GzipFilter","/*",0);
+        //FilterHolder gzip = handler.addFilterWithMapping("org.eclipse.jetty.servlet.GzipFilter","/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
         //gzip.setAsyncSupported(true);
         //gzip.setInitParameter("minGzipSize","256");
         ServletHolder proxy = handler.addServletWithMapping("org.eclipse.jetty.servlets.ProxyServlet","/");
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java
index 56e4fb5..47bcfce 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.servlets;
 
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
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 732d022..9948950 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
@@ -19,8 +19,11 @@
 package org.eclipse.jetty.servlets;
 
 import java.io.IOException;
+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.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -56,7 +59,7 @@
     @Test
     public void testRequestWithNoOriginArrivesToApplication() throws Exception
     {
-        tester.getContext().addFilter(CrossOriginFilter.class, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(CrossOriginFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         final CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -76,7 +79,7 @@
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         String origin = "http://localhost";
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin);
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -100,7 +103,7 @@
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         String origin = "http://subdomain.example.com";
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "http://*.example.com");
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -123,7 +126,7 @@
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         String origin = "http://subdomain.subdomain.example.com";
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "http://*.example.com");
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -146,7 +149,7 @@
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         String origin = "http://localhost";
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin);
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -170,7 +173,7 @@
         String origin = "http://localhost";
         String otherOrigin = origin.replace("localhost", "127.0.0.1");
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin + "," + otherOrigin);
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -193,7 +196,7 @@
     {
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "false");
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -218,7 +221,7 @@
         // will contain the CORS response headers.
 
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -243,7 +246,7 @@
         // will contain the CORS response headers.
 
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -265,7 +268,7 @@
     {
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "PUT");
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -304,7 +307,7 @@
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,HEAD,POST,PUT,DELETE");
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,X-Custom");
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*",EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -345,7 +348,7 @@
     {
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,HEAD,POST,PUT,DELETE");
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -370,7 +373,7 @@
     public void testCrossOriginFilterDisabledForWebSocketUpgrade() throws Exception
     {
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -394,7 +397,7 @@
     {
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         filterHolder.setInitParameter("exposedHeaders", "Content-Length");
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
@@ -416,7 +419,7 @@
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "PUT");
         filterHolder.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false");
-        tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
+        tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
 
         CountDownLatch latch = new CountDownLatch(1);
         tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterJMXTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterJMXTest.java
index d458c93..3ad5cc3 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterJMXTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterJMXTest.java
@@ -24,10 +24,10 @@
 import javax.management.Attribute;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
+import javax.servlet.DispatcherType;
 
 import org.eclipse.jetty.jmx.MBeanContainer;
 import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.nio.SelectChannelConnector;
 import org.eclipse.jetty.servlet.FilterHolder;
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 cf536d3..dd95fab 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
@@ -48,7 +48,8 @@
         @Override
         public void closeConnection(HttpServletRequest request, HttpServletResponse response, Thread thread)
         {
-            try {
+            try 
+            {
                 response.getWriter().append("DoSFilter: timeout");
                 super.closeConnection(request,response,thread);
             }
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
index 3094bfb..e73821c 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java
@@ -104,7 +104,7 @@
         tester.setContextPath("/context");
         tester.setResourceBase(testdir.getDir().getCanonicalPath());
         tester.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
-        FilterHolder holder = tester.addFilter(IncludableGzipFilter.class,"/*",0);
+        FilterHolder holder = tester.addFilter(IncludableGzipFilter.class,"/*",null);
         holder.setInitParameter("mimeTypes","text/plain");
         tester.start();
     }
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 6aaf889..23ed257 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
@@ -18,17 +18,22 @@
 
 package org.eclipse.jetty.servlets;
 
-import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.*;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.lang.reflect.Array;
+import java.net.Socket;
+import java.net.URL;
+import java.util.EnumSet;
+import java.util.Enumeration;
 import java.util.Map;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -75,7 +80,6 @@
             assertNotNull(req.getParameter("fileup"));
             assertNotNull(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX));
             assertEquals(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX), "application/octet-stream");
-            
             super.doPost(req, resp);
         }
         
@@ -96,7 +100,8 @@
         tester.setContextPath("/context");
         tester.setResourceBase(_dir.getCanonicalPath());
         tester.addServlet(TestServlet.class, "/");
-        FilterHolder multipartFilter = tester.addFilter(MultiPartFilter.class,"/*",FilterMapping.DEFAULT);
+        tester.setAttribute("javax.servlet.context.tempdir", _dir);
+        FilterHolder multipartFilter = tester.addFilter(MultiPartFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST));
         multipartFilter.setInitParameter("deleteFiles", "true");
         tester.start();
     }
@@ -135,7 +140,7 @@
         
         response.parse(tester.getResponses(request.generate()));
         assertTrue(response.getMethod()==null);
-        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+        assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,response.getStatus());
     }
     
 
@@ -791,14 +796,11 @@
      */
     public static class TestServletParameterMap extends DumpServlet
     {
-
         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
         {
-            String content = (String)req.getParameter("\"strup\"Content-Type: application/octet-stream");
-            
-            assertThat(content, containsString("How now brown cow."));
-                   
+            String[] content = req.getParameterMap().get("\"strup\"Content-Type: application/octet-stream");           
+            assertThat (content[0], containsString("How now brown cow."));
             super.doPost(req, resp);
         } 
     }
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java
index e78d918..eebb08b 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java
@@ -26,6 +26,8 @@
 import java.io.OutputStream;
 import java.net.Socket;
 import java.net.URL;
+import java.util.EnumSet;
+import javax.servlet.DispatcherType;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Locale;
@@ -59,7 +61,7 @@
         tester.setContextPath("/context");
         tester.setResourceBase(_dir.getCanonicalPath());
         tester.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
-        FilterHolder holder = tester.addFilter(PutFilter.class,"/*",0);
+        FilterHolder holder = tester.addFilter(PutFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
         holder.setInitParameter("delAllowed","true");
         // Bloody Windows does not allow file renaming
         if (!System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows"))
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 a4e00b6..d81c2a1 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,9 +23,10 @@
 
 import java.io.IOException;
 import java.net.URL;
+import java.util.EnumSet;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-
+import javax.servlet.DispatcherType;
 import javax.servlet.Servlet;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
@@ -99,7 +100,7 @@
         FilterHolder holder = new FilterHolder(QoSFilter2.class);
         holder.setAsyncSupported(true);
         holder.setInitParameter(QoSFilter.MAX_REQUESTS_INIT_PARAM, ""+MAX_QOS);
-        _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",FilterMapping.DEFAULT);
+        _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
 
         for(int i = 0; i < NUM_CONNECTIONS; ++i )
         {
@@ -117,8 +118,7 @@
         FilterHolder holder = new FilterHolder(QoSFilter2.class);
         holder.setAsyncSupported(true);
         holder.setInitParameter(QoSFilter.MAX_REQUESTS_INIT_PARAM, ""+MAX_QOS);
-        _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",FilterMapping.DEFAULT);
-
+        _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
         for(int i = 0; i < NUM_CONNECTIONS; ++i )
         {
             new Thread(new Worker2(i)).start();
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TransparentProxyTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TransparentProxyTest.java
new file mode 100644
index 0000000..c3535c9
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TransparentProxyTest.java
@@ -0,0 +1,140 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      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.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ * TransparentProxyTest
+ *
+ *
+ */
+public class TransparentProxyTest
+{
+  
+
+        protected Server server;
+        protected Server proxyServer;
+        
+        public static class ServletA extends HttpServlet {
+            @Override
+            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+                resp.setContentType("text/plain");
+                resp.getWriter().println("ok");
+            }
+        }
+        
+        @Before
+        public void setUp () throws Exception
+        {
+            //set up the target server
+            server = new Server();
+            SelectChannelConnector connector = new SelectChannelConnector();
+            connector.setPort(8080);
+            server.addConnector(connector);
+            ServletContextHandler handler = new ServletContextHandler(server, "/");
+            handler.addServlet(ServletA.class, "/a");
+            server.setHandler(handler);
+            server.start();
+
+
+            //set up the server that proxies to the target server
+            proxyServer = new Server();
+            SelectChannelConnector proxyConnector = new SelectChannelConnector();
+            proxyConnector.setPort(8081);
+            proxyServer.addConnector(proxyConnector);           
+            ServletContextHandler proxyHandler = new ServletContextHandler(proxyServer, "/");
+            proxyHandler.addServlet(new ServletHolder(new ProxyServlet.Transparent("/", "http", "127.0.0.1", 8080, "/")), "/");
+            proxyServer.setHandler(proxyHandler);
+            proxyServer.start();
+
+        }
+        
+        
+        @After
+        public void tearDown() throws Exception
+        {
+            server.stop();
+            proxyServer.stop();
+        }
+
+
+        @Test
+        public void testDirectNoContentType() throws Exception
+        {
+            // Direct request without Content-Type set works
+            URL url = new URL("http://localhost:8080/a");
+            HttpURLConnection con = (HttpURLConnection) url.openConnection();
+            assertEquals(200, con.getResponseCode());
+        }
+
+        
+        @Test
+        public void testDirectWithContentType() throws Exception
+        {
+            // Direct request with Content-Type works
+            URL url = new URL("http://localhost:8080/a");
+            HttpURLConnection con = (HttpURLConnection) url.openConnection();
+            con.addRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
+            assertEquals(200, con.getResponseCode());
+        }
+
+        @Test
+        public void testProxiedWithoutContentType() throws Exception
+        {
+            // Proxied request without Content-Type set works
+            URL url = new URL("http://localhost:8081/a");
+            HttpURLConnection con = (HttpURLConnection) url.openConnection();
+            assertEquals(200, con.getResponseCode());
+            System.err.println (con.getContentType());
+        }
+
+        @Test
+        public void testProxiedWithContentType() throws Exception
+        {
+            // Proxied request with Content-Type set fails
+
+            URL url = new URL("http://localhost:8081/a");
+            HttpURLConnection con = (HttpURLConnection) url.openConnection();
+            con.addRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
+            assertEquals(200, con.getResponseCode());
+            System.err.println(con.getContentType());
+            
+        }
+}
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
index dc4fdf0..4f73ffa 100644
--- 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
@@ -30,11 +30,13 @@
 import java.io.UnsupportedEncodingException;
 import java.security.DigestOutputStream;
 import java.security.MessageDigest;
+import java.util.EnumSet;
 import java.util.Enumeration;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.Inflater;
+import javax.servlet.DispatcherType;
 import java.util.zip.InflaterInputStream;
 
 import javax.servlet.Servlet;
@@ -530,7 +532,7 @@
         ServletHolder servletHolder = servletTester.addServlet(servletClass,"/");
         servletHolder.setInitParameter("baseDir",testdir.getDir().getAbsolutePath());
         servletHolder.setInitParameter("etags","true");
-        FilterHolder holder = servletTester.addFilter(gzipFilterClass,"/*",0);
+        FilterHolder holder = servletTester.addFilter(gzipFilterClass,"/*",EnumSet.allOf(DispatcherType.class));
         holder.setInitParameter("vary","Accept-Encoding");
         return holder;
     }
diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml
index af92aa4..5390572 100644
--- a/jetty-spdy/pom.xml
+++ b/jetty-spdy/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty</groupId>
         <artifactId>jetty-project</artifactId>
-        <version>7.6.19-SNAPSHOT</version>
+        <version>8.1.19-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
@@ -58,6 +58,13 @@
                     <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>
 
@@ -216,6 +223,7 @@
       </activation>
       <properties>
         <npn.version>1.1.8.v20141013</npn.version>
+        <alpn.version>7.1.0.v20141016</alpn.version>
       </properties>
     </profile>
     <profile>
@@ -228,6 +236,7 @@
       </activation>
       <properties>
         <npn.version>1.1.8.v20141013</npn.version>
+        <alpn.version>7.1.0.v20141016</alpn.version>
       </properties>
     </profile>
     <profile>
@@ -240,6 +249,7 @@
       </activation>
       <properties>
         <npn.version>1.1.8.v20141013</npn.version>
+        <alpn.version>7.1.0.v20141016</alpn.version>
       </properties>
     </profile>
     <profile>
@@ -252,6 +262,7 @@
       </activation>
       <properties>
         <npn.version>1.1.9.v20141016</npn.version>
+        <alpn.version>7.1.2.v20141202</alpn.version>
       </properties>
     </profile>
     <profile>
@@ -264,6 +275,7 @@
       </activation>
       <properties>
         <npn.version>1.1.9.v20141016</npn.version>
+        <alpn.version>7.1.2.v20141202</alpn.version>
       </properties>
     </profile>
     <profile>
@@ -276,6 +288,7 @@
       </activation>
       <properties>
         <npn.version>1.1.10.v20150130</npn.version>
+        <alpn.version>7.1.3.v20150130</alpn.version>
       </properties>
     </profile>
     <profile>
@@ -288,6 +301,7 @@
       </activation>
       <properties>
         <npn.version>1.1.10.v20150130</npn.version>
+        <alpn.version>7.1.3.v20150130</alpn.version>
       </properties>
     </profile>
     <profile>
@@ -300,6 +314,7 @@
       </activation>
       <properties>
         <npn.version>1.1.10.v20150130</npn.version>
+        <alpn.version>7.1.3.v20150130</alpn.version>
       </properties>
     </profile>
     <profile>
@@ -312,6 +327,7 @@
       </activation>
       <properties>
         <npn.version>1.1.11.v20150415</npn.version>
+        <alpn.version>7.1.3.v20150130</alpn.version>
       </properties>
     </profile>
   </profiles>
diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml
index 975459f..37e735a 100644
--- a/jetty-spdy/spdy-core/pom.xml
+++ b/jetty-spdy/spdy-core/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.spdy</groupId>
         <artifactId>spdy-parent</artifactId>
-        <version>7.6.19-SNAPSHOT</version>
+        <version>8.1.19-SNAPSHOT</version>
     </parent>
 
   <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-spdy/spdy-jetty-http-webapp/pom.xml b/jetty-spdy/spdy-jetty-http-webapp/pom.xml
index 41ff79e..e96b67c 100644
--- a/jetty-spdy/spdy-jetty-http-webapp/pom.xml
+++ b/jetty-spdy/spdy-jetty-http-webapp/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.spdy</groupId>
         <artifactId>spdy-parent</artifactId>
-        <version>7.6.19-SNAPSHOT</version>
+        <version>8.1.19-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>spdy-jetty-http-webapp</artifactId>
diff --git a/jetty-spdy/spdy-jetty-http/pom.xml b/jetty-spdy/spdy-jetty-http/pom.xml
index cf05b5e..6664490 100644
--- a/jetty-spdy/spdy-jetty-http/pom.xml
+++ b/jetty-spdy/spdy-jetty-http/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.spdy</groupId>
         <artifactId>spdy-parent</artifactId>
-        <version>7.6.19-SNAPSHOT</version>
+        <version>8.1.19-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>spdy-jetty-http</artifactId>
diff --git a/jetty-spdy/spdy-jetty/pom.xml b/jetty-spdy/spdy-jetty/pom.xml
index 806895e..a08d02d 100644
--- a/jetty-spdy/spdy-jetty/pom.xml
+++ b/jetty-spdy/spdy-jetty/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.spdy</groupId>
         <artifactId>spdy-parent</artifactId>
-        <version>7.6.19-SNAPSHOT</version>
+        <version>8.1.19-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>spdy-jetty</artifactId>
diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml
index ba97f08..3a8b601 100644
--- a/jetty-start/pom.xml
+++ b/jetty-start/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-start</artifactId>
diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config b/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config
index 0438633..bf3c920 100644
--- a/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config
+++ b/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config
@@ -92,7 +92,7 @@
 $(jetty.home)/lib/jetty-xml-$(version).jar                                              ! available org.eclipse.jetty.xml.XmlParser
          
 [Server,All,server,default]
-$(jetty.home)/lib/servlet-api-2.5.jar                                                   ! available javax.servlet.ServletContext
+$(jetty.home)/lib/servlet-api-3.0.jar                                                   ! available javax.servlet.ServletContext
 $(jetty.home)/lib/jetty-http-$(version).jar                                             ! available org.eclipse.jetty.http.HttpParser
 $(jetty.home)/lib/jetty-continuation-$(version).jar                                     ! available org.eclipse.jetty.continuation.Continuation
 $(jetty.home)/lib/jetty-server-$(version).jar                                           ! available org.eclipse.jetty.server.Server
@@ -101,7 +101,7 @@
 $(jetty.home)/lib/jetty-security-$(version).jar                                         ! available org.eclipse.jetty.security.LoginService
                                                        
 [Server,All,servlet,default]
-$(jetty.home)/lib/servlet-api-2.5.jar                                                   ! available javax.servlet.ServletContext
+$(jetty.home)/lib/servlet-api-3.0.jar                                                   ! available javax.servlet.ServletContext
 $(jetty.home)/lib/jetty-servlet-$(version).jar                                          ! available org.eclipse.jetty.servlet.ServletHandler
                             
 [Server,All,webapp,default]
@@ -141,7 +141,7 @@
 [All,Client,client]
 $(jetty.home)/lib/jetty-http-$(version).jar                                             ! available org.eclipse.jetty.http.HttpParser
 $(jetty.home)/lib/jetty-client-$(version).jar                                           ! available org.eclipse.jetty.client.HttpClient
-       
+
 [Client]
 $(jetty.home)/lib/jetty-http-$(version).jar                                             ! available org.eclipse.jetty.http.HttpParser
 
diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml
index 2528379..ae4da4b 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-util</artifactId>
@@ -25,7 +25,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>org.slf4j;version="[1.5,1.7)";resolution:=optional,org.slf4j.impl;version="[1.5,1.7)";resolution:=optional,*</Import-Package>
+                <Import-Package>javax.servlet.*;version="2.6.0",org.slf4j;version="[1.5,2.0)";resolution:=optional,org.slf4j.impl;version="[1.5,2.0)";resolution:=optional,*</Import-Package>
               </instructions>
             </configuration>
            </execution>
@@ -71,6 +71,11 @@
   </build>
   <dependencies>
     <dependency>
+      <groupId>org.eclipse.jetty.orbit</groupId>
+      <artifactId>javax.servlet</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
       <groupId>org.eclipse.jetty.toolchain</groupId>
       <artifactId>jetty-test-helper</artifactId>
       <scope>test</scope>
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 4935089..f88db18 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
@@ -21,9 +21,11 @@
 import java.io.File;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.HashSet;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
+import java.util.Set;
 
 import org.eclipse.jetty.util.resource.Resource;
 
@@ -95,7 +97,9 @@
         ClassNotFoundException ex=null;
         Class<?> c =null;
         ClassLoader loader=Thread.currentThread().getContextClassLoader();
-        while (c==null && loader!=null )
+        Set<ClassLoader> seen = new HashSet<ClassLoader>();
+        
+        while (c==null && loader!=null && seen.add(loader))
         {
             try { c=loader.loadClass(name); }
             catch (ClassNotFoundException e) {if(ex==null)ex=e;}
@@ -103,14 +107,15 @@
         }      
         
         loader=loadClass==null?null:loadClass.getClassLoader();
-        while (c==null && loader!=null )
+        while (c==null && loader!=null && seen.add(loader))
         {
             try { c=loader.loadClass(name); }
             catch (ClassNotFoundException e) {if(ex==null)ex=e;}
             loader=(c==null&&checkParents)?loader.getParent():null;
         }       
 
-        if (c==null)
+        loader=Loader.class.getClassLoader();
+        if (c==null && loader!=null && seen.add(loader))
         {
             try { c=Class.forName(name); }
             catch (ClassNotFoundException e) {if(ex==null)ex=e;}
@@ -130,7 +135,9 @@
         MissingResourceException ex=null;
         ResourceBundle bundle =null;
         ClassLoader loader=Thread.currentThread().getContextClassLoader();
-        while (bundle==null && loader!=null )
+        Set<ClassLoader> seen = new HashSet<ClassLoader>();
+        
+        while (bundle==null && loader!=null && seen.add(loader))
         {
             try { bundle=ResourceBundle.getBundle(name, locale, loader); }
             catch (MissingResourceException e) {if(ex==null)ex=e;}
@@ -138,14 +145,15 @@
         }      
         
         loader=loadClass==null?null:loadClass.getClassLoader();
-        while (bundle==null && loader!=null )
+        while (bundle==null && loader!=null && seen.add(loader))
         {
             try { bundle=ResourceBundle.getBundle(name, locale, loader); }
             catch (MissingResourceException e) {if(ex==null)ex=e;}
             loader=(bundle==null&&checkParents)?loader.getParent():null;
         }       
 
-        if (bundle==null)
+        loader = Loader.class.getClassLoader();
+        if (bundle==null && loader!=null && seen.add(loader))
         {
             try { bundle=ResourceBundle.getBundle(name, locale); }
             catch (MissingResourceException e) {if(ex==null)ex=e;}
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 61cfe00..04d50e9 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
@@ -86,7 +86,7 @@
      * @param name The entry key. 
      * @return Unmodifieable List of values.
      */
-    public List<Object> getValues(Object name)
+    public List getValues(Object name)
     {
         return LazyList.getList(_map.get(name),true);
     }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java
new file mode 100644
index 0000000..67848ba
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java
@@ -0,0 +1,856 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      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.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.ServletException;
+import javax.servlet.http.Part;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+
+/**
+ * MultiPartInputStream
+ *
+ * Handle a MultiPart Mime input stream, breaking it up on the boundary into files and strings.
+ */
+public class MultiPartInputStream
+{
+    private static final Logger LOG = Log.getLogger(MultiPartInputStream.class);
+
+    public static final MultipartConfigElement  __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir"));
+    protected InputStream _in;
+    protected MultipartConfigElement _config;
+    protected String _contentType;
+    protected MultiMap<String> _parts;
+    protected File _tmpDir;
+    protected File _contextTmpDir;
+    protected boolean _deleteOnExit;
+    
+    
+    
+    public class MultiPart implements Part
+    {
+        protected String _name;
+        protected String _filename;
+        protected File _file;
+        protected OutputStream _out;
+        protected ByteArrayOutputStream2 _bout;
+        protected String _contentType;
+        protected MultiMap<String> _headers;
+        protected long _size = 0;
+        protected boolean _temporary = true;
+
+        public MultiPart (String name, String filename) 
+        throws IOException
+        {
+            _name = name;
+            _filename = filename;
+        }
+
+        protected void setContentType (String contentType)
+        {
+            _contentType = contentType;
+        }
+        
+        
+        protected void open() 
+        throws IOException
+        {
+            //We will either be writing to a file, if it has a filename on the content-disposition
+            //and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we
+            //will need to change to write to a file.           
+            if (_filename != null && _filename.trim().length() > 0)
+            {
+                createFile();            
+            }
+            else
+            {
+                //Write to a buffer in memory until we discover we've exceed the 
+                //MultipartConfig fileSizeThreshold
+                _out = _bout= new ByteArrayOutputStream2();
+            }
+        }
+        
+        protected void close() 
+        throws IOException
+        {
+            _out.close();
+        }
+        
+      
+        protected void write (int b)
+        throws IOException
+        {      
+            if (MultiPartInputStream.this._config.getMaxFileSize() > 0 && _size + 1 > MultiPartInputStream.this._config.getMaxFileSize())
+                throw new IllegalStateException ("Multipart Mime part "+_name+" exceeds max filesize");
+            
+            if (MultiPartInputStream.this._config.getFileSizeThreshold() > 0 && _size + 1 > MultiPartInputStream.this._config.getFileSizeThreshold() && _file==null)
+                createFile();
+            _out.write(b);   
+            _size ++;
+        }
+        
+        protected void write (byte[] bytes, int offset, int length) 
+        throws IOException
+        { 
+            if (MultiPartInputStream.this._config.getMaxFileSize() > 0 && _size + length > MultiPartInputStream.this._config.getMaxFileSize())
+                throw new IllegalStateException ("Multipart Mime part "+_name+" exceeds max filesize");
+            
+            if (MultiPartInputStream.this._config.getFileSizeThreshold() > 0 && _size + length > MultiPartInputStream.this._config.getFileSizeThreshold() && _file==null)
+                createFile();
+            
+            _out.write(bytes, offset, length);
+            _size += length;
+        }
+        
+        protected void createFile ()
+        throws IOException
+        {
+            final boolean USER = true;
+            final boolean WORLD = false;
+            
+            _file = File.createTempFile("MultiPart", "", MultiPartInputStream.this._tmpDir);
+            _file.setReadable(false,WORLD); // (reset) disable it for everyone first
+            _file.setReadable(true,USER); // enable for user only
+            if (_deleteOnExit)
+                _file.deleteOnExit();
+            FileOutputStream fos = new FileOutputStream(_file);
+            BufferedOutputStream bos = new BufferedOutputStream(fos);
+            
+            if (_size > 0 && _out != null)
+            {
+                //already written some bytes, so need to copy them into the file
+                _out.flush();
+                _bout.writeTo(bos);
+                _out.close();
+                _bout = null;
+            }
+            _out = bos;
+        }
+        
+
+        
+        protected void setHeaders(MultiMap<String> headers)
+        {
+            _headers = headers;
+        }
+        
+        /** 
+         * @see javax.servlet.http.Part#getContentType()
+         */
+        public String getContentType()
+        {
+            return _contentType;
+        }
+
+        /** 
+         * @see javax.servlet.http.Part#getHeader(java.lang.String)
+         */
+        public String getHeader(String name)
+        {
+            if (name == null)
+                return null;
+            return (String)_headers.getValue(name.toLowerCase(Locale.ENGLISH), 0);
+        }
+
+        /** 
+         * @see javax.servlet.http.Part#getHeaderNames()
+         */
+        public Collection<String> getHeaderNames()
+        {
+            return _headers.keySet();
+        }
+
+        /** 
+         * @see javax.servlet.http.Part#getHeaders(java.lang.String)
+         */
+        public Collection<String> getHeaders(String name)
+        {
+           return _headers.getValues(name);
+        }
+
+        /** 
+         * @see javax.servlet.http.Part#getInputStream()
+         */
+        public InputStream getInputStream() throws IOException
+        {
+           if (_file != null)
+           {
+               //written to a file, whether temporary or not
+               return new BufferedInputStream (new FileInputStream(_file));
+           }
+           else
+           {
+               //part content is in memory
+               return new ByteArrayInputStream(_bout.getBuf(),0,_bout.size());
+           }
+        }
+
+        public byte[] getBytes()
+        {
+            if (_bout!=null)
+                return _bout.toByteArray();
+            return null;
+        }
+        
+        /** 
+         * @see javax.servlet.http.Part#getName()
+         */
+        public String getName()
+        {
+           return _name;
+        }
+
+        /** 
+         * @see javax.servlet.http.Part#getSize()
+         */
+        public long getSize()
+        {
+            return _size;         
+        }
+
+        /** 
+         * @see javax.servlet.http.Part#write(java.lang.String)
+         */
+        public void write(String fileName) throws IOException
+        {
+            if (_file == null)
+            {
+                _temporary = false;
+                
+                //part data is only in the ByteArrayOutputStream and never been written to disk
+                _file = new File (_tmpDir, fileName);
+
+                BufferedOutputStream bos = null;
+                try
+                {
+                    bos = new BufferedOutputStream(new FileOutputStream(_file));
+                    _bout.writeTo(bos);
+                    bos.flush();
+                }
+                finally
+                {
+                    if (bos != null)
+                        bos.close();
+                    _bout = null;
+                }
+            }
+            else
+            {
+                //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;
+            }
+        }
+        
+        /** 
+         * Remove the file, whether or not Part.write() was called on it
+         * (ie no longer temporary)
+         * @see javax.servlet.http.Part#delete()
+         */
+        public void delete() throws IOException
+        {
+            if (_file != null && _file.exists())
+                _file.delete();     
+        }
+        
+        /**
+         * Only remove tmp files.
+         * 
+         * @throws IOException
+         */
+        public void cleanUp() throws IOException
+        {
+            if (_temporary && _file != null && _file.exists())
+                _file.delete();
+        }
+        
+        
+        /**
+         * Get the file, if any, the data has been written to.
+         * @return
+         */
+        public File getFile ()
+        {
+            return _file;
+        }  
+        
+        
+        /**
+         * Get the filename from the content-disposition.
+         * @return null or the filename
+         */
+        public String getContentDispositionFilename ()
+        {
+            return _filename;
+        }
+    }
+    
+    
+    
+    
+    /**
+     * @param in Request input stream 
+     * @param contentType Content-Type header
+     * @param config MultipartConfigElement 
+     * @param contextTmpDir javax.servlet.context.tempdir
+     */
+    public MultiPartInputStream (InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir)
+    {
+        _in = new ReadLineInputStream(in);
+       _contentType = contentType;
+       _config = config;
+       _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
+     */
+    public Collection<Part> getParsedParts()
+    {
+        if (_parts == null)
+            return Collections.emptyList();
+
+        Collection<Object> values = _parts.values();
+        List<Part> parts = new ArrayList<Part>();
+        for (Object o: values)
+        {
+            List<Part> asList = LazyList.getList(o, false);
+            parts.addAll(asList);
+        }
+        return parts;
+    }
+    
+    /**
+     * Delete any tmp storage for parts, and clear out the parts list.
+     * 
+     * @throws MultiException
+     */
+    public void deleteParts ()
+    throws MultiException
+    {
+        Collection<Part> parts = getParsedParts();
+        MultiException err = new MultiException();
+        for (Part p:parts)
+        {
+            try
+            {
+                ((MultiPartInputStream.MultiPart)p).cleanUp();
+            } 
+            catch(Exception e)
+            {     
+                err.add(e); 
+            }
+        }
+        _parts.clear();
+        
+        err.ifExceptionThrowMulti();
+    }
+
+   
+    /**
+     * Parse, if necessary, the multipart data and return the list of Parts.
+     * 
+     * @return
+     * @throws IOException
+     * @throws ServletException
+     */
+    public Collection<Part> getParts()
+    throws IOException, ServletException
+    {
+        parse();
+        Collection<Object> values = _parts.values();
+        List<Part> parts = new ArrayList<Part>();
+        for (Object o: values)
+        {
+            List<Part> asList = LazyList.getList(o, false);
+            parts.addAll(asList);
+        }
+        return parts;
+    }
+    
+    
+    /**
+     * Get the named Part.
+     * 
+     * @param name
+     * @return
+     * @throws IOException
+     * @throws ServletException
+     */
+    public Part getPart(String name)
+    throws IOException, ServletException
+    {
+        parse();
+        return (Part)_parts.getValue(name, 0);
+    }
+    
+    
+    /**
+     * Parse, if necessary, the multipart stream.
+     * 
+     * @throws IOException
+     * @throws ServletException
+     */
+    protected void parse ()
+    throws IOException, ServletException
+    {
+        //have we already parsed the input?
+        if (_parts != null)
+            return;
+        
+        //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<String>();
+
+        //if its not a multipart request, don't parse it
+        if (_contentType == null || !_contentType.startsWith("multipart/form-data"))
+            return;
+ 
+        //sort out the location to which to write the files
+        
+        if (_config.getLocation() == null)
+            _tmpDir = _contextTmpDir;
+        else if ("".equals(_config.getLocation()))
+            _tmpDir = _contextTmpDir;
+        else
+        {
+            File f = new File (_config.getLocation());
+            if (f.isAbsolute())
+                _tmpDir = f;
+            else
+                _tmpDir = new File (_contextTmpDir, _config.getLocation());
+        }
+      
+        if (!_tmpDir.exists())
+            _tmpDir.mkdirs();
+
+        String contentTypeBoundary = "";
+        int bstart = _contentType.indexOf("boundary=");
+        if (bstart >= 0)
+        {
+            int bend = _contentType.indexOf(";", bstart);
+            bend = (bend < 0? _contentType.length(): bend);
+            contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(bstart,bend), true).trim());
+        }
+        
+        String boundary="--"+contentTypeBoundary;
+        byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1);
+
+        // Get first boundary
+        String line = null;
+        try
+        {
+            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))
+        {
+            if (!badFormatLogged)
+            {
+                LOG.warn("Badly formatted multipart request");
+                badFormatLogged = true;
+            }
+            line=((ReadLineInputStream)_in).readLine();
+            line=(line==null?line:line.trim());
+        }
+
+        if (line == null || line.length() == 0)
+            throw new IOException("Missing initial multi part boundary");
+
+        // Read each part
+        boolean lastPart=false;
+
+        outer:while(!lastPart)
+        {
+            String contentDisposition=null;
+            String contentType=null;
+            String contentTransferEncoding=null;
+            
+            MultiMap<String> headers = new MultiMap<String>();
+            while(true)
+            {
+                line=((ReadLineInputStream)_in).readLine();
+                
+                //No more input
+                if(line==null)
+                    break outer;
+
+                // If blank line, end of part headers
+                if("".equals(line))
+                    break;
+                
+                total += line.length();
+                if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize())
+                    throw new IllegalStateException ("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")");
+
+                //get content-disposition and content-type
+                int c=line.indexOf(':',0);
+                if(c>0)
+                {
+                    String key=line.substring(0,c).trim().toLowerCase(Locale.ENGLISH);
+                    String value=line.substring(c+1,line.length()).trim();
+                    headers.put(key, value);
+                    if (key.equalsIgnoreCase("content-disposition"))
+                        contentDisposition=value;
+                    if (key.equalsIgnoreCase("content-type"))
+                        contentType = value;
+                    if(key.equals("content-transfer-encoding"))
+                        contentTransferEncoding=value;
+
+                }
+            }
+
+            // Extract content-disposition
+            boolean form_data=false;
+            if(contentDisposition==null)
+            {
+                throw new IOException("Missing content-disposition");
+            }
+
+            QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";", false, true);
+            String name=null;
+            String filename=null;
+            while(tok.hasMoreTokens())
+            {
+                String t=tok.nextToken().trim();
+                String tl=t.toLowerCase(Locale.ENGLISH);
+                if(t.startsWith("form-data"))
+                    form_data=true;
+                else if(tl.startsWith("name="))
+                    name=value(t, true);
+                else if(tl.startsWith("filename="))
+                    filename=filenameValue(t);
+            }
+
+            // Check disposition
+            if(!form_data)
+            {
+                continue;
+            }
+            //It is valid for reset and submit buttons to have an empty name.
+            //If no name is supplied, the browser skips sending the info for that field.
+            //However, if you supply the empty string as the name, the browser sends the
+            //field, with name as the empty string. So, only continue this loop if we
+            //have not yet seen a name field.
+            if(name==null)
+            {
+                continue;
+            }
+
+            //Have a new Part
+            MultiPart part = new MultiPart(name, filename);
+            part.setHeaders(headers);
+            part.setContentType(contentType);
+            _parts.add(name, part);
+            part.open();
+            
+            InputStream partInput = null;
+            if ("base64".equalsIgnoreCase(contentTransferEncoding))
+            {
+                partInput = new Base64InputStream((ReadLineInputStream)_in);
+            }
+            else if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding))
+            {
+                partInput = new FilterInputStream(_in)
+                {
+                    @Override
+                    public int read() throws IOException
+                    {
+                        int c = in.read();
+                        if (c >= 0 && c == '=')
+                        {
+                            int hi = in.read();
+                            int lo = in.read();
+                            if (hi < 0 || lo < 0)
+                            {
+                                throw new IOException("Unexpected end to quoted-printable byte");
+                            }
+                            char[] chars = new char[] { (char)hi, (char)lo };
+                            c = Integer.parseInt(new String(chars),16);
+                        }
+                        return c;
+                    }
+                };
+            }
+            else
+                partInput = _in;
+            
+            try
+            { 
+                int state=-2;
+                int c;
+                boolean cr=false;
+                boolean lf=false;
+
+                // loop for all lines
+                while(true)
+                {
+                    int b=0;
+                    while((c=(state!=-2)?state:partInput.read())!=-1)
+                    {
+                        total ++;
+                        if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize())
+                            throw new IllegalStateException("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")");
+                        
+                        state=-2;
+                        
+                        // look for CR and/or LF
+                        if(c==13||c==10)
+                        {
+                            if(c==13)
+                            {
+                                partInput.mark(1);
+                                int tmp=partInput.read();
+                                if (tmp!=10)
+                                    partInput.reset();
+                                else
+                                    state=tmp;
+                            }
+                            break;
+                        }
+                        
+                        // Look for boundary
+                        if(b>=0&&b<byteBoundary.length&&c==byteBoundary[b])
+                        {
+                            b++;
+                        }
+                        else
+                        {
+                            // Got a character not part of the boundary, so we don't have the boundary marker.
+                            // Write out as many chars as we matched, then the char we're looking at.
+                            if(cr)
+                                part.write(13);
+                    
+                            if(lf)
+                                part.write(10); 
+                            
+                            cr=lf=false;
+                            if(b>0)
+                                part.write(byteBoundary,0,b);
+                              
+                            b=-1;
+                            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))
+                    {
+                        if(cr)
+                            part.write(13);
+
+                        if(lf)
+                            part.write(10);
+
+                        cr=lf=false;
+                        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); 
+
+                    if(lf)
+                        part.write(10);
+
+                    cr=(c==13);
+                    lf=(c==10||state==10);
+                    if(state==10)
+                        state=-2;
+                }
+            }
+            finally
+            {
+                part.close();
+            }
+        }
+        if (!lastPart)
+            throw new IOException("Incomplete parts");
+    }
+    
+    public void setDeleteOnExit(boolean deleteOnExit)
+    {
+        _deleteOnExit = deleteOnExit;
+    }
+
+
+    public boolean isDeleteOnExit()
+    {
+        return _deleteOnExit;
+    }
+
+
+    /* ------------------------------------------------------------ */
+    private String value(String nameEqualsValue, boolean splitAfterSpace)
+    {
+        /*
+        String value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
+        int i=value.indexOf(';');
+        if(i>0)
+            value=value.substring(0,i);
+        if(value.startsWith("\""))
+        {
+            value=value.substring(1,value.indexOf('"',1));
+        }
+        else if (splitAfterSpace)
+        {
+            i=value.indexOf(' ');
+            if(i>0)
+                value=value.substring(0,i);
+        }
+        return value;
+        */
+         int idx = nameEqualsValue.indexOf('=');
+         String value = nameEqualsValue.substring(idx+1).trim();
+         return QuotedStringTokenizer.unquoteOnly(value);
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    private String filenameValue(String nameEqualsValue)
+    {
+        int idx = nameEqualsValue.indexOf('=');
+        String value = nameEqualsValue.substring(idx+1).trim();   
+
+        if (value.matches(".??[a-z,A-Z]\\:\\\\[^\\\\].*"))
+        {
+            //incorrectly escaped IE filenames that have the whole path
+            //we just strip any leading & trailing quotes and leave it as is
+            char first=value.charAt(0);
+            if (first=='"' || first=='\'')
+                value=value.substring(1);
+            char last=value.charAt(value.length()-1);
+            if (last=='"' || last=='\'')
+                value = value.substring(0,value.length()-1);
+
+            return value;
+        }
+        else
+            //unquote the string, but allow any backslashes that don't
+            //form a valid escape sequence to remain as many browsers
+            //even on *nix systems will not escape a filename containing
+            //backslashes
+            return QuotedStringTokenizer.unquoteOnly(value, true);
+    }
+    
+    private static class Base64InputStream extends InputStream
+    {
+        ReadLineInputStream _in;
+        String _line;
+        byte[] _buffer;
+        int _pos;
+
+    
+        public Base64InputStream(ReadLineInputStream rlis)
+        {
+            _in = rlis;
+        }
+
+        @Override
+        public int read() throws IOException
+        {
+            if (_buffer==null || _pos>= _buffer.length)
+            {
+                //Any CR and LF will be consumed by the readLine() call.
+                //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(); 
+                if (_line==null)
+                    return -1;  //nothing left
+                if (_line.startsWith("--"))
+                    _buffer=(_line+"\r\n").getBytes(); //boundary marking end of part
+                else if (_line.length()==0)
+                    _buffer="\r\n".getBytes(); //blank line
+                else
+                {
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream((4*_line.length()/3)+2);
+                    B64Code.decode(_line, baos);
+                    baos.write(13);
+                    baos.write(10);
+                    _buffer = baos.toByteArray();
+                }
+
+                _pos=0;
+            }
+            
+            return _buffer[_pos++];
+        }
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java
index 02e8ba6..96625e4 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java
@@ -58,8 +58,8 @@
                 int m=markpos;
                 markpos=-1;
                 if (pos>m)
-                    return new String(buf,m,pos-m,StringUtil.__UTF8);
-                
+                    return new String(buf,m,pos-m,StringUtil.__UTF8_CHARSET);
+
                 return null;
             }
             
@@ -77,7 +77,7 @@
                     _skipLF=true;
                 int m=markpos;
                 markpos=-1;
-                return new String(buf,m,p-m-1,StringUtil.__UTF8);
+                return new String(buf,m,p-m-1,StringUtil.__UTF8_CHARSET);
             }
             
             if (b=='\n')
@@ -91,7 +91,7 @@
                 }
                 int m=markpos;
                 markpos=-1;
-                return new String(buf,m,pos-m-1,StringUtil.__UTF8);
+                return new String(buf,m,pos-m-1,StringUtil.__UTF8_CHARSET);
             }
         }
     }
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 74fa201..6f74e02 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
@@ -487,6 +487,9 @@
 
 
     /* ------------------------------------------------------------ */
+    /**
+     * @deprecated
+     */
     public static byte[] readLine(InputStream in) throws IOException
     {
         byte[] buf = new byte[256];
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 fa74d6b..b7c24c4 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
@@ -226,7 +226,7 @@
                       key = null;
                       value=null;
                       if (maxKeys>0 && map.size()>maxKeys)
-                          throw new IllegalStateException("Form too many keys");
+                          throw new IllegalStateException(String.format("Form with too many keys [%d > %d]",map.size(),maxKeys));
                       break;
                   case '=':
                       if (key!=null)
@@ -414,7 +414,7 @@
                         key = null;
                         value=null;
                         if (maxKeys>0 && map.size()>maxKeys)
-                            throw new IllegalStateException("Form too many keys");
+                            throw new IllegalStateException(String.format("Form with too many keys [%d > %d]",map.size(),maxKeys));
                         break;
                         
                     case '=':
@@ -515,7 +515,7 @@
                             key = null;
                             value=null;
                             if (maxKeys>0 && map.size()>maxKeys)
-                                throw new IllegalStateException("Form too many keys");
+                                throw new IllegalStateException(String.format("Form with too many keys [%d > %d]",map.size(),maxKeys));
                             break;
 
                         case '=':
@@ -656,7 +656,7 @@
                         key = null;
                         value=null;
                         if (maxKeys>0 && map.size()>maxKeys)
-                            throw new IllegalStateException("Form too many keys");
+                            throw new IllegalStateException(String.format("Form with too many keys [%d > %d]",map.size(),maxKeys));
                         break;
                     case '=':
                         if (key!=null)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertor.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertor.java
index a35a32e..a489d3f 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertor.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertor.java
@@ -135,7 +135,7 @@
                     case 1:
                         if (name.startsWith("set") && name.length()>3)
                         {
-                            name=name.substring(3,4).toLowerCase()+name.substring(4);
+                            name=name.substring(3,4).toLowerCase(Locale.ENGLISH)+name.substring(4);
                             if(includeField(name, m))
                                 addSetter(name, m);
                         }
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 15d0367..7974448 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
@@ -65,19 +65,23 @@
         _list=null;
         _entry=null;
         _file=null;
-        
-        if ( _jarFile != null )
+        //if the jvm is not doing url caching, then the JarFiles will not be cached either,
+        //and so they are safe to close
+        if (!getUseCaches())
         {
-            try
+            if ( _jarFile != null )
             {
-                _jarFile.close();
-            }
-            catch ( IOException ioe )
-            {
-                LOG.ignore(ioe);
+                try
+                {
+                    LOG.debug("Closing JarFile "+_jarFile.getName());
+                    _jarFile.close();
+                }
+                catch ( IOException ioe )
+                {
+                    LOG.ignore(ioe);
+                }
             }
         }
-        
         _jarFile=null;
         super.release();
     }
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 21742e3..c0b0a90 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
@@ -18,6 +18,28 @@
 
 package org.eclipse.jetty.util.ssl;
 
+import org.eclipse.jetty.util.IO;
+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.Resource;
+import org.eclipse.jetty.util.security.CertificateUtils;
+import org.eclipse.jetty.util.security.CertificateValidator;
+import org.eclipse.jetty.util.security.Password;
+
+import javax.net.ssl.CertPathTrustManagerParameters;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -40,28 +62,6 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
-import javax.net.ssl.CertPathTrustManagerParameters;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import org.eclipse.jetty.util.IO;
-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.Resource;
-import org.eclipse.jetty.util.security.CertificateUtils;
-import org.eclipse.jetty.util.security.CertificateValidator;
-import org.eclipse.jetty.util.security.Password;
 
 
 /* ------------------------------------------------------------ */
@@ -111,12 +111,12 @@
     /** Excluded protocols. */
     private final Set<String> _excludeProtocols = new LinkedHashSet<String>();
     /** Included protocols. */
-    private Set<String> _includeProtocols = null;
+    private Set<String> _includeProtocols = new LinkedHashSet<String>();
 
     /** Excluded cipher suites. */
     private final Set<String> _excludeCipherSuites = new LinkedHashSet<String>();
     /** Included cipher suites. */
-    private Set<String> _includeCipherSuites = null;
+    private Set<String> _includeCipherSuites = new LinkedHashSet<String>();
 
     /** Keystore path. */
     private String _keyStorePath;
@@ -252,7 +252,7 @@
                 }
 
                 SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
-                _context = SSLContext.getInstance(_sslProtocol);
+                _context = (_sslProvider == null)?SSLContext.getInstance(_sslProtocol):SSLContext.getInstance(_sslProtocol,_sslProvider);
                 _context.init(null, trust_managers, secureRandom);
             }
             else
@@ -323,7 +323,6 @@
     public void setExcludeProtocols(String... protocols)
     {
         checkNotStarted();
-
         _excludeProtocols.clear();
         _excludeProtocols.addAll(Arrays.asList(protocols));
     }
@@ -357,8 +356,8 @@
     public void setIncludeProtocols(String... protocols)
     {
         checkNotStarted();
-
-        _includeProtocols = new LinkedHashSet<String>(Arrays.asList(protocols));
+        _includeProtocols.clear();
+        _includeProtocols.addAll(Arrays.asList(protocols));
     }
 
     /* ------------------------------------------------------------ */
@@ -413,8 +412,8 @@
     public void setIncludeCipherSuites(String... cipherSuites)
     {
         checkNotStarted();
-
-        _includeCipherSuites = new LinkedHashSet<String>(Arrays.asList(cipherSuites));
+        _includeCipherSuites.clear();
+        _includeCipherSuites.addAll(Arrays.asList(cipherSuites));
     }
 
     /* ------------------------------------------------------------ */
@@ -1214,7 +1213,7 @@
         Set<String> selected_protocols = new LinkedHashSet<String>();
 
         // Set the starting protocols - either from the included or enabled list
-        if (_includeProtocols!=null)
+        if (!_includeProtocols.isEmpty())
         {
             // Use only the supported included protocols
             for (String protocol : _includeProtocols)
@@ -1246,7 +1245,7 @@
         Set<String> selected_ciphers = new LinkedHashSet<String>();
 
         // Set the starting ciphers - either from the included or enabled list
-        if (_includeCipherSuites!=null)
+        if (!_includeCipherSuites.isEmpty())
         {
             // Use only the supported included ciphers
             for (String cipherSuite : _includeCipherSuites)
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
index 9ec4413..6bc310f 100644
--- 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
@@ -25,7 +25,6 @@
 import java.util.List;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.Executor;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -33,6 +32,7 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.eclipse.jetty.util.BlockingArrayQueue;
+import org.eclipse.jetty.util.ConcurrentHashSet;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.component.AggregateLifeCycle;
 import org.eclipse.jetty.util.component.Dumpable;
@@ -48,7 +48,7 @@
     private final AtomicInteger _threadsStarted = new AtomicInteger();
     private final AtomicInteger _threadsIdle = new AtomicInteger();
     private final AtomicLong _lastShrink = new AtomicLong();
-    private final ConcurrentLinkedQueue<Thread> _threads=new ConcurrentLinkedQueue<Thread>();
+    private final ConcurrentHashSet<Thread> _threads=new ConcurrentHashSet<Thread>();
     private final Object _joinLock = new Object();
     private BlockingQueue<Runnable> _jobs;
     private String _name;
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java
new file mode 100644
index 0000000..9e617e0
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java
@@ -0,0 +1,858 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+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.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.util.Collection;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.ServletException;
+import javax.servlet.http.Part;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jetty.util.MultiPartInputStream.MultiPart;
+import org.hamcrest.core.IsNot;
+
+/**
+ * MultiPartInputStreamTest
+ *
+ *
+ */
+public class MultiPartInputStreamTest extends TestCase
+{
+    private static final String FILENAME = "stuff.txt";
+    protected String _contentType = "multipart/form-data, boundary=AaB03x";
+    protected String _multi = createMultipartRequestString(FILENAME);
+    protected String _dirname = System.getProperty("java.io.tmpdir")+File.separator+"myfiles-"+System.currentTimeMillis();
+    protected File _tmpDir = new File(_dirname);
+    
+    public MultiPartInputStreamTest ()
+    {
+        _tmpDir.deleteOnExit();
+    }
+    
+    public void testBadMultiPartRequest()
+    throws Exception
+    {
+        String boundary = "X0Y0";
+        String str = "--" + boundary + "\r\n"+
+        "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n"+
+        "Content-Type: application/octet-stream\r\n\r\n"+
+        "How now brown cow."+
+        "\r\n--" + boundary + "-\r\n\r\n";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(str.getBytes()), 
+                                                             "multipart/form-data, boundary="+boundary,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        try
+        {
+            mpis.getParts();
+            fail ("Multipart incomplete");
+        }
+        catch (IOException e)
+        {
+            assertTrue(e.getMessage().startsWith("Incomplete"));
+        }
+    }
+
+    
+    public void testNoBoundaryRequest()
+    throws Exception
+    {
+        String str = "--\r\n"+
+        "Content-Disposition: form-data; name=\"fileName\"\r\n"+
+            "Content-Type: text/plain; charset=US-ASCII\r\n"+
+            "Content-Transfer-Encoding: 8bit\r\n"+
+            "\r\n"+
+            "abc\r\n"+
+            "--\r\n"+
+            "Content-Disposition: form-data; name=\"desc\"\r\n"+ 
+            "Content-Type: text/plain; charset=US-ASCII\r\n"+ 
+            "Content-Transfer-Encoding: 8bit\r\n"+
+            "\r\n"+
+            "123\r\n"+ 
+            "--\r\n"+ 
+            "Content-Disposition: form-data; name=\"title\"\r\n"+
+            "Content-Type: text/plain; charset=US-ASCII\r\n"+
+            "Content-Transfer-Encoding: 8bit\r\n"+ 
+            "\r\n"+
+            "ttt\r\n"+ 
+            "--\r\n"+
+            "Content-Disposition: form-data; name=\"datafile5239138112980980385.txt\"; filename=\"datafile5239138112980980385.txt\"\r\n"+
+            "Content-Type: application/octet-stream; charset=ISO-8859-1\r\n"+
+            "Content-Transfer-Encoding: binary\r\n"+ 
+            "\r\n"+
+            "000\r\n"+ 
+            "----\r\n";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(str.getBytes()),
+                                                             "multipart/form-data",
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(4));
+        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Part fileName = mpis.getPart("fileName");
+        assertThat(fileName, notNullValue());
+        assertThat(fileName.getSize(), is(3L));
+        IO.copy(fileName.getInputStream(), baos);
+        assertThat(baos.toString("US-ASCII"), is("abc"));
+       
+        baos = new ByteArrayOutputStream();
+        Part desc = mpis.getPart("desc");
+        assertThat(desc, notNullValue());
+        assertThat(desc.getSize(), is(3L));
+        IO.copy(desc.getInputStream(), baos);
+        assertThat(baos.toString("US-ASCII"), is("123"));
+        
+        baos = new ByteArrayOutputStream();
+        Part title = mpis.getPart("title");
+        assertThat(title, notNullValue());
+        assertThat(title.getSize(), is(3L));
+        IO.copy(title.getInputStream(), baos);
+        assertThat(baos.toString("US-ASCII"), is("ttt"));  
+    }
+
+    public void testNoBody()
+    throws Exception
+    {
+        String body = "";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(body.getBytes()), 
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        try
+        {
+            mpis.getParts();
+            fail ("Multipart missing body");
+        }
+        catch (IOException e)
+        {
+            assertTrue(e.getMessage().startsWith("Missing content"));
+        }
+    }
+    
+    public void testWhitespaceBodyWithCRLF()
+    throws Exception
+    {
+        String whitespace = "              \n\n\n\r\n\r\n\r\n\r\n";
+ 
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(whitespace.getBytes()), 
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        try
+        {
+            mpis.getParts();
+            fail ("Multipart missing body");
+        }
+        catch (IOException e)
+        {
+            assertTrue(e.getMessage().startsWith("Missing initial"));
+        }
+    }
+    
+    public void testWhitespaceBody()
+    throws Exception
+    {
+        String whitespace = " ";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(whitespace.getBytes()), 
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        try
+        {
+            mpis.getParts();
+            fail ("Multipart missing body");
+        }
+        catch (IOException e)
+        {
+            assertTrue(e.getMessage().startsWith("Missing initial"));
+        }
+    }
+
+
+    public void testLeadingWhitespaceBodyWithCRLF()
+    throws Exception
+    {
+        String body = "              \n\n\n\r\n\r\n\r\n\r\n"+
+                      "--AaB03x\r\n"+
+                      "content-disposition: form-data; name=\"field1\"\r\n"+
+                      "\r\n"+
+                      "Joe Blow\r\n"+
+                      "--AaB03x\r\n"+
+                      "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+
+                      "Content-Type: text/plain\r\n"+
+                      "\r\n"+"aaaa"+
+                      "bbbbb"+"\r\n" +
+                      "--AaB03x--\r\n";
+
+
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(body.getBytes()),
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+ 
+        Collection<Part> parts =    mpis.getParts();
+        assertThat(parts, notNullValue());
+        assertThat(parts.size(), is(2));
+        Part field1 = mpis.getPart("field1");
+        assertThat(field1, notNullValue());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IO.copy(field1.getInputStream(), baos);
+        assertThat(baos.toString("US-ASCII"), is("Joe Blow"));
+        
+        Part stuff = mpis.getPart("stuff");
+        assertThat(stuff, notNullValue());
+        baos = new ByteArrayOutputStream();
+        IO.copy(stuff.getInputStream(), baos);
+        assertTrue(baos.toString("US-ASCII").contains("aaaa"));
+    }
+    
+
+
+
+    public void testLeadingWhitespaceBodyWithoutCRLF()
+    throws Exception
+    {
+        String body = "            "+
+        "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"field1\"\r\n"+
+        "\r\n"+
+        "Joe Blow\r\n"+
+        "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+
+        "Content-Type: text/plain\r\n"+
+        "\r\n"+"aaaa"+
+        "bbbbb"+"\r\n" +
+        "--AaB03x--\r\n";
+
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(body.getBytes()),
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+ 
+        Collection<Part> parts =    mpis.getParts();
+        assertThat(parts, notNullValue());
+        assertThat(parts.size(), is(2));
+        Part field1 = mpis.getPart("field1");
+        assertThat(field1, notNullValue());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IO.copy(field1.getInputStream(), baos);
+        assertThat(baos.toString("US-ASCII"), is("Joe Blow"));
+        
+        Part stuff = mpis.getPart("stuff");
+        assertThat(stuff, notNullValue());
+        baos = new ByteArrayOutputStream();
+        IO.copy(stuff.getInputStream(), baos);
+        assertTrue(baos.toString("US-ASCII").contains("bbbbb"));
+    }
+    
+    
+    
+    
+    
+
+    public void testNonMultiPartRequest()
+    throws Exception
+    {
+
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);  
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), 
+                                                             "Content-type: text/plain",
+                                                             config,
+                                                            _tmpDir);
+        mpis.setDeleteOnExit(true);
+        assertTrue(mpis.getParts().isEmpty());   
+    }
+    
+    public void testNoLimits()
+    throws Exception
+    {
+        MultipartConfigElement config = new MultipartConfigElement(_dirname);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), 
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertFalse(parts.isEmpty());
+    }
+
+    public void testRequestTooBig ()
+    throws Exception
+    {
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 60, 100, 50);  
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), 
+                                                            _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = null;
+        try
+        {
+            parts = mpis.getParts();
+            fail("Request should have exceeded maxRequestSize");
+        }
+        catch (IllegalStateException e)
+        {
+            assertTrue(e.getMessage().startsWith("Request exceeds maxRequestSize"));
+        }
+    }
+    
+    public void testFileTooBig()
+    throws Exception
+    {
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 40, 1024, 30);  
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), 
+                                                            _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = null;
+        try
+        {
+            parts = mpis.getParts();
+            fail("stuff.txt should have been larger than maxFileSize");
+        }
+        catch (IllegalStateException e)
+        {
+            assertTrue(e.getMessage().startsWith("Multipart Mime part"));
+        }
+    }
+    
+    public void testPartFileNotDeleted () throws Exception
+    {
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);  
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()),
+                _contentType,
+                config,
+                _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        
+        MultiPart part = (MultiPart)mpis.getPart("stuff");
+        File stuff = ((MultiPartInputStream.MultiPart)part).getFile();
+        assertThat(stuff,notNullValue()); // longer than 100 bytes, should already be a tmp file
+        part.write("tptfd.txt");
+        File tptfd = new File (_dirname+File.separator+"tptfd.txt");
+        assertThat(tptfd.exists(), is(true));
+        assertThat(stuff.exists(), is(false)); //got renamed
+        part.cleanUp();
+        assertThat(tptfd.exists(), is(true));  //explicitly written file did not get removed after cleanup
+        tptfd.deleteOnExit(); //clean up test
+    }
+    
+    
+    public void testPartTmpFileDeletion () throws Exception
+    {
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);  
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()),
+                _contentType,
+                config,
+                _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        
+        MultiPart part = (MultiPart)mpis.getPart("stuff");
+        File stuff = ((MultiPartInputStream.MultiPart)part).getFile();
+        assertThat(stuff,notNullValue()); // longer than 100 bytes, should already be a tmp file
+        assertThat (stuff.exists(), is(true));
+        part.cleanUp();
+        assertThat(stuff.exists(), is(false));  //tmp file was removed after cleanup
+    }
+    
+ 
+    public void testLFOnlyRequest()
+    throws Exception
+    {
+        String str = "--AaB03x\n"+
+                "content-disposition: form-data; name=\"field1\"\n"+
+                "\n"+
+                "Joe Blow\n"+ 
+                "--AaB03x\n"+
+                "content-disposition: form-data; name=\"field2\"\n"+
+                "\n"+
+                "Other\n"+        
+                "--AaB03x--\n";
+
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(str.getBytes()),
+                                                                         _contentType,
+                                                                         config,
+                                                                         _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(2));
+        Part p1 = mpis.getPart("field1");
+        assertThat(p1, notNullValue());      
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IO.copy(p1.getInputStream(), baos);
+        assertThat(baos.toString("UTF-8"), is("Joe Blow"));
+                
+        Part p2 = mpis.getPart("field2");
+        assertThat(p2, notNullValue());
+        baos = new ByteArrayOutputStream();
+        IO.copy(p2.getInputStream(), baos);
+        assertThat(baos.toString("UTF-8"), is("Other"));
+    }
+    
+ 
+    public void testCROnlyRequest()
+    throws Exception
+    {
+        String str = "--AaB03x\r"+
+        "content-disposition: form-data; name=\"field1\"\r"+
+        "\r"+
+        "Joe Blow\r"+ 
+        "--AaB03x\r"+
+        "content-disposition: form-data; name=\"field2\"\r"+
+        "\r"+
+        "Other\r"+        
+        "--AaB03x--\r";
+
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(str.getBytes()),
+                                                                         _contentType,
+                                                                         config,
+                                                                         _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(2));
+        
+        assertThat(parts.size(), is(2));
+        Part p1 = mpis.getPart("field1");
+        assertThat(p1, notNullValue());
+        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IO.copy(p1.getInputStream(), baos);
+        assertThat(baos.toString("UTF-8"), is("Joe Blow"));
+        
+        Part p2 = mpis.getPart("field2");
+        assertThat(p2, notNullValue());
+        baos = new ByteArrayOutputStream();
+        IO.copy(p2.getInputStream(), baos);
+        assertThat(baos.toString("UTF-8"), is("Other"));
+    }
+
+   
+    public void testCRandLFMixRequest()
+    throws Exception
+    {
+        String str = "--AaB03x\r"+
+                "content-disposition: form-data; name=\"field1\"\r"+
+                "\r"+
+                "\nJoe Blow\n"+ 
+                "\r"+
+                "--AaB03x\r"+
+                "content-disposition: form-data; name=\"field2\"\r"+
+                "\r"+
+                "Other\r"+        
+                "--AaB03x--\r";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(str.getBytes()),
+                                                                         _contentType,
+                                                                         config,
+                                                                         _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(2));
+
+        Part p1 = mpis.getPart("field1");
+        assertThat(p1, notNullValue());      
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IO.copy(p1.getInputStream(), baos);
+        assertThat(baos.toString("UTF-8"), is("\nJoe Blow\n"));
+        
+        Part p2 = mpis.getPart("field2");
+        assertThat(p2, notNullValue());
+        baos = new ByteArrayOutputStream();
+        IO.copy(p2.getInputStream(), baos);
+        assertThat(baos.toString("UTF-8"), is("Other")); 
+    }
+    
+
+    public void testBufferOverflowNoCRLF () throws Exception
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        baos.write("--AaB03x".getBytes());
+        for (int i=0; i< 8500; i++) //create content that will overrun default buffer size of BufferedInputStream
+        {
+            baos.write('a');
+        }
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(baos.toByteArray()), 
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        try
+        {
+            mpis.getParts();
+            fail ("Multipart buffer overrun");
+        }
+        catch (IOException e)
+        {
+            assertTrue(e.getMessage().startsWith("Buffer size exceeded"));
+        }
+
+    }
+    
+    
+    public void testCharsetEncoding () throws Exception
+    {
+        String contentType = "multipart/form-data; boundary=TheBoundary; charset=ISO-8859-1";
+        String str = "--TheBoundary\r"+
+                "content-disposition: form-data; name=\"field1\"\r"+
+                "\r"+
+                "\nJoe Blow\n"+ 
+                "\r"+
+                "--TheBoundary--\r";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(str.getBytes()),
+                                                                         contentType,
+                                                                         config,
+                                                                         _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(1));
+    }
+    
+    
+    public void testBadlyEncodedFilename() throws Exception
+    {
+        
+        String contents =  "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"; filename=\"" +"Taken on Aug 22 \\ 2012.jpg"  + "\"\r\n"+
+        "Content-Type: text/plain\r\n"+
+        "\r\n"+"stuff"+
+        "aaa"+"\r\n" +
+        "--AaB03x--\r\n";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(contents.getBytes()),
+                                                                         _contentType,
+                                                                         config,
+                                                                         _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(1));
+        assertThat(((MultiPartInputStream.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("Taken on Aug 22 \\ 2012.jpg"));
+    }
+    
+    public void testBadlyEncodedMSFilename() throws Exception
+    {
+        
+        String contents =  "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"; filename=\"" +"c:\\this\\really\\is\\some\\path\\to\\a\\file.txt"  + "\"\r\n"+
+        "Content-Type: text/plain\r\n"+
+        "\r\n"+"stuff"+
+        "aaa"+"\r\n" +
+        "--AaB03x--\r\n";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(contents.getBytes()),
+                                                                         _contentType,
+                                                                         config,
+                                                                         _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(1));
+        assertThat(((MultiPartInputStream.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt"));
+    }
+
+    public void testCorrectlyEncodedMSFilename() throws Exception
+    {
+        String contents =  "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"; filename=\"" +"c:\\\\this\\\\really\\\\is\\\\some\\\\path\\\\to\\\\a\\\\file.txt"  + "\"\r\n"+
+        "Content-Type: text/plain\r\n"+
+        "\r\n"+"stuff"+
+        "aaa"+"\r\n" +
+        "--AaB03x--\r\n";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(contents.getBytes()),
+                                                                         _contentType,
+                                                                         config,
+                                                                         _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(1));
+        assertThat(((MultiPartInputStream.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt"));
+    }
+    
+    public void testMulti ()
+    throws Exception
+    {
+        testMulti(FILENAME);
+    }
+
+    public void testMultiWithSpaceInFilename() throws Exception
+    {
+        testMulti("stuff with spaces.txt");
+    }
+
+    
+    
+    
+    private void testMulti(String filename) throws IOException, ServletException
+    {
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);  
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(createMultipartRequestString(filename).getBytes()),
+                _contentType,
+                config,
+                _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertThat(parts.size(), is(2));
+        Part field1 = mpis.getPart("field1");  //field 1 too small to go into tmp file, should be in internal buffer
+        assertThat(field1,notNullValue());
+        assertThat(field1.getName(),is("field1"));
+        InputStream is = field1.getInputStream();
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        IO.copy(is, os);
+        assertEquals("Joe Blow", new String(os.toByteArray()));
+        assertEquals(8, field1.getSize());
+        
+        assertNotNull(((MultiPartInputStream.MultiPart)field1).getBytes());//in internal buffer
+        field1.write("field1.txt");
+        assertNull(((MultiPartInputStream.MultiPart)field1).getBytes());//no longer in internal buffer
+        File f = new File (_dirname+File.separator+"field1.txt");
+        assertTrue(f.exists());
+        field1.write("another_field1.txt"); //write after having already written
+        File f2 = new File(_dirname+File.separator+"another_field1.txt");
+        assertTrue(f2.exists());
+        assertFalse(f.exists()); //should have been renamed
+        field1.delete();  //file should be deleted
+        assertFalse(f.exists()); //original file was renamed
+        assertFalse(f2.exists()); //2nd written file was explicitly deleted
+        
+        MultiPart stuff = (MultiPart)mpis.getPart("stuff");
+        assertThat(stuff.getContentDispositionFilename(), is(filename));
+        assertThat(stuff.getContentType(),is("text/plain"));
+        assertThat(stuff.getHeader("Content-Type"),is("text/plain"));
+        assertThat(stuff.getHeaders("content-type").size(),is(1));
+        assertThat(stuff.getHeader("content-disposition"),is("form-data; name=\"stuff\"; filename=\"" + filename + "\""));
+        assertThat(stuff.getHeaderNames().size(),is(2));
+        assertThat(stuff.getSize(),is(51L));
+        File tmpfile = ((MultiPartInputStream.MultiPart)stuff).getFile();
+        assertThat(tmpfile,notNullValue()); // longer than 100 bytes, should already be a tmp file
+        assertThat(((MultiPartInputStream.MultiPart)stuff).getBytes(),nullValue()); //not in an internal buffer
+        assertThat(tmpfile.exists(),is(true));
+        assertThat(tmpfile.getName(),is(not("stuff with space.txt")));
+        stuff.write(filename);
+        f = new File(_dirname+File.separator+filename);
+        assertThat(f.exists(),is(true));
+        assertThat(tmpfile.exists(), is(false));
+        try
+        {
+            stuff.getInputStream();          
+        }
+        catch (Exception e)
+        {
+            fail("Part.getInputStream() after file rename operation");
+        }
+        f.deleteOnExit(); //clean up after test
+    }
+
+    public void testMultiSameNames ()
+    throws Exception
+    {
+        String sameNames =  "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"; filename=\"stuff1.txt\"\r\n"+
+        "Content-Type: text/plain\r\n"+
+        "\r\n"+
+        "00000\r\n"+
+        "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"; filename=\"stuff2.txt\"\r\n"+
+        "Content-Type: text/plain\r\n"+
+        "\r\n"+
+        "110000000000000000000000000000000000000000000000000\r\n"+
+        "--AaB03x--\r\n";
+        
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);          
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(sameNames.getBytes()),
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertEquals(2, parts.size());
+        for (Part p:parts)
+            assertEquals("stuff", p.getName());
+        
+        //if they all have the name name, then only retrieve the first one
+        Part p = mpis.getPart("stuff");
+        assertNotNull(p);
+        assertEquals(5, p.getSize());
+    }
+
+
+    public void testBase64EncodedContent () throws Exception
+    {
+        String contentWithEncodedPart =
+                "--AaB03x\r\n"+
+                        "Content-disposition: form-data; name=\"other\"\r\n"+
+                        "Content-Type: text/plain\r\n"+
+                        "\r\n"+
+                        "other" + "\r\n"+
+                        "--AaB03x\r\n"+
+                        "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+
+                        "Content-Transfer-Encoding: base64\r\n"+
+                        "Content-Type: application/octet-stream\r\n"+
+                        "\r\n"+
+                        B64Code.encode("hello jetty") + "\r\n"+                  
+                        "--AaB03x\r\n"+
+                        "Content-disposition: form-data; name=\"final\"\r\n"+
+                        "Content-Type: text/plain\r\n"+
+                        "\r\n"+
+                        "the end" + "\r\n"+
+                        "--AaB03x--\r\n";
+
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(contentWithEncodedPart.getBytes()),
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertEquals(3, parts.size());
+       
+        Part p1 = mpis.getPart("other");
+        assertNotNull(p1);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IO.copy(p1.getInputStream(), baos);
+        assertEquals("other", baos.toString("US-ASCII"));
+
+        Part p2 = mpis.getPart("stuff");
+        assertNotNull(p2);
+        baos = new ByteArrayOutputStream();
+        IO.copy(p2.getInputStream(), baos);
+        assertEquals("hello jetty", baos.toString("US-ASCII"));
+        
+        Part p3 = mpis.getPart("final");
+        assertNotNull(p3);
+        baos = new ByteArrayOutputStream();
+        IO.copy(p3.getInputStream(), baos);
+        assertEquals("the end", baos.toString("US-ASCII"));
+    }
+    
+    public void testQuotedPrintableEncoding () throws Exception
+    {
+        String contentWithEncodedPart = 
+                "--AaB03x\r\n"+
+                        "Content-disposition: form-data; name=\"other\"\r\n"+
+                        "Content-Type: text/plain\r\n"+
+                        "\r\n"+
+                        "other" + "\r\n"+
+                        "--AaB03x\r\n"+
+                        "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+
+                        "Content-Transfer-Encoding: quoted-printable\r\n"+
+                        "Content-Type: text/plain\r\n"+
+                        "\r\n"+
+                        "truth=3Dbeauty" + "\r\n"+
+                        "--AaB03x--\r\n";  
+        MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
+        MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(contentWithEncodedPart.getBytes()),
+                                                             _contentType,
+                                                             config,
+                                                             _tmpDir);
+        mpis.setDeleteOnExit(true);
+        Collection<Part> parts = mpis.getParts();
+        assertEquals(2, parts.size());
+
+        Part p1 = mpis.getPart("other");
+        assertNotNull(p1);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IO.copy(p1.getInputStream(), baos);
+        assertEquals("other", baos.toString("US-ASCII"));
+
+        Part p2 = mpis.getPart("stuff");
+        assertNotNull(p2);
+        baos = new ByteArrayOutputStream();
+        IO.copy(p2.getInputStream(), baos);
+        assertEquals("truth=beauty", baos.toString("US-ASCII"));
+    }
+
+
+
+
+    
+    private String createMultipartRequestString(String filename)
+    {
+        int length = filename.length();
+        String name = filename;
+        if (length > 10)
+            name = filename.substring(0,10);
+        StringBuffer filler = new StringBuffer();
+        int i = name.length();
+        while (i < 51)
+        {
+            filler.append("0");
+            i++;
+        }
+        
+        return "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"field1\"\r\n"+
+        "\r\n"+
+        "Joe Blow\r\n"+
+        "--AaB03x\r\n"+
+        "content-disposition: form-data; name=\"stuff\"; filename=\"" + filename + "\"\r\n"+
+        "Content-Type: text/plain\r\n"+
+        "\r\n"+name+
+        filler.toString()+"\r\n" +
+        "--AaB03x--\r\n";
+    }
+}
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 826bb1e..2992852 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
@@ -118,11 +118,11 @@
     /* ------------------------------------------------------------ */
     @BeforeClass
     public static void setUp()
-        throws Exception
+    throws Exception
     {
         if (data!=null)
             return;
-        
+
         File file = new File(__userDir);
         file=new File(file.getCanonicalPath());
         URI uri = file.toURI();
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 88780b3..3c23805 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,10 +18,6 @@
 
 package org.eclipse.jetty.util.ssl;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.KeyStore;
-
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.StdErrLog;
@@ -30,51 +26,56 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import static junit.framework.Assert.assertTrue;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 
-public class SslContextFactoryTest
+public class SslContextFactoryTest 
 {
 
     private SslContextFactory cf;
 
     @Before
-    public void setUp() throws Exception
+    public void setUp() throws Exception 
     {
         cf = new SslContextFactory();
     }
 
     @Test
-    public void testNoTsFileKs() throws Exception
+    public void testNoTsFileKs() throws Exception 
     {
-        String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
+        String keystorePath = System.getProperty("basedir", ".") + "/src/test/resources/keystore";
         cf.setKeyStorePassword("storepwd");
         cf.setKeyManagerPassword("keypwd");
-        
+
         cf.start();
-        
-        assertTrue(cf.getSslContext()!=null);
+
+        assertTrue(cf.getSslContext() != null);
     }
-    
+
     @Test
-    public void testNoTsStreamKs() throws Exception
+    public void testNoTsStreamKs() throws Exception 
     {
         InputStream keystoreInputStream = this.getClass().getResourceAsStream("keystore");
 
         cf.setKeyStoreInputStream(keystoreInputStream);
         cf.setKeyStorePassword("storepwd");
         cf.setKeyManagerPassword("keypwd");
-        
+
         cf.start();
-        
-        assertTrue(cf.getSslContext()!=null);
+
+        assertTrue(cf.getSslContext() != null);
     }
-    
+
     @Test
-    public void testNoTsSetKs() throws Exception
+    public void testNoTsSetKs() throws Exception 
     {
         InputStream keystoreInputStream = this.getClass().getResourceAsStream("keystore");
 
@@ -83,28 +84,28 @@
 
         cf.setKeyStore(ks);
         cf.setKeyManagerPassword("keypwd");
-        
+
         cf.start();
-        
-        assertTrue(cf.getSslContext()!=null);
-    }
-    
-    @Test
-    public void testNoTsNoKs() throws Exception
-    {
-        cf.start();
-        assertTrue(cf.getSslContext()!=null);
-    }
-    
-    @Test
-    public void testTrustAll() throws Exception
-    {
-        cf.start();
-        assertTrue(cf.getSslContext()!=null);
+
+        assertTrue(cf.getSslContext() != null);
     }
 
     @Test
-    public void testNoTsResourceKs() throws Exception
+    public void testNoTsNoKs() throws Exception 
+    {
+        cf.start();
+        assertTrue(cf.getSslContext() != null);
+    }
+
+    @Test
+    public void testTrustAll() throws Exception 
+    {
+        cf.start();
+        assertTrue(cf.getSslContext() != null);
+    }
+
+    @Test
+    public void testNoTsResourceKs() throws Exception 
     {
         Resource keystoreResource = Resource.newSystemResource("keystore");
 
@@ -114,11 +115,11 @@
 
         cf.start();
 
-        assertTrue(cf.getSslContext()!=null);
+        assertTrue(cf.getSslContext() != null);
     }
 
     @Test
-    public void testResourceTsResourceKs() throws Exception
+    public void testResourceTsResourceKs() throws Exception 
     {
         Resource keystoreResource = Resource.newSystemResource("keystore");
         Resource truststoreResource = Resource.newSystemResource("keystore");
@@ -131,11 +132,11 @@
 
         cf.start();
 
-        assertTrue(cf.getSslContext()!=null);
+        assertTrue(cf.getSslContext() != null);
     }
 
     @Test
-    public void testResourceTsResourceKsWrongPW() throws Exception
+    public void testResourceTsResourceKsWrongPW() throws Exception 
     {
         Resource keystoreResource = Resource.newSystemResource("keystore");
         Resource truststoreResource = Resource.newSystemResource("keystore");
@@ -146,19 +147,16 @@
         cf.setKeyManagerPassword("wrong_keypwd");
         cf.setTrustStorePassword("storepwd");
 
-        try
-        {
-            ((StdErrLog)Log.getLogger(AbstractLifeCycle.class)).setHideStacks(true);
+        try {
+            ((StdErrLog) Log.getLogger(AbstractLifeCycle.class)).setHideStacks(true);
             cf.start();
             Assert.fail();
-        }
-        catch(java.security.UnrecoverableKeyException e)
-        {
+        } catch (java.security.UnrecoverableKeyException e) {
         }
     }
 
     @Test
-    public void testResourceTsWrongPWResourceKs() throws Exception
+    public void testResourceTsWrongPWResourceKs() throws Exception 
     {
         Resource keystoreResource = Resource.newSystemResource("keystore");
         Resource truststoreResource = Resource.newSystemResource("keystore");
@@ -169,39 +167,31 @@
         cf.setKeyManagerPassword("keypwd");
         cf.setTrustStorePassword("wrong_storepwd");
 
-        try
-        {
-            ((StdErrLog)Log.getLogger(AbstractLifeCycle.class)).setHideStacks(true);
+        try {
+            ((StdErrLog) Log.getLogger(AbstractLifeCycle.class)).setHideStacks(true);
             cf.start();
             Assert.fail();
-        }
-        catch(IOException e)
-        {
+        } catch (IOException e) {
         }
     }
-    
+
     @Test
-    public void testNoKeyConfig() throws Exception
+    public void testNoKeyConfig() throws Exception 
     {
-        try
-        {
-            ((StdErrLog)Log.getLogger(AbstractLifeCycle.class)).setHideStacks(true);
+        try {
+            ((StdErrLog) Log.getLogger(AbstractLifeCycle.class)).setHideStacks(true);
             cf.setTrustStore("/foo");
             cf.start();
             Assert.fail();
-        }
-        catch (IllegalStateException e)
-        {
-            
-        }
-        catch (Exception e)
-        {
+        } catch (IllegalStateException e) {
+
+        } catch (Exception e) {
             Assert.fail("Unexpected exception");
         }
     }
 
     @Test
-    public void testSetIncludeCipherSuitesPreservesOrder()
+    public void testSetIncludeCipherSuitesPreservesOrder() 
     {
         String[] supportedCipherSuites = new String[]{"cipher4", "cipher2", "cipher1", "cipher3"};
         String[] includeCipherSuites = {"cipher1", "cipher3", "cipher4"};
@@ -213,7 +203,7 @@
     }
 
     @Test
-    public void testSetIncludeProtocolsPreservesOrder()
+    public void testSetIncludeProtocolsPreservesOrder() 
     {
         String[] supportedProtocol = new String[]{"cipher4", "cipher2", "cipher1", "cipher3"};
         String[] includeProtocol = {"cipher1", "cipher3", "cipher4"};
@@ -224,11 +214,20 @@
         assertSelectedMatchesIncluded(includeProtocol, selectedProtocol);
     }
 
-    private void assertSelectedMatchesIncluded(String[] includeStrings, String[] selectedStrings)
+    private void assertSelectedMatchesIncluded(String[] includeStrings, String[] selectedStrings) 
     {
         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]));
     }
+
+    @Test
+    public void testProtocolAndCipherSettingsAreNPESafe() 
+    {
+        assertNotNull(cf.getExcludeProtocols());
+        assertNotNull(cf.getIncludeProtocols());
+        assertNotNull(cf.getExcludeCipherSuites());
+        assertNotNull(cf.getIncludeCipherSuites());
+    }
 }
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java
index 3c2faa6..7555a76 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java
@@ -29,6 +29,8 @@
 
 public class TimeoutTest
 {
+	private boolean _stress=Boolean.getBoolean("STRESS");
+	
     Object lock = new Object();
     Timeout timeout = new Timeout(null);
     Timeout.Task[] tasks;
@@ -136,6 +138,9 @@
     @Test
     public void testStress() throws Exception
     {
+    	if ( !_stress )
+    		return;
+    	
         final int LOOP=250;
         final AtomicBoolean running=new AtomicBoolean(true);
         final AtomicIntegerArray count = new AtomicIntegerArray( 4 );
diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml
index fdda808..0b2be79 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-webapp</artifactId>
@@ -53,6 +53,11 @@
             <goals>
               <goal>manifest</goal>
             </goals>
+            <configuration>
+              <instructions>
+                <Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
+              </instructions>
+            </configuration>
           </execution>
         </executions>
       </plugin>
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java
index e815ad6..753f844 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java
@@ -21,6 +21,7 @@
 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.resource.Resource;
 
 /**
  * DiscoveredAnnotation
@@ -36,16 +37,28 @@
     protected WebAppContext _context;
     protected String _className;
     protected Class<?> _clazz;
+    protected Resource _resource; //resource it was discovered on, can be null (eg from WEB-INF/classes)
     
     public abstract void apply();
     
     public DiscoveredAnnotation (WebAppContext context, String className)
     {
-        _context = context;
-        _className = className;
+        this(context,className, null);
     } 
     
     
+    public DiscoveredAnnotation(WebAppContext context, String className, Resource resource)
+    {
+        _context = context;
+        _className = className;
+        _resource = resource;
+    }
+    
+    public Resource getResource ()
+    {
+        return _resource;
+    }
+    
     public Class<?> getTargetClass()
     {
         if (_clazz != null)
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java
index 52eeba7..0f9208d 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java
@@ -136,7 +136,7 @@
             node = (XmlParser.Node) o;
             if (node.getTag().equalsIgnoreCase("others"))
             {
-                if (_otherType != OtherType.After)
+                if (_otherType != OtherType.None)
                     throw new IllegalStateException("Duplicate <other> clause detected in "+_xml.getURI());
 
                 _otherType = OtherType.After;
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java
index aaad463..f1e13e2 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.webapp;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import org.eclipse.jetty.util.log.Log;
@@ -30,7 +31,7 @@
  * 
  * JettyWebConfiguration.
  * 
- * Looks for Xmlconfiguration files in WEB-INF.  Searches in order for the first of jettyX-web.xml, jetty-web.xml or web-jetty.xml
+ * Looks for Xmlconfiguration files in WEB-INF.  Searches in order for the first of jetty6-web.xml, jetty-web.xml or web-jetty.xml
  *
  * 
  *
@@ -70,7 +71,7 @@
         if(web_inf!=null&&web_inf.isDirectory())
         {
             // do jetty.xml file
-            Resource jetty=web_inf.addPath("jetty7-web.xml");
+            Resource jetty=web_inf.addPath("jetty8-web.xml");
             if(!jetty.exists())
                 jetty=web_inf.addPath(JETTY_WEB_XML);
             if(!jetty.exists())
@@ -133,6 +134,13 @@
     private void setupXmlConfiguration(XmlConfiguration jetty_config, Resource web_inf)
     {
     	Map<String,String> props = jetty_config.getProperties();
+    	if (props == null)
+    	{
+    		props = new HashMap<String, String>();
+    		jetty_config.setProperties(props);
+    	}
+    	
+    	// TODO - should this be an id rather than a property?
     	props.put(PROPERTY_THIS_WEB_INF_URL, String.valueOf(web_inf.getURL()));
     }
 }
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 e306672..92ca93f 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
@@ -24,6 +24,8 @@
 import java.util.List;
 import java.util.Map;
 
+import javax.servlet.ServletContext;
+
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
@@ -168,6 +170,8 @@
         _webXmlRoot.parse();
         _metaDataComplete=_webXmlRoot.getMetaDataComplete() == MetaDataComplete.True;
         
+        
+        
         if (_webXmlRoot.isOrdered())
         {
             if (_ordering == null)
@@ -197,7 +201,7 @@
                 _metaDataComplete=true;
                 break;
             case False:
-                _metaDataComplete=true;
+                _metaDataComplete=false;
                 break;
             case NotSet:
                 break;
@@ -267,12 +271,42 @@
      */
     public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations)
     {
-        _annotations.addAll(annotations);
+        if (annotations == null)
+            return;
+        for (DiscoveredAnnotation a:annotations)
+        {
+            Resource r = a.getResource();
+            if (r == null || !_webInfJars.contains(r))
+                _annotations.add(a);
+            else 
+                addDiscoveredAnnotation(a.getResource(), a);
+                
+        }
     }
+    
+    
+    public void addDiscoveredAnnotation(Resource resource, DiscoveredAnnotation annotation)
+    {
+        List<DiscoveredAnnotation> list = _webFragmentAnnotations.get(resource);
+        if (list == null)
+        {
+            list = new ArrayList<DiscoveredAnnotation>();
+            _webFragmentAnnotations.put(resource, list);
+        }
+        list.add(annotation);
+    }
+    
 
     public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations)
     {
-        _webFragmentAnnotations.put(resource, new ArrayList<DiscoveredAnnotation>(annotations));
+        List<DiscoveredAnnotation> list = _webFragmentAnnotations.get(resource);
+        if (list == null)
+        {
+            list = new ArrayList<DiscoveredAnnotation>();
+            _webFragmentAnnotations.put(resource, list);
+        }
+            
+        list.addAll(annotations);
     }
     
     public void addDescriptorProcessor(DescriptorProcessor p)
@@ -317,7 +351,14 @@
                 int j = fullname.lastIndexOf("/", i);
                 orderedLibs.add(fullname.substring(j+1,i+4));
             }
-            context.setAttribute(ORDERED_LIBS, orderedLibs);
+            context.setAttribute(ServletContext.ORDERED_LIBS, orderedLibs);
+        }
+
+        // set the webxml version
+        if (_webXmlRoot != null)
+        {
+            context.getServletContext().setEffectiveMajorVersion(_webXmlRoot.getMajorVersion());
+            context.getServletContext().setEffectiveMinorVersion(_webXmlRoot.getMinorVersion());
         }
 
         for (DescriptorProcessor p:_descriptorProcessors)
@@ -497,6 +538,15 @@
         OriginInfo x = new OriginInfo (name, Origin.Annotation);
         _origins.put(name, x);
     }
+    
+    public void setOrigin(String name, Origin origin)
+    {
+        if (name == null)
+            return;
+       
+        OriginInfo x = new OriginInfo (name, origin);
+        _origins.put(name, x);
+    }
 
     public boolean isMetaDataComplete()
     {
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 fb27992..81db172 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
@@ -84,6 +84,17 @@
             scanner.scan(null, uris, true);
         }
     }
+    @Override
+    public void configure(WebAppContext context) throws Exception
+    {
+        
+    }
+
+    @Override
+    public void deconfigure(WebAppContext context) throws Exception
+    {
+ 
+    }
 
     @Override
     public void postConfigure(WebAppContext context) throws Exception
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 7fb7fe9..7586d67 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
@@ -62,6 +62,7 @@
          * Order the list of jars in WEB-INF/lib according to the ordering declarations in the descriptors
          * @see org.eclipse.jetty.webapp.Ordering#order(java.util.List)
          */
+        @Override
         public List<Resource> order(List<Resource> jars)
         {           
             List<Resource> orderedList = new ArrayList<Resource>();
@@ -99,7 +100,7 @@
             return orderedList;
         }
         
-
+        @Override
         public boolean isAbsolute()
         {
             return true;
@@ -119,7 +120,7 @@
             _order.add(OTHER);
         }
         
-  
+        @Override
         public boolean hasOther ()
         {
             return _hasOther;
@@ -146,7 +147,7 @@
          * in the various web-fragment.xml files.
          * @see org.eclipse.jetty.webapp.Ordering#order(java.util.List)
          */
-   
+        @Override
         public List<Resource> order(List<Resource> jars)
         {         
             //for each jar, put it into the ordering according to the fragment ordering
@@ -216,13 +217,13 @@
             return orderedList;
         }
         
-    
+        @Override
         public boolean isAbsolute ()
         {
             return false;
         }
         
-     
+        @Override
         public boolean hasOther ()
         {
             return !_beforeOthers.isEmpty() || !_afterOthers.isEmpty();
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Origin.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Origin.java
index 7043fe7..f54acf0 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Origin.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Origin.java
@@ -18,4 +18,4 @@
 
 package org.eclipse.jetty.webapp;
 
-public enum Origin {NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation}
+public enum Origin {NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation, API}
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 a9b568b..e950233 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
@@ -23,25 +23,38 @@
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.EnumSet;
 import java.util.EventListener;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
+import javax.servlet.DispatcherType;
+import javax.servlet.MultipartConfigElement;
 import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
+import javax.servlet.descriptor.JspPropertyGroupDescriptor;
+import javax.servlet.descriptor.TaglibDescriptor;
 
 import org.eclipse.jetty.security.ConstraintAware;
 import org.eclipse.jetty.security.ConstraintMapping;
 import org.eclipse.jetty.security.authentication.FormAuthenticator;
-import org.eclipse.jetty.server.DispatcherType;
 import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
 import org.eclipse.jetty.servlet.FilterHolder;
 import org.eclipse.jetty.servlet.FilterMapping;
+import org.eclipse.jetty.servlet.Holder;
 import org.eclipse.jetty.servlet.JspPropertyGroupServlet;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig;
+import org.eclipse.jetty.servlet.ServletContextHandler.JspPropertyGroup;
+import org.eclipse.jetty.servlet.ServletContextHandler.TagLib;
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.eclipse.jetty.servlet.ServletMapping;
 import org.eclipse.jetty.util.LazyList;
@@ -196,7 +209,7 @@
          */
         if (holder == null)
         {
-            holder = context.getServletHandler().newServletHolder();
+            holder = context.getServletHandler().newServletHolder(Holder.Source.DESCRIPTOR);
             holder.setName(servlet_name);
             context.getServletHandler().addServlet(holder);
         }
@@ -462,6 +475,136 @@
                 }
             }
         }
+
+        String async=node.getString("async-supported",false,true);
+        if (async!=null)
+        {
+            boolean val = async.length()==0||Boolean.valueOf(async);
+            Origin o =context.getMetaData().getOrigin(servlet_name+".servlet.async-supported");
+            switch (o)
+            {
+                case NotSet:
+                {
+                    //set it
+                    holder.setAsyncSupported(val);
+                    context.getMetaData().setOrigin(servlet_name+".servlet.async-supported", descriptor);
+                    break;
+                }
+                case WebXml:
+                case WebDefaults:
+                case WebOverride:
+                {
+                    //async-supported set by previous web xml descriptor, only allow override if we're parsing another web descriptor(web.xml/web-override.xml/web-default.xml)
+                    if (!(descriptor instanceof FragmentDescriptor))
+                    {
+                        holder.setAsyncSupported(val);
+                        context.getMetaData().setOrigin(servlet_name+".servlet.async-supported", descriptor);  
+                    }             
+                    break;
+                }
+                case WebFragment:
+                {
+                    //async-supported set by another fragment, this fragment's value must match
+                    if (holder.isAsyncSupported() != val)
+                        throw new IllegalStateException("Conflicting async-supported="+async+" for servlet "+servlet_name+" in "+descriptor.getResource());
+                    break;
+                }
+            }
+        }
+
+        String enabled = node.getString("enabled", false, true);
+        if (enabled!=null)
+        {
+            boolean is_enabled = enabled.length()==0||Boolean.valueOf(enabled);     
+            Origin o = context.getMetaData().getOrigin(servlet_name+".servlet.enabled");
+            switch (o)
+            {
+                case NotSet:
+                {
+                    //hasn't been set yet, so set it                
+                    holder.setEnabled(is_enabled);
+                    context.getMetaData().setOrigin(servlet_name+".servlet.enabled", descriptor);
+                    break;
+                }
+                case WebXml:
+                case WebDefaults:
+                case WebOverride:
+                {
+                    //was set in a web xml descriptor, only allow override from another web xml descriptor
+                    if (!(descriptor instanceof FragmentDescriptor))
+                    {
+                        holder.setEnabled(is_enabled);   
+                        context.getMetaData().setOrigin(servlet_name+".servlet.enabled", descriptor);
+                    }
+                    break;
+                }
+                case WebFragment:
+                {
+                    //was set by another fragment, this fragment's value must match
+                    if (holder.isEnabled() != is_enabled)
+                        throw new IllegalStateException("Conflicting value of servlet enabled for servlet "+servlet_name+" in "+descriptor.getResource());
+                    break;
+                }
+            }
+        }
+        
+        /*
+         * If multipart config not set, then set it and record it was by the web.xml or fragment.
+         * If it was set by web.xml then if this is a fragment, ignore the settings.
+         * If it was set by a fragment, if this is a fragment and the values are different, error!
+         */
+        XmlParser.Node multipart = node.get("multipart-config");
+        if (multipart != null)
+        {
+            String location = multipart.getString("location", false, true);
+            String maxFile = multipart.getString("max-file-size", false, true);
+            String maxRequest = multipart.getString("max-request-size", false, true);
+            String threshold = multipart.getString("file-size-threshold",false,true);
+            MultipartConfigElement element = new MultipartConfigElement(location,
+                                                                        (maxFile==null||"".equals(maxFile)?-1L:Long.parseLong(maxFile)),
+                                                                        (maxRequest==null||"".equals(maxRequest)?-1L:Long.parseLong(maxRequest)),
+                                                                        (threshold==null||"".equals(threshold)?0:Integer.parseInt(threshold)));
+            
+            Origin o = context.getMetaData().getOrigin(servlet_name+".servlet.multipart-config");
+            switch (o)
+            {
+                case NotSet:
+                {
+                    //hasn't been set, so set it
+                    holder.getRegistration().setMultipartConfig(element);
+                    context.getMetaData().setOrigin(servlet_name+".servlet.multipart-config", descriptor);
+                    break;
+                }
+                case WebXml:
+                case WebDefaults:
+                case WebOverride:
+                {
+                    //was set in a web xml, only allow changes if we're parsing another web xml (web.xml/web-default.xml/web-override.xml)
+                    if (!(descriptor instanceof FragmentDescriptor))
+                    {
+                        holder.getRegistration().setMultipartConfig(element);
+                        context.getMetaData().setOrigin(servlet_name+".servlet.multipart-config", descriptor);  
+                    }
+                    break;
+                }
+                case WebFragment:
+                {
+                    //another fragment set the value, this fragment's values must match exactly or it is an error
+                    MultipartConfigElement cfg = ((ServletHolder.Registration)holder.getRegistration()).getMultipartConfig();
+                    
+                    if (cfg.getMaxFileSize() != element.getMaxFileSize())
+                        throw new IllegalStateException("Conflicting multipart-config max-file-size for servlet "+servlet_name+" in "+descriptor.getResource());
+                    if (cfg.getMaxRequestSize() != element.getMaxRequestSize())
+                        throw new IllegalStateException("Conflicting multipart-config max-request-size for servlet "+servlet_name+" in "+descriptor.getResource());
+                    if (cfg.getFileSizeThreshold() != element.getFileSizeThreshold())
+                        throw new IllegalStateException("Conflicting multipart-config file-size-threshold for servlet "+servlet_name+" in "+descriptor.getResource());
+                    if ((cfg.getLocation() != null && (element.getLocation() == null || element.getLocation().length()==0))
+                            || (cfg.getLocation() == null && (element.getLocation()!=null || element.getLocation().length() > 0)))
+                        throw new IllegalStateException("Conflicting multipart-config location for servlet "+servlet_name+" in "+descriptor.getResource());
+                    break;
+                }
+            } 
+        }
     }
     
     
@@ -488,7 +631,8 @@
             {
                 //no servlet mappings
                 context.getMetaData().setOrigin(servlet_name+".servlet.mappings", descriptor);
-                addServletMapping(servlet_name, node, context);
+                ServletMapping mapping = addServletMapping(servlet_name, node, context, descriptor);
+                mapping.setDefault(context.getMetaData().getOrigin(servlet_name+".servlet.mappings") == Origin.WebDefaults);
                 break;
             }
             case WebXml:
@@ -499,14 +643,14 @@
                 //otherwise just ignore it
                 if (!(descriptor instanceof FragmentDescriptor))
                 {
-                   addServletMapping(servlet_name, node, context);
+                   addServletMapping(servlet_name, node, context, descriptor);
                 }
                 break;
             }
             case WebFragment:
             {
                 //mappings previously set by another web-fragment, so merge in this web-fragment's mappings
-                addServletMapping(servlet_name, node, context);
+                addServletMapping(servlet_name, node, context, descriptor);
                 break;
             }
         }        
@@ -526,6 +670,309 @@
             int timeout = Integer.parseInt(tNode.toString(false, true));
             context.getSessionHandler().getSessionManager().setMaxInactiveInterval(timeout * 60);
         }
+        
+        //Servlet Spec 3.0 
+        // <tracking-mode>
+        // this is additive across web-fragments
+        Iterator iter = node.iterator("tracking-mode");
+        if (iter.hasNext())
+        { 
+            Set<SessionTrackingMode> modes = null;
+            Origin o = context.getMetaData().getOrigin("session.tracking-mode");
+            switch (o)
+            {
+                case NotSet://not previously set, starting fresh
+                case WebDefaults://previously set in web defaults, allow this descriptor to start fresh
+                {
+                    
+                    modes = new HashSet<SessionTrackingMode>();
+                    context.getMetaData().setOrigin("session.tracking-mode", descriptor);
+                    break;
+                }
+                case WebXml:
+                case WebFragment:
+                case WebOverride:
+                {
+                    //if setting from an override descriptor, start afresh, otherwise add-in tracking-modes
+                    if (descriptor instanceof OverrideDescriptor)
+                        modes = new HashSet<SessionTrackingMode>();
+                    else
+                        modes = new HashSet<SessionTrackingMode>(context.getSessionHandler().getSessionManager().getEffectiveSessionTrackingModes());
+                    context.getMetaData().setOrigin("session.tracking-mode", descriptor);
+                    break;
+                }       
+            }
+            
+            while (iter.hasNext())
+            {
+                XmlParser.Node mNode = (XmlParser.Node) iter.next();
+                String trackMode = mNode.toString(false, true);
+                modes.add(SessionTrackingMode.valueOf(trackMode));
+            }
+            context.getSessionHandler().getSessionManager().setSessionTrackingModes(modes);   
+        }
+       
+        
+        //Servlet Spec 3.0 
+        //<cookie-config>
+        XmlParser.Node cookieConfig = node.get("cookie-config");
+        if (cookieConfig != null)
+        {
+            //  <name>
+            String name = cookieConfig.getString("name", false, true);
+            if (name != null)
+            {
+                Origin o = context.getMetaData().getOrigin("cookie-config.name");
+                switch (o)
+                {
+                    case NotSet:
+                    {
+                        //no <cookie-config><name> set yet, accept it
+                        context.getSessionHandler().getSessionManager().getSessionCookieConfig().setName(name);
+                        context.getMetaData().setOrigin("cookie-config.name", descriptor);
+                        break;
+                    }
+                    case WebXml:
+                    case WebDefaults:
+                    case WebOverride:
+                    {
+                        //<cookie-config><name> set in a web xml, only allow web-default/web-override to change
+                        if (!(descriptor instanceof FragmentDescriptor))
+                        {
+                            context.getSessionHandler().getSessionManager().getSessionCookieConfig().setName(name);
+                            context.getMetaData().setOrigin("cookie-config.name", descriptor);
+                        }
+                        break;
+                    }
+                    case WebFragment:
+                    {
+                        //a web-fragment set the value, all web-fragments must have the same value
+                        if (!context.getSessionHandler().getSessionManager().getSessionCookieConfig().getName().equals(name))                  
+                            throw new IllegalStateException("Conflicting cookie-config name "+name+" in "+descriptor.getResource());
+                        break;
+                    }
+                }
+            }
+            
+            //  <domain>
+            String domain = cookieConfig.getString("domain", false, true);
+            if (domain != null)
+            {
+                Origin o = context.getMetaData().getOrigin("cookie-config.domain");
+                switch (o)
+                {
+                    case NotSet:
+                    {
+                        //no <cookie-config><domain> set yet, accept it
+                        context.getSessionHandler().getSessionManager().getSessionCookieConfig().setDomain(domain);
+                        context.getMetaData().setOrigin("cookie-config.domain", descriptor);
+                        break;
+                    }
+                    case WebXml:
+                    case WebDefaults:
+                    case WebOverride:
+                    {
+                        //<cookie-config><domain> set in a web xml, only allow web-default/web-override to change
+                        if (!(descriptor instanceof FragmentDescriptor))
+                        {
+                            context.getSessionHandler().getSessionManager().getSessionCookieConfig().setDomain(domain);
+                            context.getMetaData().setOrigin("cookie-config.domain", descriptor);
+                        }
+                        break;
+                    }
+                    case WebFragment:
+                    {
+                        //a web-fragment set the value, all web-fragments must have the same value
+                        if (!context.getSessionHandler().getSessionManager().getSessionCookieConfig().getDomain().equals(domain))                  
+                            throw new IllegalStateException("Conflicting cookie-config domain "+domain+" in "+descriptor.getResource());
+                        break;
+                    }
+                }
+            }
+            
+            //  <path>
+            String path = cookieConfig.getString("path", false, true);
+            if (path != null)
+            {
+                Origin o = context.getMetaData().getOrigin("cookie-config.path");
+                switch (o)
+                {
+                    case NotSet:
+                    {
+                        //no <cookie-config><domain> set yet, accept it
+                        context.getSessionHandler().getSessionManager().getSessionCookieConfig().setPath(path);
+                        context.getMetaData().setOrigin("cookie-config.path", descriptor);
+                        break;
+                    }
+                    case WebXml:
+                    case WebDefaults:
+                    case WebOverride:
+                    {
+                        //<cookie-config><domain> set in a web xml, only allow web-default/web-override to change
+                        if (!(descriptor instanceof FragmentDescriptor))
+                        {
+                            context.getSessionHandler().getSessionManager().getSessionCookieConfig().setPath(path);
+                            context.getMetaData().setOrigin("cookie-config.path", descriptor);
+                        }
+                        break;
+                    }
+                    case WebFragment:
+                    {
+                        //a web-fragment set the value, all web-fragments must have the same value
+                        if (!context.getSessionHandler().getSessionManager().getSessionCookieConfig().getPath().equals(path))                  
+                            throw new IllegalStateException("Conflicting cookie-config path "+path+" in "+descriptor.getResource());
+                        break;
+                    }
+                }
+            }
+            
+            //  <comment>
+            String comment = cookieConfig.getString("comment", false, true);
+            if (comment != null)
+            {
+                Origin o = context.getMetaData().getOrigin("cookie-config.comment");
+                switch (o)
+                {
+                    case NotSet:
+                    {
+                        //no <cookie-config><comment> set yet, accept it
+                        context.getSessionHandler().getSessionManager().getSessionCookieConfig().setComment(comment);
+                        context.getMetaData().setOrigin("cookie-config.comment", descriptor);
+                        break;
+                    }
+                    case WebXml:
+                    case WebDefaults:
+                    case WebOverride:
+                    {
+                        //<cookie-config><comment> set in a web xml, only allow web-default/web-override to change
+                        if (!(descriptor instanceof FragmentDescriptor))
+                        {
+                            context.getSessionHandler().getSessionManager().getSessionCookieConfig().setComment(comment);
+                            context.getMetaData().setOrigin("cookie-config.comment", descriptor);
+                        }
+                        break;
+                    }
+                    case WebFragment:
+                    {
+                        //a web-fragment set the value, all web-fragments must have the same value
+                        if (!context.getSessionHandler().getSessionManager().getSessionCookieConfig().getComment().equals(comment))                  
+                            throw new IllegalStateException("Conflicting cookie-config comment "+comment+" in "+descriptor.getResource());
+                        break;
+                    }
+                }
+            }
+            
+            //  <http-only>true/false
+            tNode = cookieConfig.get("http-only");
+            if (tNode != null)
+            {
+                boolean httpOnly = Boolean.parseBoolean(tNode.toString(false,true));           
+                Origin o = context.getMetaData().getOrigin("cookie-config.http-only");
+                switch (o)
+                {
+                    case NotSet:
+                    {
+                        //no <cookie-config><http-only> set yet, accept it
+                        context.getSessionHandler().getSessionManager().getSessionCookieConfig().setHttpOnly(httpOnly);
+                        context.getMetaData().setOrigin("cookie-config.http-only", descriptor);
+                        break;
+                    }
+                    case WebXml:
+                    case WebDefaults:
+                    case WebOverride:
+                    {
+                        //<cookie-config><http-only> set in a web xml, only allow web-default/web-override to change
+                        if (!(descriptor instanceof FragmentDescriptor))
+                        {
+                            context.getSessionHandler().getSessionManager().getSessionCookieConfig().setHttpOnly(httpOnly);
+                            context.getMetaData().setOrigin("cookie-config.http-only", descriptor);
+                        }
+                        break;
+                    }
+                    case WebFragment:
+                    {
+                        //a web-fragment set the value, all web-fragments must have the same value
+                        if (context.getSessionHandler().getSessionManager().getSessionCookieConfig().isHttpOnly() != httpOnly)       
+                            throw new IllegalStateException("Conflicting cookie-config http-only "+httpOnly+" in "+descriptor.getResource());
+                        break;
+                    }
+                }
+            }
+            
+            //  <secure>true/false
+            tNode = cookieConfig.get("secure");
+            if (tNode != null)
+            {
+                boolean secure = Boolean.parseBoolean(tNode.toString(false,true));
+                Origin o = context.getMetaData().getOrigin("cookie-config.secure");
+                switch (o)
+                {
+                    case NotSet:
+                    {
+                        //no <cookie-config><secure> set yet, accept it
+                        context.getSessionHandler().getSessionManager().getSessionCookieConfig().setSecure(secure);
+                        context.getMetaData().setOrigin("cookie-config.secure", descriptor);
+                        break;
+                    }                   
+                    case WebXml:
+                    case WebDefaults:
+                    case WebOverride:
+                    {
+                        //<cookie-config><secure> set in a web xml, only allow web-default/web-override to change
+                        if (!(descriptor instanceof FragmentDescriptor))
+                        {
+                            context.getSessionHandler().getSessionManager().getSessionCookieConfig().setSecure(secure);
+                            context.getMetaData().setOrigin("cookie-config.secure", descriptor);
+                        }
+                        break;
+                    }
+                    case WebFragment:
+                    {
+                        //a web-fragment set the value, all web-fragments must have the same value
+                        if (context.getSessionHandler().getSessionManager().getSessionCookieConfig().isSecure() != secure)       
+                            throw new IllegalStateException("Conflicting cookie-config secure "+secure+" in "+descriptor.getResource());
+                        break;
+                    }
+                }
+            }
+            
+            //  <max-age>
+            tNode = cookieConfig.get("max-age");
+            if (tNode != null)
+            {
+                int maxAge = Integer.parseInt(tNode.toString(false,true));
+                Origin o = context.getMetaData().getOrigin("cookie-config.max-age");
+                switch (o)
+                {
+                    case NotSet:
+                    { 
+                        //no <cookie-config><max-age> set yet, accept it
+                        context.getSessionHandler().getSessionManager().getSessionCookieConfig().setMaxAge(maxAge);
+                        context.getMetaData().setOrigin("cookie-config.max-age", descriptor);
+                        break;
+                    }
+                    case WebXml:
+                    case WebDefaults:
+                    case WebOverride:
+                    {   
+                        //<cookie-config><max-age> set in a web xml, only allow web-default/web-override to change
+                        if (!(descriptor instanceof FragmentDescriptor))
+                        {
+                            context.getSessionHandler().getSessionManager().getSessionCookieConfig().setMaxAge(maxAge);
+                            context.getMetaData().setOrigin("cookie-config.max-age", descriptor);
+                        }
+                        break;
+                    }
+                    case WebFragment:
+                    {
+                        //a web-fragment set the value, all web-fragments must have the same value
+                        if (context.getSessionHandler().getSessionManager().getSessionCookieConfig().getMaxAge() != maxAge)
+                            throw new IllegalStateException("Conflicting cookie-config max-age "+maxAge+" in "+descriptor.getResource());
+                        break;
+                    }
+                }
+            }
+        }
     }
     
     
@@ -666,7 +1113,7 @@
                     {
                         //a value was set by a web-fragment, all fragments must have the same value
                         if (!encoding.equals(context.getLocaleEncoding(locale)))
-                            throw new IllegalStateException("Conflicting locale-encoding mapping for locale "+locale+" in "+descriptor.getResource());
+                            throw new IllegalStateException("Conflicting loacle-encoding mapping for locale "+locale+" in "+descriptor.getResource());
                         break;                    
                     }
                 }
@@ -763,7 +1210,7 @@
      * @param node
      * @param context
      */
-    protected void addServletMapping (String servletName, XmlParser.Node node, WebAppContext context)
+    protected ServletMapping addServletMapping (String servletName, XmlParser.Node node, WebAppContext context, Descriptor descriptor)
     {
         ServletMapping mapping = new ServletMapping();
         mapping.setServletName(servletName);
@@ -775,9 +1222,11 @@
             String p = iter.next().toString(false, true);
             p = normalizePattern(p);
             paths.add(p);
+            context.getMetaData().setOrigin(servletName+".servlet.mapping."+p, descriptor);
         }
         mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
         context.getServletHandler().addServletMapping(mapping);
+        return mapping;
     }
     
     /**
@@ -785,7 +1234,7 @@
      * @param node
      * @param context
      */
-    protected void addFilterMapping (String filterName, XmlParser.Node node, WebAppContext context)
+    protected void addFilterMapping (String filterName, XmlParser.Node node, WebAppContext context, Descriptor descriptor)
     {
         FilterMapping mapping = new FilterMapping();
         mapping.setFilterName(filterName);
@@ -797,6 +1246,7 @@
             String p = iter.next().toString(false, true);
             p = normalizePattern(p);
             paths.add(p);
+            context.getMetaData().setOrigin(filterName+".filter.mapping."+p, descriptor);
         }
         mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
 
@@ -837,6 +1287,18 @@
         String location = node.getString("taglib-location", false, true);
 
         context.setResourceAlias(uri, location);
+        
+        JspConfig config = (JspConfig)context.getServletContext().getJspConfigDescriptor();
+        if (config == null)
+        {
+            config = new JspConfig();
+            context.getServletContext().setJspConfigDescriptor(config);
+        }
+        
+        TagLib tl = new TagLib();
+        tl.setTaglibLocation(location);
+        tl.setTaglibURI(uri);
+        config.addTaglibDescriptor(tl);
     }
     
     /**
@@ -845,7 +1307,16 @@
      * @param node
      */
     protected void visitJspConfig(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
-    {  
+    {   
+        //Additive across web.xml and web-fragment.xml
+        JspConfig config = (JspConfig)context.getServletContext().getJspConfigDescriptor();
+        if (config == null)
+        {
+           config = new JspConfig();
+           context.getServletContext().setJspConfigDescriptor(config);
+        }
+        
+        
         for (int i = 0; i < node.size(); i++)
         {
             Object o = node.get(i);
@@ -854,19 +1325,51 @@
         }
 
         // Map URLs from jsp property groups to JSP servlet.
-        // this is more JSP stupidness creaping into the servlet spec
+        // this is more JSP stupidness creeping into the servlet spec
         Iterator<XmlParser.Node> iter = node.iterator("jsp-property-group");
         List<String> paths = new ArrayList<String>();
         while (iter.hasNext())
         {
+            JspPropertyGroup jpg = new JspPropertyGroup();
+            config.addJspPropertyGroup(jpg);
             XmlParser.Node group = iter.next();
+            
+            //url-patterns
             Iterator<XmlParser.Node> iter2 = group.iterator("url-pattern");
             while (iter2.hasNext())
             {
                 String url = iter2.next().toString(false, true);
                 url = normalizePattern(url);
                 paths.add( url);
+                jpg.addUrlPattern(url);
             }
+            
+            jpg.setElIgnored(group.getString("el-ignored", false, true));
+            jpg.setPageEncoding(group.getString("page-encoding", false, true));
+            jpg.setScriptingInvalid(group.getString("scripting-invalid", false, true));
+            jpg.setIsXml(group.getString("is-xml", false, true));
+            jpg.setDeferredSyntaxAllowedAsLiteral(group.getString("deferred-syntax-allowed-as-literal", false, true));
+            jpg.setTrimDirectiveWhitespaces(group.getString("trim-directive-whitespaces", false, true));
+            jpg.setDefaultContentType(group.getString("default-content-type", false, true));
+            jpg.setBuffer(group.getString("buffer", false, true));
+            jpg.setErrorOnUndeclaredNamespace(group.getString("error-on-undeclared-namespace", false, true));
+            
+            //preludes
+            Iterator<XmlParser.Node> preludes = group.iterator("include-prelude");
+            while (preludes.hasNext())
+            {
+                String prelude = preludes.next().toString(false, true);
+                jpg.addIncludePrelude(prelude);
+            }
+            //codas
+            Iterator<XmlParser.Node> codas = group.iterator("include-coda");
+            while (codas.hasNext())
+            {
+                String coda = codas.next().toString(false, true);
+                jpg.addIncludeCoda(coda);
+            }
+            
+            if (LOG.isDebugEnabled()) LOG.debug(config.toString());
         }
 
         if (paths.size() > 0)
@@ -897,6 +1400,8 @@
 
         //ServletSpec 3.0, p74 security-constraints, as minOccurs > 1, are additive 
         //across fragments
+        
+        //TODO: need to remember origin of the constraints
         try
         {
             XmlParser.Node auths = node.get("auth-constraint");
@@ -945,29 +1450,50 @@
                 {
                     String url = iter2.next().toString(false, true);
                     url = normalizePattern(url);
-
+                    //remember origin so we can process ServletRegistration.Dynamic.setServletSecurityElement() correctly
+                    context.getMetaData().setOrigin("constraint.url."+url, descriptor);
+                    
                     Iterator<XmlParser.Node> iter3 = collection.iterator("http-method");
+                    Iterator<XmlParser.Node> iter4 = collection.iterator("http-method-omission");
+                   
                     if (iter3.hasNext())
                     {
+                        if (iter4.hasNext())
+                            throw new IllegalStateException ("web-resource-collection cannot contain both http-method and http-method-omission");
+                        
+                        //configure all the http-method elements for each url
                         while (iter3.hasNext())
                         {
                             String method = ((XmlParser.Node) iter3.next()).toString(false, true);
                             ConstraintMapping mapping = new ConstraintMapping();
                             mapping.setMethod(method);
                             mapping.setPathSpec(url);
+                            mapping.setConstraint(sc);                                                      
+                            ((ConstraintAware)context.getSecurityHandler()).addConstraintMapping(mapping);
+                        }
+                    }
+                    else if (iter4.hasNext())
+                    {
+                        //configure all the http-method-omission elements for each url
+                        while (iter4.hasNext())
+                        {
+                            String method = ((XmlParser.Node)iter4.next()).toString(false, true);
+                            ConstraintMapping mapping = new ConstraintMapping();
+                            mapping.setMethodOmissions(new String[]{method});
+                            mapping.setPathSpec(url);
                             mapping.setConstraint(sc);
-                                                        
                             ((ConstraintAware)context.getSecurityHandler()).addConstraintMapping(mapping);
                         }
                     }
                     else
                     {
+                        //No http-methods or http-method-omissions specified, the constraint applies to all
                         ConstraintMapping mapping = new ConstraintMapping();
                         mapping.setPathSpec(url);
                         mapping.setConstraint(sc);
                         ((ConstraintAware)context.getSecurityHandler()).addConstraintMapping(mapping);
                     }
-                }
+                } 
             }
         }
         catch (CloneNotSupportedException e)
@@ -1167,7 +1693,7 @@
         FilterHolder holder = context.getServletHandler().getFilter(name);
         if (holder == null)
         {
-            holder = context.getServletHandler().newFilterHolder();
+            holder = context.getServletHandler().newFilterHolder(Holder.Source.DESCRIPTOR);
             holder.setName(name);
             context.getServletHandler().addFilter(holder);
         }
@@ -1313,7 +1839,7 @@
             {
                 //no filtermappings for this filter yet defined
                 context.getMetaData().setOrigin(filter_name+".filter.mappings", descriptor);
-                addFilterMapping(filter_name, node, context);
+                addFilterMapping(filter_name, node, context, descriptor);
                 break;
             }
             case WebDefaults:
@@ -1323,14 +1849,14 @@
                 //filter mappings defined in a web xml file. If we're processing a fragment, we ignore filter mappings.
                 if (!(descriptor instanceof FragmentDescriptor))
                 {
-                   addFilterMapping(filter_name, node, context);
+                   addFilterMapping(filter_name, node, context, descriptor);
                 }
                 break;
             }
             case WebFragment:
             {
                 //filter mappings first defined in a web-fragment, allow other fragments to add
-                addFilterMapping(filter_name, node, context);
+                addFilterMapping(filter_name, node, context, descriptor);
                 break;
             }
         }
@@ -1408,7 +1934,7 @@
     {
         try
         {
-            return ((ServletContextHandler.Context)context.getServletContext()).createListener(clazz);
+            return context.getServletContext().createListener(clazz);
         }
         catch (ServletException se)
         {
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 035c71d..8c4880c 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
@@ -446,5 +446,4 @@
     {
         return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode());
     }
-
 }
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
index fcbe611..b078424 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
@@ -25,18 +25,29 @@
 import java.security.PermissionCollection;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.EventListener;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import javax.servlet.HttpMethodConstraintElement;
 import javax.servlet.ServletContext;
+import javax.servlet.ServletRegistration.Dynamic;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
+import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
 import javax.servlet.http.HttpSessionActivationListener;
 import javax.servlet.http.HttpSessionAttributeListener;
 import javax.servlet.http.HttpSessionBindingListener;
 import javax.servlet.http.HttpSessionListener;
 
+import org.eclipse.jetty.security.ConstraintAware;
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.security.SecurityHandler;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HandlerContainer;
@@ -56,6 +67,7 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.resource.ResourceCollection;
+import org.eclipse.jetty.util.security.Constraint;
 
 /* ------------------------------------------------------------ */
 /** Web Application Context Handler.
@@ -90,8 +102,8 @@
         "org.eclipse.jetty.webapp.WebXmlConfiguration",
         "org.eclipse.jetty.webapp.MetaInfConfiguration",
         "org.eclipse.jetty.webapp.FragmentConfiguration",
-        "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
-        "org.eclipse.jetty.webapp.TagLibConfiguration"
+        "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"//,
+        //"org.eclipse.jetty.webapp.TagLibConfiguration"
     } ;
 
     // System classes are classes that cannot be replaced by
@@ -979,16 +991,6 @@
         }
     }
 
-    /* ------------------------------------------------------------ */
-    /** Add EventListener
-     * Conveniance method that calls {@link #setEventListeners(EventListener[])}
-     * @param listener
-     */
-    @Override
-    public void addEventListener(EventListener listener)
-    {
-        setEventListeners(LazyList.addToArray(getEventListeners(), listener, EventListener.class));
-    }
 
 
     /* ------------------------------------------------------------ */
@@ -1239,6 +1241,79 @@
 
         super.startContext();
     }
+       
+    /* ------------------------------------------------------------ */    
+    @Override
+    public Set<String> setServletSecurity(Dynamic registration, ServletSecurityElement servletSecurityElement)
+    {
+     
+        Set<String> unchangedURLMappings = new HashSet<String>();
+        //From javadoc for ServletSecurityElement:
+        /*
+        If a URL pattern of this ServletRegistration is an exact target of a security-constraint that 
+        was established via the portable deployment descriptor, then this method does not change the 
+        security-constraint for that pattern, and the pattern will be included in the return value.
+
+        If a URL pattern of this ServletRegistration is an exact target of a security constraint 
+        that was established via the ServletSecurity annotation or a previous call to this method, 
+        then this method replaces the security constraint for that pattern.
+
+        If a URL pattern of this ServletRegistration is neither the exact target of a security constraint 
+        that was established via the ServletSecurity annotation or a previous call to this method, 
+        nor the exact target of a security-constraint in the portable deployment descriptor, then 
+        this method establishes the security constraint for that pattern from the argument ServletSecurityElement. 
+         */
+
+        Collection<String> pathMappings = registration.getMappings();
+        if (pathMappings != null)
+        {
+            Constraint constraint = ConstraintSecurityHandler.createConstraint(registration.getName(), servletSecurityElement);
+
+            for (String pathSpec:pathMappings)
+            {
+                Origin origin = getMetaData().getOrigin("constraint.url."+pathSpec);
+               
+                switch (origin)
+                {
+                    case NotSet:
+                    {
+                        //No mapping for this url already established
+                        List<ConstraintMapping> mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
+                        for (ConstraintMapping m:mappings)
+                            ((ConstraintAware)getSecurityHandler()).addConstraintMapping(m);
+                        getMetaData().setOrigin("constraint.url."+pathSpec, Origin.API);
+                        break;
+                    }
+                    case WebXml:
+                    case WebDefaults:
+                    case WebOverride:
+                    case WebFragment:
+                    {
+                        //a mapping for this url was created in a descriptor, which overrides everything
+                        unchangedURLMappings.add(pathSpec);
+                        break;
+                    }
+                    case Annotation:
+                    case API:
+                    {
+                        //mapping established via an annotation or by previous call to this method,
+                        //replace the security constraint for this pattern
+                        List<ConstraintMapping> constraintMappings = ConstraintSecurityHandler.removeConstraintMappingsForPath(pathSpec, ((ConstraintAware)getSecurityHandler()).getConstraintMappings());
+                       
+                        List<ConstraintMapping> freshMappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
+                        constraintMappings.addAll(freshMappings);
+                           
+                        ((ConstraintSecurityHandler)getSecurityHandler()).setConstraintMappings(constraintMappings);
+                        break;
+                    }
+                }
+            }
+        }
+        
+        return unchangedURLMappings;
+    }
+
+
 
     /* ------------------------------------------------------------ */
     public class Context extends ServletContextHandler.Context
@@ -1289,6 +1364,8 @@
             }
         }
 
+        
+        
     }
 
     /* ------------------------------------------------------------ */
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java
index 5b8ddd3..6b9ab15 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java
@@ -59,6 +59,8 @@
         if (webxml != null) 
         {      
             context.getMetaData().setWebXml(webxml);
+            context.getServletContext().setEffectiveMajorVersion(context.getMetaData().getWebXml().getMajorVersion());
+            context.getServletContext().setEffectiveMinorVersion(context.getMetaData().getWebXml().getMinorVersion());
         }
         
         //parse but don't process override-web.xml
@@ -119,16 +121,8 @@
     @Override
     public void deconfigure (WebAppContext context) throws Exception
     {
-        // TODO preserve any configuration that pre-existed.
-
         ServletHandler _servletHandler = context.getServletHandler();
        
-        _servletHandler.setFilters(null);
-        _servletHandler.setFilterMappings(null);
-        _servletHandler.setServlets(null);
-        _servletHandler.setServletMappings(null);
-
-        context.setEventListeners(null);
         context.setWelcomeFiles(null);
 
         if (context.getErrorHandler() instanceof ErrorPageErrorHandler)
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 bd82287..e926a53 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
@@ -853,6 +853,44 @@
     }
     
     @Test
+    public void testRelativeOrderingWithPlainJars2 ()
+    throws Exception
+    {
+        //web.xml has no ordering, jar A has fragment after others, jar B is plain, jar C is plain
+        List<Resource> resources = new ArrayList<Resource>();
+        WebAppContext wac = new WebAppContext();
+        MetaData metaData = new MetaData();
+        metaData._ordering = new RelativeOrdering(metaData);
+        
+        //A has after others
+        TestResource jar1 = new TestResource("A");
+        resources.add(jar1);
+        TestResource r1 = new TestResource("A/web-fragment.xml");
+        FragmentDescriptor f1 = new FragmentDescriptor(r1);
+        f1._name = "A";
+        metaData._webFragmentNameMap.put(f1._name, f1);
+        metaData._webFragmentResourceMap.put(jar1, f1);
+        f1._otherType = FragmentDescriptor.OtherType.After;
+        
+        //No fragment jar B
+        TestResource r4 = new TestResource("plainB");
+        resources.add(r4);
+        
+        //No fragment jar C
+        TestResource r5 = new TestResource("plainC");
+        resources.add(r5);
+        
+        List<Resource> orderedList = metaData._ordering.order(resources);
+        String[] outcomes = {"plainBplainCA"};
+        String result = "";
+        for (Resource r:orderedList)
+           result+=(((TestResource)r)._name);
+        
+        if (!checkResult(result, outcomes))
+            fail ("No outcome matched "+result);
+    }
+    
+    @Test
     public void testAbsoluteOrderingWithPlainJars()
     throws Exception
     {
diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml
index ff70d3b..8762297 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>7.6.19-SNAPSHOT</version>
+        <version>8.1.19-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
@@ -65,6 +65,11 @@
                         <goals>
                             <goal>manifest</goal>
                         </goals>
+                        <configuration>
+                            <instructions>
+                                <Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
+                            </instructions>
+                        </configuration>
                     </execution>
                 </executions>
             </plugin>
@@ -100,5 +105,4 @@
             </plugin>
         </plugins>
     </build>
-
 </project>
diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClient.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClient.java
index 497eaea..dea8fe0 100644
--- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClient.java
+++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClient.java
@@ -36,6 +36,7 @@
 import java.util.concurrent.TimeoutException;
 
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
 
@@ -336,6 +337,8 @@
     {
         if (!_factory.isStarted())
             throw new IllegalStateException("Factory !started");
+        
+        __log.debug("Connecting to: {}", uri);
 
         InetSocketAddress address = toSocketAddress(uri);
 
diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClientFactory.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClientFactory.java
index 35ee2ca..4dd8f6f 100644
--- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClientFactory.java
+++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClientFactory.java
@@ -423,9 +423,31 @@
 
                 StringBuilder request = new StringBuilder(512);
                 request.append("GET ").append(path).append(" HTTP/1.1\r\n")
-                .append("Host: ").append(_future.getURI().getHost()).append(":")
-                .append(_future.getURI().getPort()).append("\r\n")
-                .append("Upgrade: websocket\r\n")
+                .append("Host: ").append(_future.getURI().getHost()).append(":");
+                
+                int port = _future.getURI().getPort();
+                if (port <= 0)
+                {
+                    // fix it
+                    String scheme = _future.getURI().getScheme();
+
+                    if ("ws".equalsIgnoreCase(scheme))
+                    {
+                        port = 80;
+                    }
+                    else if ("wss".equalsIgnoreCase(scheme))
+                    {
+                        port = 443;
+                    }
+                    else
+                    {
+                        throw new RuntimeException("No valid port provided for scheme [" + scheme + "]");
+                    }
+                }
+
+                request.append(port).append("\r\n");
+                
+                request.append("Upgrade: websocket\r\n")
                 .append("Connection: Upgrade\r\n")
                 .append("Sec-WebSocket-Key: ")
                 .append(_key).append("\r\n");
diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserD06Test.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserD06Test.java
index 84290e5..02fc306 100644
--- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserD06Test.java
+++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserD06Test.java
@@ -29,6 +29,7 @@
 import org.eclipse.jetty.io.ByteArrayBuffer;
 import org.eclipse.jetty.io.ByteArrayEndPoint;
 import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.util.Utf8StringBuilder;
 import org.junit.Before;
 import org.junit.Test;
@@ -130,7 +131,7 @@
         _in.put((byte)0x84);
         _in.put((byte)11);
         _in.put("Hello World".getBytes(StringUtil.__UTF8));
-        // System.err.println("tosend="+TypeUtil.toHexString(_in.asArray()));
+        System.err.println("tosend="+TypeUtil.toHexString(_in.asArray()));
 
         int filled =_parser.parseNext();
 
diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/examples/EchoClientSocketExample.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/examples/EchoClientSocketExample.java
new file mode 100644
index 0000000..2bb4af0
--- /dev/null
+++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/examples/EchoClientSocketExample.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.websocket.examples;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+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.websocket.WebSocket;
+import org.eclipse.jetty.websocket.WebSocketClient;
+import org.eclipse.jetty.websocket.WebSocketClientFactory;
+
+public class EchoClientSocketExample
+{
+    /**
+     * A simple echo socket, on connect it sends a text message, then when it receives the message it tracks it and then closes the connection.
+     * <p>
+     * There are some fundamental latches provided that a WebSocketClient can use to wait till a socket is connected or even disconnected.
+     */
+    public static class EchoClientSocket implements WebSocket, WebSocket.OnTextMessage
+    {
+        private static final Logger LOG = Log.getLogger(EchoClientSocket.class);
+
+        public CountDownLatch connectLatch = new CountDownLatch(1);
+        public CountDownLatch disconnectLatch = new CountDownLatch(1);
+
+        public List<String> textMessages = new ArrayList<String>();
+        public List<Throwable> errors = new ArrayList<Throwable>();
+        private Connection connection;
+
+        @Override
+        public void onClose(int closeCode, String message)
+        {
+            LOG.info("Closed {} : {}",closeCode,message);
+            disconnectLatch.countDown();
+        }
+
+        @Override
+        public void onMessage(String message)
+        {
+            LOG.info("on Text : {}",message);
+            textMessages.add(message);
+            connection.close();
+        }
+
+        @Override
+        public void onOpen(Connection connection)
+        {
+            this.connection = connection;
+            LOG.info("Connection opened : {}",connection);
+            connectLatch.countDown();
+            try
+            {
+                connection.sendMessage("Hello WebSocket World");
+            }
+            catch (IOException e)
+            {
+                LOG.warn(e);
+            }
+        }
+    }
+    
+    private static final Logger LOG = Log.getLogger(EchoClientSocketExample.class);
+
+    public static void main(String[] args)
+    {
+        QueuedThreadPool threadPool = new QueuedThreadPool();
+        // Since this is a standalone client, lets make the threadpool
+        // be able to shut itself down at System.exit()
+        threadPool.setDaemon(true);
+
+        WebSocketClientFactory factory = new WebSocketClientFactory(threadPool);
+
+        factory.getSslContextFactory().setTrustAll(true);
+        
+        // disable vulnerable SSL protocols
+        factory.getSslContextFactory().addExcludeProtocols("SSL","SSLv2","SSLv2Hello","SSLv3");
+        // disable vulnerable SSL cipher suites
+        factory.getSslContextFactory().addExcludeCipherSuites(
+                "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");
+
+        try
+        {
+            factory.start();
+
+            WebSocketClient client = factory.newWebSocketClient();
+            client.setMaxTextMessageSize(50000);
+
+            // Change to "wss://" for secure (SSL) version.
+            URI wsUri = new URI("ws://echo.websocket.org/");
+
+            // Our socket endpoint (the client side)
+            EchoClientSocket socket = new EchoClientSocket();
+
+            // Open the connection to the destination, wait 10 seconds for it to succeed (toss exception otherwise).
+            client.open(wsUri,socket).get(10,TimeUnit.SECONDS);
+
+            // wait till the socket is disconnected
+            socket.disconnectLatch.await(2L,TimeUnit.SECONDS);
+        }
+        catch (Throwable t)
+        {
+            LOG.warn(t);
+        }
+        finally
+        {
+            try
+            {
+                factory.stop();
+            }
+            catch (Exception e)
+            {
+                LOG.ignore(e);
+            }
+        }
+    }
+}
diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/examples/EchoServerSocketExample.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/examples/EchoServerSocketExample.java
new file mode 100644
index 0000000..902ab58
--- /dev/null
+++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/examples/EchoServerSocketExample.java
@@ -0,0 +1,140 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      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.examples;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.eclipse.jetty.io.Buffer;
+import org.eclipse.jetty.io.ByteArrayBuffer;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.WebSocket;
+import org.eclipse.jetty.websocket.WebSocketServlet;
+
+public class EchoServerSocketExample
+{
+    public static class EchoSocket implements WebSocket, WebSocket.OnTextMessage, WebSocket.OnBinaryMessage
+    {
+        private static final Logger LOG = Log.getLogger(EchoSocket.class);
+
+        public List<Throwable> errors = new ArrayList<Throwable>();
+        private Connection connection;
+
+        @Override
+        public void onClose(int closeCode, String message)
+        {
+            LOG.info("Closed {} : {}",closeCode,message);
+        }
+
+        @Override
+        public void onMessage(byte[] data, int offset, int length)
+        {
+            // Wrap in Jetty Buffer (only for logging reasons)
+            Buffer buf = new ByteArrayBuffer(data,offset,length);
+            LOG.info("on Text : {}",buf.toDetailString());
+
+            try
+            {
+                // echo back this BINARY message
+                this.connection.sendMessage(data,offset,length);
+            }
+            catch (IOException e)
+            {
+                LOG.warn(e);
+            }
+        }
+
+        @Override
+        public void onMessage(String message)
+        {
+            LOG.info("on Text : {}",message);
+
+            try
+            {
+                // echo back this TEXT message
+                this.connection.sendMessage(message);
+            }
+            catch (IOException e)
+            {
+                LOG.warn(e);
+            }
+        }
+
+        @Override
+        public void onOpen(Connection connection)
+        {
+            this.connection = connection;
+            LOG.info("Connection opened : {}",connection);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class EchoSocketServlet extends WebSocketServlet
+    {
+        @Override
+        public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
+        {
+            return new EchoSocket();
+        }
+    }
+
+    private static final Logger LOG = Log.getLogger(EchoServerSocketExample.class);
+
+    public static void main(String[] args)
+    {
+        Server server = new Server(9090);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        server.setHandler(context);
+
+        // Setup websocket echo socket, via servlet, on url pattern "/echo"
+        context.addServlet(EchoSocketServlet.class,"/echo");
+
+        try
+        {
+            // Start server
+            server.start();
+
+            Connector conn = server.getConnectors()[0];
+            String host = conn.getHost();
+            if (host == null)
+            {
+                host = "localhost";
+            }
+            int port = conn.getLocalPort();
+            URI serverUri = new URI(String.format("ws://%s:%d/echo",host,port));
+
+            LOG.info("WebSocket Echo Server started on {}",serverUri);
+            server.join();
+        }
+        catch (Throwable t)
+        {
+            LOG.warn(t);
+        }
+    }
+}
diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml
index 7a5f2e8..331eeef 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-xml</artifactId>
diff --git a/pom.xml b/pom.xml
index 8418b07..add494b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,14 +6,14 @@
     <version>20</version>
   </parent>
   <artifactId>jetty-project</artifactId>
-  <version>7.6.19-SNAPSHOT</version>
+  <version>8.1.19-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>
-    <orbit-servlet-api-version>2.5.0.v201103041518</orbit-servlet-api-version>
+    <orbit-servlet-api-version>3.0.0.v201112011016</orbit-servlet-api-version>
     <build-support-version>1.1</build-support-version>
     <slf4j-version>1.6.1</slf4j-version>
     <jetty-test-policy-version>1.2</jetty-test-policy-version>
@@ -22,7 +22,7 @@
     <connection>scm:git:http://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</connection>
     <developerConnection>scm:git:ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</developerConnection>
     <url>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree</url>
-    <tag>HEAD</tag>
+    <tag>jetty-8</tag>
   </scm>
   <build>
     <defaultGoal>install</defaultGoal>
@@ -30,8 +30,8 @@
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
         <configuration>
-          <source>1.5</source>
-          <target>1.5</target>
+          <source>1.6</source>
+          <target>1.6</target>
           <verbose>false</verbose>
         </configuration>
       </plugin>
@@ -189,7 +189,7 @@
           </execution>
         </executions>
         <configuration>
-          <targetJdk>1.5</targetJdk>
+          <targetJdk>1.6</targetJdk>
           <rulesets>
             <ruleset>jetty/pmd_logging_ruleset.xml</ruleset>
           </rulesets>
@@ -247,6 +247,14 @@
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-deploy-plugin</artifactId>
+          <version>2.8.2</version>
+          <configuration>
+            <retryFailedDeploymentCount>10</retryFailedDeploymentCount>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
           <configuration>
             <archive>
@@ -417,6 +425,7 @@
     <module>jetty-start</module>
     <module>jetty-nested</module>
     <module>jetty-overlay-deployer</module>
+    <module>jetty-osgi</module>
     <module>jetty-nosql</module>
     <module>jetty-http-spi</module>
     <module>jetty-jsp</module>
@@ -427,6 +436,7 @@
     <module>test-jetty-webapp</module>
     <module>test-jetty-nested</module>
     <module>example-jetty-embedded</module>
+    <module>example-async-rest</module>
     <module>tests</module>
   </modules>
   <dependencyManagement>
@@ -757,8 +767,8 @@
             <configuration>
               <excludePackageNames>com.acme</excludePackageNames>
               <links>
-                <link>http://java.sun.com/j2se/1.5.0/docs/api</link>
-                <link>http://java.sun.com/javaee/5/docs/api</link>
+                <link>http://java.sun.com/javase/6/docs/api/</link>
+                <link>http://java.sun.com/javaee/6/docs/api</link>
                 <link>http://junit.sourceforge.net/javadoc/</link>
               </links>
               <tags>
diff --git a/settings.xml b/settings.xml
new file mode 100755
index 0000000..9b5ddef
--- /dev/null
+++ b/settings.xml
@@ -0,0 +1,21 @@
+<settings>
+  <localRepository>/tmp/jetty-builds/jetty8/localRepo</localRepository>
+  <interactiveMode>true</interactiveMode>
+  <offline>false</offline>
+<proxies>
+   <proxy>
+      <active>true</active>
+      <protocol>http</protocol>
+      <host>proxy.eclipse.org</host>
+      <port>9898</port>
+    </proxy>
+  </proxies>
+<mirrors>
+  <mirror>
+      <id>central</id>
+      <name>central</name>
+      <url>http://repo2.maven.org/maven2/</url>
+      <mirrorOf>*</mirrorOf>
+    </mirror>
+  </mirrors>
+</settings>
diff --git a/test-continuation-jetty6/pom.xml b/test-continuation-jetty6/pom.xml
index 9f7f4e1..86048b7 100644
--- a/test-continuation-jetty6/pom.xml
+++ b/test-continuation-jetty6/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.0-SNAPSHOT</version>
+    <version>8.1.0-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>test-continuation-jetty6</artifactId>
@@ -29,16 +29,34 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.mortbay.jetty</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>2.5-20081211</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.eclipse.jetty</groupId> 
       <artifactId>jetty-servlet</artifactId>
       <version>${project.version}</version>
       <scope>test</scope>
+        <exclusions>
+          <exclusion>
+            <groupId>${servlet.spec.groupId}</groupId>
+            <artifactId>${servlet.spec.artifactId}</artifactId>
+          </exclusion>
+        </exclusions>
     </dependency> 
     <dependency>
       <groupId>org.eclipse.jetty</groupId> 
       <artifactId>test-continuation</artifactId>
       <version>${project.version}</version>
       <scope>test</scope>
+      <exclusions>
+       	<exclusion>
+	  <groupId>${servlet.spec.groupId}</groupId>
+	  <artifactId>${servlet.spec.artifactId}</artifactId>
+       	</exclusion>
+      </exclusions>
     </dependency> 
     <dependency>
         <groupId>org.mortbay.jetty</groupId>
diff --git a/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java b/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java
new file mode 100644
index 0000000..aafecbc
--- /dev/null
+++ b/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java
@@ -0,0 +1,428 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      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.net.Socket;
+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 junit.framework.TestCase;
+
+
+
+public abstract class ContinuationBase extends TestCase
+{
+    protected SuspendServlet _servlet=new SuspendServlet();
+    protected int _port;
+    
+    protected void doit(String type) throws Exception
+    {
+        String response;
+        
+        response=process(null,null);
+        assertContains(type,response);
+        assertContains("NORMAL",response);
+        assertNotContains("history: onTimeout",response);
+        assertNotContains("history: onComplete",response);
+
+        response=process("sleep=200",null);
+        assertContains("SLEPT",response);
+        assertNotContains("history: onTimeout",response);
+        assertNotContains("history: onComplete",response);
+        
+        response=process("suspend=200",null);
+        assertContains("TIMEOUT",response);
+        assertContains("history: onTimeout",response);
+        assertContains("history: onComplete",response);
+        
+        response=process("suspend=200&resume=10",null);
+        assertContains("RESUMED",response);
+        assertNotContains("history: onTimeout",response);
+        assertContains("history: onComplete",response);
+        
+        response=process("suspend=200&resume=0",null);
+        assertContains("RESUMED",response);
+        assertNotContains("history: onTimeout",response);
+        assertContains("history: onComplete",response);
+        
+        response=process("suspend=200&complete=10",null);
+        assertContains("COMPLETED",response);
+        assertNotContains("history: onTimeout",response);
+        assertContains("history: onComplete",response);
+        
+        response=process("suspend=200&complete=0",null);
+        assertContains("COMPLETED",response);
+        assertNotContains("history: onTimeout",response);
+        assertContains("history: onComplete",response);
+        
+        
+        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);
+        
+        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);
+        
+        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);
+        
+        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);
+        
+
+        
+        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);
+        
+        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);
+        
+        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);
+        
+        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);
+        
+    }
+
+    
+    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)
+    {
+        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
+        if (response.indexOf(content,15)<0)
+        {
+            System.err.println(content+" NOT IN '"+response+"'");
+            assertTrue(false);
+        }
+    }
+    
+    protected void assertNotContains(String content,String response)
+    {
+        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
+        if (response.indexOf(content,15)>=0)
+        {
+            System.err.println(content+" IS IN '"+response+"'");
+            assertTrue(false);
+        }
+    }
+    
+    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+="Content-Length: "+content.length()+"\r\n";
+        request+="\r\n" + content;
+        
+        Socket socket = new Socket("localhost",_port);
+        socket.getOutputStream().write(request.getBytes("UTF-8"));
+        
+        String response = toString(socket.getInputStream());
+        return response;
+    }
+    
+    
+    protected abstract String toString(InputStream in) throws IOException;
+    
+    
+    private static class SuspendServlet extends HttpServlet
+    {
+        private Timer _timer=new Timer();
+        
+        public SuspendServlet()
+        {}
+        
+        /* ------------------------------------------------------------ */
+        protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+        {
+            final Continuation continuation = ContinuationSupport.getContinuation(request,response);
+
+            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;
+            
+            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 (continuation.isInitial())
+            {
+                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);
+                    ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","suspend");
+                    continuation.suspend();
+                    
+                    if (complete_after>0)
+                    {
+                        TimerTask complete = new TimerTask()
+                        {
+                            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()
+                        {
+                            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();
+                    }
+                }
+                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 if (suspend2_for>=0 && request.getAttribute("2nd")==null)
+            {
+                request.setAttribute("2nd","cycle");
+
+                if (suspend2_for>0)
+                    continuation.setTimeout(suspend2_for);
+                // continuation.addContinuationListener(__listener);
+                ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","suspend");
+                continuation.suspend();
+
+                if (complete2_after>0)
+                {
+                    TimerTask complete = new TimerTask()
+                    {
+                        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()
+                    {
+                        public void run()
+                        {
+                            ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","resume");
+                            continuation.resume();
+                        }
+                    };
+                    synchronized (_timer)
+                    {
+                        _timer.schedule(resume,resume2_after);
+                    }
+                }
+                else if (resume2_after==0)
+                {
+                    ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","resume");
+                    continuation.resume();
+                }
+                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()
+    {
+        public void onComplete(Continuation continuation)
+        {
+            ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","onComplete");
+        }
+
+        public void onTimeout(Continuation continuation)
+        {
+            ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","onTimeout");
+            continuation.resume();
+        }
+        
+    };
+}
diff --git a/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java b/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java
new file mode 100644
index 0000000..f43e4c7
--- /dev/null
+++ b/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.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.continuation;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+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;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.nio.SelectChannelConnector;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.FilterHolder;
+import org.mortbay.jetty.servlet.ServletHandler;
+import org.mortbay.jetty.servlet.ServletHolder;
+import org.mortbay.util.IO;
+
+
+public class FauxContinuationTest extends ContinuationBase
+{
+    protected Server _server = new Server();
+    protected ServletHandler _servletHandler;
+    protected SelectChannelConnector _connector;
+    FilterHolder _filter;
+
+    protected void setUp() throws Exception
+    {
+        _connector = new SelectChannelConnector();
+        _server.setConnectors(new Connector[]{ _connector });
+        Context servletContext = new Context(Context.NO_SECURITY|Context.NO_SESSIONS);
+        _server.setHandler(servletContext);
+        _servletHandler=servletContext.getServletHandler();
+        ServletHolder holder=new ServletHolder(_servlet);
+        _servletHandler.addServletWithMapping(holder,"/");
+        _filter=_servletHandler.addFilterWithMapping(ContinuationFilter.class,"/*",0);
+    }
+
+    protected void tearDown() throws Exception
+    {
+        _server.stop();
+    }
+
+    public void testFaux() throws Exception
+    {
+        _filter.setInitParameter("debug","true");
+        _filter.setInitParameter("faux","true");
+        _server.start();
+        _port=_connector.getLocalPort();
+        
+        doit("FauxContinuation");
+    }
+
+    
+    
+    protected String toString(InputStream in) throws IOException
+    {
+        return IO.toString(in);
+    }
+}
diff --git a/test-continuation/pom.xml b/test-continuation/pom.xml
index cc83550..22eb956 100644
--- a/test-continuation/pom.xml
+++ b/test-continuation/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>test-continuation</artifactId>
diff --git a/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java b/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java
index 24bf362..747fd78 100644
--- a/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java
+++ b/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.EnumSet;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -66,6 +67,7 @@
         
         _servletHandler=servletContext.getServletHandler();
         ServletHolder holder=new ServletHolder(_servlet);
+        holder.setAsyncSupported(true);
         _servletHandler.addServletWithMapping(holder,"/");
         
         _server.start();
diff --git a/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java b/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java
index b8e7ce4..5db81e4 100644
--- a/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java
+++ b/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java
@@ -20,6 +20,9 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
 
 import org.eclipse.jetty.continuation.test.ContinuationBase;
 import org.eclipse.jetty.server.Connector;
@@ -49,7 +52,7 @@
         ServletHolder holder=new ServletHolder(_servlet);
         _servletHandler.addServletWithMapping(holder,"/");
         
-        _filter=_servletHandler.addFilterWithMapping(ContinuationFilter.class,"/*",0);
+        _filter=_servletHandler.addFilterWithMapping(ContinuationFilter.class,"/*",null);
         _filter.setInitParameter("debug","true");
         _filter.setInitParameter("faux","true");
         _server.start();
diff --git a/test-jetty-nested/pom.xml b/test-jetty-nested/pom.xml
index 3fe5400..7cae48a 100644
--- a/test-jetty-nested/pom.xml
+++ b/test-jetty-nested/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-jetty-nested</artifactId>
   <name>Jetty :: Nested Test</name>
diff --git a/test-jetty-nested/src/main/java/org/eclipse/jetty/nested/Dump.java b/test-jetty-nested/src/main/java/org/eclipse/jetty/nested/Dump.java
index a71fa17..5f93b4e 100644
--- a/test-jetty-nested/src/main/java/org/eclipse/jetty/nested/Dump.java
+++ b/test-jetty-nested/src/main/java/org/eclipse/jetty/nested/Dump.java
@@ -101,7 +101,7 @@
         final boolean flush= request.getParameter("flush")!=null?Boolean.parseBoolean(request.getParameter("flush")):false;
 
         
-        if(request.getPathInfo()!=null && request.getPathInfo().toLowerCase().indexOf("script")!=-1)
+        if(request.getPathInfo()!=null && request.getPathInfo().toLowerCase(Locale.ENGLISH).indexOf("script")!=-1)
         {
             response.sendRedirect(response.encodeRedirectURL(getServletContext().getContextPath() + "/dump/info"));
             return;
diff --git a/test-jetty-servlet/pom.xml b/test-jetty-servlet/pom.xml
index ce211cb..b6f6487 100644
--- a/test-jetty-servlet/pom.xml
+++ b/test-jetty-servlet/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>test-jetty-servlet</artifactId>
diff --git a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java
index 7e489df..65ce9f1 100644
--- a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java
+++ b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java
@@ -382,7 +382,7 @@
                 cookie.getMaxAge(),
                 cookie.getComment(),
                 cookie.getSecure(),
-                false,
+                cookie.isHttpOnly(),
                 cookie.getVersion());
     }
 
diff --git a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java
index 053e668..4e3de5d 100644
--- a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java
+++ b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java
@@ -19,9 +19,12 @@
 package org.eclipse.jetty.testing;
 
 import java.net.InetAddress;
+import java.util.EnumSet;
 import java.util.Enumeration;
 import java.util.EventListener;
 
+import javax.servlet.DispatcherType;
+
 import org.eclipse.jetty.io.ByteArrayBuffer;
 import org.eclipse.jetty.server.LocalConnector;
 import org.eclipse.jetty.server.Server;
@@ -245,7 +248,7 @@
      * @return the FilterHolder
      * @see org.eclipse.jetty.servlet.ServletContextHandler#addFilter(java.lang.Class, java.lang.String, int)
      */
-    public FilterHolder addFilter(Class filterClass, String pathSpec, int dispatches)
+    public FilterHolder addFilter(Class filterClass, String pathSpec, EnumSet<DispatcherType> dispatches)
     {
         return _context.addFilter(filterClass,pathSpec,dispatches);
     }
@@ -258,7 +261,7 @@
      * @return the FilterHolder
      * @see org.eclipse.jetty.servlet.ServletContextHandler#addFilter(java.lang.String, java.lang.String, int)
      */
-    public FilterHolder addFilter(String filterClass, String pathSpec, int dispatches)
+    public FilterHolder addFilter(String filterClass, String pathSpec, EnumSet<DispatcherType> dispatches)
     {
         return _context.addFilter(filterClass,pathSpec,dispatches);
     }
diff --git a/test-jetty-webapp/pom.xml b/test-jetty-webapp/pom.xml
index 9d2e009..2a78829 100644
--- a/test-jetty-webapp/pom.xml
+++ b/test-jetty-webapp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>test-jetty-webapp</artifactId>
@@ -110,6 +110,7 @@
               <value>222</value>
             </systemProperty>
           </systemProperties>
+          <useTestScope>true</useTestScope>
           <webAppConfig>
             <contextPath>/test</contextPath>
             <tempDirectory>${project.build.directory}/work</tempDirectory>
diff --git a/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml b/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml
index 9e42d6d..512ce2b 100644
--- a/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml
+++ b/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml
@@ -15,15 +15,6 @@
     <param-value>a context value</param-value>
   </context-param>
 
-  <!-- Add or override filter init parameter -->
-  <filter>
-    <filter-name>TestFilter</filter-name>
-    <filter-class>com.acme.TestFilter</filter-class>
-    <init-param>
-      <param-name>remote</param-name>
-      <param-value>false</param-value>
-    </init-param>
-  </filter>
 
   <!-- Add or override servlet init parameter -->
   <servlet>
@@ -46,6 +37,23 @@
     <servlet-class>com.acme.SessionDump</servlet-class>
     <load-on-startup>5</load-on-startup>
   </servlet>
+
+  <!-- Uncomment to override the setup of the test filter -->
+  <!-- 
+  <filter>
+    <filter-name>TestFilter</filter-name>
+    <filter-class>com.acme.TestFilter</filter-class>
+    <async-support>true</async-support>
+    <init-param>
+      <param-name>remote</param-name>
+      <param-value>false</param-value>
+    </init-param>
+  </filter>
+  <filter-mapping>
+     <filter-name>TestFilter</filter-name>
+     <url-pattern>/*</url-pattern>
+  </filter-mapping>
+  -->
   
 </web-app>
 
diff --git a/test-jetty-webapp/src/main/java/com/acme/Dump.java b/test-jetty-webapp/src/main/java/com/acme/Dump.java
index 7af0bfe..e99eb99 100644
--- a/test-jetty-webapp/src/main/java/com/acme/Dump.java
+++ b/test-jetty-webapp/src/main/java/com/acme/Dump.java
@@ -119,6 +119,18 @@
     @Override
     public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
     {
+        if (!request.isUserInRole("user")) 
+        {
+            try 
+            {
+                request.login("user", "password");
+            } 
+            catch(ServletException se) 
+            {
+            	se.printStackTrace();
+            }
+        }
+        
         // Handle a dump of data
         final String data= request.getParameter("data");
         final String chars= request.getParameter("chars");
@@ -493,6 +505,10 @@
             pout.write("<td>"+request.isSecure()+"</td>");
 
             pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">encodeRedirectURL(/foo?bar):&nbsp;</th>");
+            pout.write("<td>"+response.encodeRedirectURL("/foo?bar")+"</td>");
+
+            pout.write("</tr><tr>\n");
             pout.write("<th align=\"right\">isUserInRole(admin):&nbsp;</th>");
             pout.write("<td>"+request.isUserInRole("admin")+"</td>");
 
diff --git a/test-jetty-webapp/src/main/java/com/acme/LoginServlet.java b/test-jetty-webapp/src/main/java/com/acme/LoginServlet.java
new file mode 100644
index 0000000..6d9c70e
--- /dev/null
+++ b/test-jetty-webapp/src/main/java/com/acme/LoginServlet.java
@@ -0,0 +1,92 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package com.acme;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import javax.servlet.ServletConfig;
+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.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/** Dump Servlet Request.
+ * 
+ */
+public class LoginServlet extends HttpServlet
+{
+    private static final Logger LOG = Log.getLogger(SecureModeServlet.class);
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void init(ServletConfig config) throws ServletException
+    {
+    	super.init(config);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        doGet(request, response);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+         
+        response.setContentType("text/html");
+        ServletOutputStream out = response.getOutputStream();
+        out.println("<html>");
+        out.println("<br/>Before getUserPrincipal="+request.getUserPrincipal());
+        out.println("<br/>Before getRemoteUser="+request.getRemoteUser());
+        String param = request.getParameter("action");
+
+        if ("login".equals(param))
+        {
+              request.login("jetty", "jetty");
+        }
+        else if ("logout".equals(param))
+        {
+             request.logout();
+        }
+        else if ("wrong".equals(param))
+        {
+             request.login("jetty", "123");
+        }  
+
+        out.println("<br/>After getUserPrincipal="+request.getUserPrincipal());
+        out.println("<br/>After getRemoteUser="+request.getRemoteUser());
+        out.println("</html>");
+        out.flush();
+    }
+}
diff --git a/test-jetty-webapp/src/main/java/com/acme/RegTest.java b/test-jetty-webapp/src/main/java/com/acme/RegTest.java
new file mode 100644
index 0000000..28e47f4
--- /dev/null
+++ b/test-jetty-webapp/src/main/java/com/acme/RegTest.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 com.acme;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.util.StringUtil;
+
+
+
+
+/* ------------------------------------------------------------ */
+/** Rego Servlet - tests being accessed from servlet 3.0 programmatic 
+ * configuration.
+ * 
+ */
+public class RegTest extends HttpServlet
+{
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public void init(ServletConfig config) throws ServletException
+    {
+    	super.init(config);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        doGet(request, response);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+    { 
+        request.setCharacterEncoding("UTF-8");        
+        PrintWriter pout=null;
+        
+        try
+        {
+            pout =response.getWriter();
+        }
+        catch(IllegalStateException e)
+        {
+            pout=new PrintWriter(new OutputStreamWriter(response.getOutputStream(),"UTF-8"));
+        }
+   
+        try
+        {
+            pout.write("<html>\n<body>\n");
+            pout.write("<h1>Rego Servlet</h1>\n");
+            pout.write("<table width=\"95%\">");
+            pout.write("<tr>\n");
+            pout.write("<th align=\"right\">getMethod:&nbsp;</th>");
+            pout.write("<td>" + notag(request.getMethod())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getContentLength:&nbsp;</th>");
+            pout.write("<td>"+Integer.toString(request.getContentLength())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getContentType:&nbsp;</th>");
+            pout.write("<td>"+notag(request.getContentType())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getRequestURI:&nbsp;</th>");
+            pout.write("<td>"+notag(request.getRequestURI())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getRequestURL:&nbsp;</th>");
+            pout.write("<td>"+notag(request.getRequestURL().toString())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getContextPath:&nbsp;</th>");
+            pout.write("<td>"+request.getContextPath()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getServletPath:&nbsp;</th>");
+            pout.write("<td>"+notag(request.getServletPath())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getPathInfo:&nbsp;</th>");
+            pout.write("<td>"+notag(request.getPathInfo())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getPathTranslated:&nbsp;</th>");
+            pout.write("<td>"+notag(request.getPathTranslated())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getQueryString:&nbsp;</th>");
+            pout.write("<td>"+notag(request.getQueryString())+"</td>");
+            pout.write("</tr><tr>\n");
+            
+            pout.write("<th align=\"right\">getProtocol:&nbsp;</th>");
+            pout.write("<td>"+request.getProtocol()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getScheme:&nbsp;</th>");
+            pout.write("<td>"+request.getScheme()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getServerName:&nbsp;</th>");
+            pout.write("<td>"+notag(request.getServerName())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getServerPort:&nbsp;</th>");
+            pout.write("<td>"+Integer.toString(request.getServerPort())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getLocalName:&nbsp;</th>");
+            pout.write("<td>"+request.getLocalName()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getLocalAddr:&nbsp;</th>");
+            pout.write("<td>"+request.getLocalAddr()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getLocalPort:&nbsp;</th>");
+            pout.write("<td>"+Integer.toString(request.getLocalPort())+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getRemoteUser:&nbsp;</th>");
+            pout.write("<td>"+request.getRemoteUser()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getUserPrincipal:&nbsp;</th>");
+            pout.write("<td>"+request.getUserPrincipal()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getRemoteAddr:&nbsp;</th>");
+            pout.write("<td>"+request.getRemoteAddr()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getRemoteHost:&nbsp;</th>");
+            pout.write("<td>"+request.getRemoteHost()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getRemotePort:&nbsp;</th>");
+            pout.write("<td>"+request.getRemotePort()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">getRequestedSessionId:&nbsp;</th>");
+            pout.write("<td>"+request.getRequestedSessionId()+"</td>");
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">isSecure():&nbsp;</th>");
+            pout.write("<td>"+request.isSecure()+"</td>");
+
+            pout.write("</tr><tr>\n");
+            pout.write("<th align=\"right\">isUserInRole(admin):&nbsp;</th>");
+            pout.write("<td>"+request.isUserInRole("admin")+"</td>");
+
+            pout.write("</tr></table>");
+   
+        }
+        catch (Exception e)
+        {
+            getServletContext().log("dump "+e);
+        }
+        
+        
+        pout.write("</body>\n</html>\n");
+        
+        pout.close();
+    }
+
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String getServletInfo()
+    {
+        return "Rego Servlet";
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public synchronized void destroy()
+    {
+    }
+
+    
+    private String notag(String s)
+    {
+        if (s==null)
+            return "null";
+        s=StringUtil.replace(s,"&","&amp;");
+        s=StringUtil.replace(s,"<","&lt;");
+        s=StringUtil.replace(s,">","&gt;");
+        return s;
+    }
+}
diff --git a/test-jetty-webapp/src/main/java/com/acme/TestListener.java b/test-jetty-webapp/src/main/java/com/acme/TestListener.java
index 084a462..884f283 100644
--- a/test-jetty-webapp/src/main/java/com/acme/TestListener.java
+++ b/test-jetty-webapp/src/main/java/com/acme/TestListener.java
@@ -18,6 +18,7 @@
 
 package com.acme;
 
+import javax.servlet.DispatcherType;
 import javax.servlet.ServletContextAttributeEvent;
 import javax.servlet.ServletContextAttributeListener;
 import javax.servlet.ServletContextEvent;
@@ -26,6 +27,12 @@
 import javax.servlet.ServletRequestAttributeListener;
 import javax.servlet.ServletRequestEvent;
 import javax.servlet.ServletRequestListener;
+import javax.servlet.ServletRegistration;
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.HttpConstraintElement;
+import javax.servlet.HttpMethodConstraintElement;
+import javax.servlet.annotation.ServletSecurity;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSessionActivationListener;
 import javax.servlet.http.HttpSessionAttributeListener;
@@ -33,6 +40,9 @@
 import javax.servlet.http.HttpSessionEvent;
 import javax.servlet.http.HttpSessionListener;
 
+import java.util.EnumSet;
+import java.util.Set;
+
 public class TestListener implements HttpSessionListener,  HttpSessionAttributeListener, HttpSessionActivationListener, ServletContextListener, ServletContextAttributeListener, ServletRequestListener, ServletRequestAttributeListener
 {
     public void attributeAdded(HttpSessionBindingEvent se)
@@ -62,16 +72,33 @@
 
     public void contextInitialized(ServletContextEvent sce)
     {	
-    	/* TODO  for servlet 3.0
-    	 * FilterRegistration registration=context.addFilter("TestFilter",TestFilter.class.getName());
-    	
-    	
-    	registration.setAsyncSupported(true);
-    	registration.addMappingForUrlPatterns(
+        //configure programmatic security
+        ServletRegistration.Dynamic rego = sce.getServletContext().addServlet("RegoTest", RegTest.class.getName());
+        rego.addMapping("/rego/*");
+        HttpConstraintElement constraintElement = new HttpConstraintElement(ServletSecurity.EmptyRoleSemantic.PERMIT, 
+                                                                            ServletSecurity.TransportGuarantee.NONE, new String[]{"admin"});
+        ServletSecurityElement securityElement = new ServletSecurityElement(constraintElement, null);
+        Set<String> unchanged = rego.setServletSecurity(securityElement);
+        //System.err.println("Security constraints registered: "+unchanged.isEmpty());
+
+        //Test that a security constraint from web.xml can't be overridden programmatically
+        ServletRegistration.Dynamic rego2 = sce.getServletContext().addServlet("RegoTest2", RegTest.class.getName());
+        rego2.addMapping("/rego2/*");
+        securityElement = new ServletSecurityElement(constraintElement, null);
+        unchanged = rego2.setServletSecurity(securityElement);
+        //System.err.println("Overridding web.xml constraints not possible:" +!unchanged.isEmpty());
+
+    	/* For servlet 3.0 */
+    	FilterRegistration.Dynamic registration = sce.getServletContext().addFilter("TestFilter",TestFilter.class.getName());
+        if (registration != null) //otherwise it was configured in web.xml
+        {
+    	    registration.setInitParameter("remote", "false");
+    	    registration.setAsyncSupported(true);
+    	    registration.addMappingForUrlPatterns(
     	        EnumSet.of(DispatcherType.ERROR,DispatcherType.ASYNC,DispatcherType.FORWARD,DispatcherType.INCLUDE,DispatcherType.REQUEST),
     	        true, 
-    	        new String[]{"/dump/*","/dispatch/*","*.dump"});
-    	        */
+    	        new String[]{"/*"});
+        }
     }
 
     public void contextDestroyed(ServletContextEvent sce)
diff --git a/test-jetty-webapp/src/main/webapp/META-INF/MANIFEST.MF b/test-jetty-webapp/src/main/webapp/META-INF/MANIFEST.MF
index cc61b1a..cfe644d 100644
--- a/test-jetty-webapp/src/main/webapp/META-INF/MANIFEST.MF
+++ b/test-jetty-webapp/src/main/webapp/META-INF/MANIFEST.MF
@@ -4,8 +4,8 @@
 Bundle-SymbolicName: TestIt

 Bundle-Version: 1.0.0.qualifier

 Bundle-Activator: testit.Activator

-Import-Package: javax.servlet,

- javax.servlet.http,

+Import-Package: javax.servlet;version="2.6",

+ javax.servlet.http;version="2.6",

  javax.servlet.jsp,

  javax.servlet.jsp.tagext

 Require-Bundle: org.eclipse.jetty.client,

diff --git a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
index 3806a33..4eaf5e1 100644
--- a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
+++ b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
@@ -2,8 +2,9 @@
 <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" 
-   version="2.5"> 
+   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+   metadata-complete="false"
+   version="3.0"> 
 
   <display-name>Test WebApp</display-name>
   
@@ -17,23 +18,11 @@
     <listener-class>com.acme.TestListener</listener-class>
   </listener>
 
-  <filter>
-    <filter-name>TestFilter</filter-name>
-    <filter-class>com.acme.TestFilter</filter-class>
-    <init-param>
-      <param-name>remote</param-name>
-      <param-value>false</param-value>
-    </init-param>
-  </filter>
-  <filter-mapping>
-    <filter-name>TestFilter</filter-name>
-    <url-pattern>/*</url-pattern>
-  </filter-mapping>
-
 
   <filter>
     <filter-name>QoSFilter</filter-name>
     <filter-class>org.eclipse.jetty.servlets.QoSFilter</filter-class>
+    <async-support>true</async-support>
     <init-param>
       <param-name>maxRequests</param-name>
       <param-value>10000</param-value>
@@ -52,6 +41,7 @@
   <filter>
     <filter-name>MultiPart</filter-name>
     <filter-class>org.eclipse.jetty.servlets.MultiPartFilter</filter-class>
+    <async-support>true</async-support>
     <init-param>
       <param-name>deleteFiles</param-name>
       <param-value>true</param-value>
@@ -66,6 +56,7 @@
   <filter>
     <filter-name>GzipFilter</filter-name>
     <filter-class>org.eclipse.jetty.servlets.IncludableGzipFilter</filter-class>
+    <async-support>true</async-support>
     <init-param>
       <param-name>bufferSize</param-name>
       <param-value>8192</param-value>
@@ -119,6 +110,16 @@
     <dispatcher>REQUEST</dispatcher>
   </filter-mapping>
   -->
+  <servlet>
+    <servlet-name>Login</servlet-name>
+    <servlet-class>com.acme.LoginServlet</servlet-class>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>Login</servlet-name>
+    <url-pattern>/login/*</url-pattern>
+  </servlet-mapping>
 
 
   <servlet>
@@ -135,6 +136,7 @@
   <servlet>
     <servlet-name>Dump</servlet-name>
     <servlet-class>com.acme.Dump</servlet-class>
+    <async-support>true</async-support>
     <load-on-startup>1</load-on-startup>
     <run-as><role-name>admin</role-name></run-as>
   </servlet>
@@ -170,6 +172,7 @@
   <servlet>
     <servlet-name>Dispatch</servlet-name>
     <servlet-class>com.acme.DispatchServlet</servlet-class>
+    <async-support>true</async-support>
     <load-on-startup>1</load-on-startup>
   </servlet>
   
@@ -192,6 +195,7 @@
   <servlet>
     <servlet-name>Chat</servlet-name>
     <servlet-class>com.acme.ChatServlet</servlet-class>
+    <async-support>true</async-support>
     <load-on-startup>1</load-on-startup>
   </servlet>
 
@@ -239,11 +243,12 @@
   <servlet>
     <servlet-name>TransparentProxy</servlet-name>
     <servlet-class>org.eclipse.jetty.servlets.ProxyServlet$Transparent</servlet-class>
+    <async-support>true</async-support>
     <init-param>
       <param-name>Prefix</param-name><param-value>/javadoc-proxy</param-value>
     </init-param>
     <init-param>
-      <param-name>ProxyTo</param-name><param-value>http://download.eclipse.org/jetty/stable-7/apidocs</param-value>
+      <param-name>ProxyTo</param-name><param-value>http://download.eclipse.org/jetty/stable-8/apidocs</param-value>
     </init-param>
     <init-param>
       <param-name>HostHeader</param-name><param-value>download.eclipse.org</param-value>
@@ -271,6 +276,18 @@
     <location>/error404.html</location>
   </error-page>
 
+
+
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>Rego2</web-resource-name>
+      <url-pattern>/rego2/*</url-pattern>
+    </web-resource-collection>
+    <auth-constraint>
+      <role-name>server-administrator</role-name>
+    </auth-constraint>
+  </security-constraint>
+
   <security-constraint>
     <web-resource-collection>
       <web-resource-name>Auth2</web-resource-name>
diff --git a/test-jetty-webapp/src/main/webapp/auth.html b/test-jetty-webapp/src/main/webapp/auth.html
index 1b1de11..4b67966 100644
--- a/test-jetty-webapp/src/main/webapp/auth.html
+++ b/test-jetty-webapp/src/main/webapp/auth.html
@@ -18,6 +18,12 @@
 <li><a href="dump/auth/info">dump/auth/*</a> - Authenticated any user</li>
 <li><a href="dump/auth/admin/info">dump/auth/admin/*</a> - Authenticated admin role (<a href="session/?Action=Invalidate">click</a> to invalidate session)</li>
 <li><a href="dump/auth/ssl/info">dump/auth/ssl/*</a> - Confidential</li>
+<li><a href="rego/info">rego/info/*</a> - Authenticated admin role from programmatic security (<a href="session/?Action=Invalidate">click</a> to invalidate session)</li>
+<li><a href="rego2/info">rego2/info/*</a> - Authenticated servlet-administrator role from programmatic security (login as admin/admin, <a href="session/?Action=Invalidate">click</a> to invalidate session)</li>
+<li><a href="login?action=login">login</a> - Programmatically login as the user jetty/jetty</li>
+<li><a href="login?action=x">check login status</a> - Check the request's login status</li>
+<li><a href="login?action=logout">logout</a> - Programmatically logout the logged in user</li>
+<li><a href="login?action=wrong">incorrect login</a> - Programmatically login with incorrect credentials</li>
 </ul>
 <p/>
 <p>
diff --git a/test-jetty-webapp/src/main/webapp/index.html b/test-jetty-webapp/src/main/webapp/index.html
index 74ef907..630bc1d 100644
--- a/test-jetty-webapp/src/main/webapp/index.html
+++ b/test-jetty-webapp/src/main/webapp/index.html
@@ -11,9 +11,9 @@
   </HEAD>
 <BODY>
 <A HREF="http://jetty.eclipse.org"><IMG SRC="jetty_banner.gif"></A>
-<h1>Welcome to Jetty 7</h1>
+<h1>Welcome to Jetty 8</h1>
 <p>
-This is the Test webapp for the Jetty 7 HTTP Server and Servlet Container.  
+This is the Test webapp for the Jetty 8 HTTP Server and Servlet Container.  
 For more information about Jetty, please visit our
 <a href="http://www.eclipse.org/jetty">website</a>
 or <a href="http://wiki.eclipse.org/Jetty">wiki</a> or see the bundled <a href="javadoc/">javadoc</a>.<br/>
diff --git a/test-jetty-webapp/src/main/webapp/remote.html b/test-jetty-webapp/src/main/webapp/remote.html
index b759568..3f52269 100644
--- a/test-jetty-webapp/src/main/webapp/remote.html
+++ b/test-jetty-webapp/src/main/webapp/remote.html
@@ -6,9 +6,9 @@
   </HEAD>
 <BODY>
 <A HREF="http://www.eclipse.org/jetty"><IMG SRC="jetty_banner.gif"></A>
-<h1>Welcome to Jetty 7 - REMOTE ACCESS!!</h1>
+<h1>Welcome to Jetty 8 - REMOTE ACCESS!!</h1>
 <p>
-This is the Test webapp for the Jetty 7 HTTP Server and Servlet Container.  
+This is the Test webapp for the Jetty 8 HTTP Server and Servlet Container.  
 For more information about Jetty, please visit our
 <a href="http://www.eclipse.org/jetty">website</a>
 or <a href="http://www.eclipse.org/jetty/documentation/">documentation</a>. 
@@ -21,12 +21,11 @@
 is displayed because you have accessed this context from a non local IP address.
 </p>
 <p>
-You can disable the remote address checking by editing contexts/test.d/override-web.xml and changing the
-"remote" init parameter to true for the TestFilter. 
+You can disable the remote address checking by editing contexts/test.d/override-web.xml, uncommenting the definition of the TestFilter, and changing the
+"remote" init parameter to "true".
 </p>
 <p>
-This webapp is deployed in $JETTY_HOME/webapp/test and configured by $JETTY_HOME/contexts/test.xml
-and $JETTY_HOME/contexts/test.d/override-web.xml
+This webapp is deployed in $JETTY_HOME/webapp/test.war and configured by $JETTY_HOME/contexts/test.xml and $JETTY_HOME/contexts/test.d/override-web.xml
 </p>
 
 </BODY>
diff --git a/tests/pom.xml b/tests/pom.xml
index 22ec0b4..ecb152d 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <groupId>org.eclipse.jetty.tests</groupId>
   <artifactId>tests-parent</artifactId>
diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml
index bc60242..76320e1 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>test-integration</artifactId>
diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml
index 771c9f1..af040e0 100644
--- a/tests/test-loginservice/pom.xml
+++ b/tests/test-loginservice/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>tests-parent</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-loginservice</artifactId>
   <name>Jetty Tests :: Login Service</name>
diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml
index bfd1159..4a771d4 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-sessions-parent</artifactId>
   <name>Jetty Tests :: Sessions :: Parent</name>
diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml
index ed726c9..8b0ff30 100644
--- a/tests/test-sessions/test-hash-sessions/pom.xml
+++ b/tests/test-sessions/test-hash-sessions/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-sessions-parent</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-hash-sessions</artifactId>
   <name>Jetty Tests :: Sessions :: Hash</name>
diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml
index 9364836..5cdfe5e 100644
--- a/tests/test-sessions/test-jdbc-sessions/pom.xml
+++ b/tests/test-sessions/test-jdbc-sessions/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-sessions-parent</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-jdbc-sessions</artifactId>
   <name>Jetty Tests :: Sessions :: JDBC</name>
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
new file mode 100644
index 0000000..2c83878
--- /dev/null
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java
@@ -0,0 +1,192 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      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.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+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.ContentExchange;
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.junit.Test;
+import org.junit.Ignore;
+
+/**
+ *  SaveIntervalTest
+ *
+ *  Checks to see that potentially stale sessions that have not
+ *  changed are not always reloaded from the datase.
+ *
+ *  This test is Ignored because it takes a little while to run.
+ *
+ */
+public class SaveIntervalTest
+{
+    public static int INACTIVE = 90; //sec
+    public static int SCAVENGE = 100; //sec
+    public static int SAVE = 10; //sec
+
+
+    @Ignore
+    @Test
+    public void testSaveInterval() throws Exception
+    {
+        AbstractTestServer server = new JdbcTestServer(0,INACTIVE,SCAVENGE);
+
+        ServletContextHandler ctxA = server.addContext("/mod");
+        ServletHolder holder = new ServletHolder();
+        TestSaveIntervalServlet servlet = new TestSaveIntervalServlet();
+        holder.setServlet(servlet);
+        ctxA.addServlet(holder, "/test");
+        ((JDBCSessionManager)ctxA.getSessionHandler().getSessionManager()).setSaveInterval(SAVE);
+        server.start();
+        int port=server.getPort();
+        try
+        {
+            HttpClient client = new HttpClient();
+            client.start();
+            try
+            {
+                // Perform a request to create a session 
+                ContentExchange exchange1 = new ContentExchange(true);
+                exchange1.setMethod(HttpMethods.GET);
+                exchange1.setURL("http://localhost:" + port + "/mod/test?action=create");
+                client.send(exchange1);
+                exchange1.waitForDone();
+                assertEquals(HttpServletResponse.SC_OK,exchange1.getResponseStatus());
+                String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
+                assertTrue(sessionCookie != null);
+                // Mangle the cookie, replacing Path with $Path, etc.
+                sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
+                long lastSaved = ((JDBCSessionManager.Session)servlet._session).getLastSaved();
+                
+                
+                //do another request to change the session attribute
+                ContentExchange exchange2 = new ContentExchange(true);
+                exchange2.setMethod(HttpMethods.GET);
+                exchange2.setURL("http://localhost:" + port + "/mod/test?action=set");
+                exchange2.getRequestFields().add("Cookie", sessionCookie);
+                client.send(exchange2);
+                exchange2.waitForDone();
+                assertEquals(HttpServletResponse.SC_OK,exchange2.getResponseStatus());
+                long tmp = ((JDBCSessionManager.Session)servlet._session).getLastSaved();
+                assertNotEquals(lastSaved, tmp); //set of attribute will cause save to db
+                lastSaved = tmp;
+                
+                //do nothing for just a bit longer than the save interval to ensure
+                //session will be checked against database on next request
+                Thread.currentThread().sleep((SAVE+2)*1000);
+             
+                
+                //do another request to access the session, this will cause session to be initially
+                //checked against db. On exit of request, the access time will need updating, so the
+                //session will be saved to db.
+                ContentExchange exchange3 = new ContentExchange(true);
+                exchange3.setMethod(HttpMethods.GET);
+                exchange3.setURL("http://localhost:" + port + "/mod/test?action=tickle");
+                exchange3.getRequestFields().add("Cookie", sessionCookie);
+                client.send(exchange3);
+                exchange3.waitForDone();
+                assertEquals(HttpServletResponse.SC_OK,exchange3.getResponseStatus());
+                tmp = ((JDBCSessionManager.Session)servlet._session).getLastSaved();
+                assertNotEquals(lastSaved, tmp);
+                lastSaved = tmp;
+              
+                //wait a little and do another request to access the session
+                Thread.currentThread().sleep((SAVE/2)*1000);
+                
+                //do another request to access the session. This time, the save interval has not
+                //expired, so we should NOT see a debug trace of loading stale session. Nor should
+                //the exit of the request cause a save of the updated access time.
+                ContentExchange exchange4 = new ContentExchange(true);
+                exchange4.setMethod(HttpMethods.GET);
+                exchange4.setURL("http://localhost:" + port + "/mod/test?action=tickle");
+                exchange4.getRequestFields().add("Cookie", sessionCookie);
+                client.send(exchange3);
+                exchange4.waitForDone();
+                assertEquals(HttpServletResponse.SC_OK,exchange4.getResponseStatus());
+                tmp = ((JDBCSessionManager.Session)servlet._session).getLastSaved();
+                assertEquals(lastSaved, tmp); //the save interval did not expire, so update to the access time will not have been persisted
+            }
+            finally
+            {
+                client.stop();
+            }
+        }
+        finally
+        {
+            server.stop();
+        }  
+    }
+    
+    public static class TestSaveIntervalServlet extends HttpServlet
+    {
+        public HttpSession _session;
+        
+        
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            String action = request.getParameter("action");
+            
+            
+            if ("create".equals(action))
+            {
+                HttpSession session = request.getSession(true);
+                System.err.println("CREATE: Session id="+session.getId());
+                _session = session;
+                return;
+            }
+            
+            if ("set".equals(action))
+            {
+                HttpSession session = request.getSession(false);
+                if (session == null)
+                    throw new ServletException("Session is null for action=change");
+               
+                System.err.println("SET: Session id="+session.getId());
+                session.setAttribute("aaa", "12345");
+                assertEquals(_session.getId(), session.getId());
+                return;
+            }
+            
+            if ("tickle".equals(action))
+            {
+                HttpSession session = request.getSession(false);
+                if (session == null)
+                    throw new ServletException("Session does not exist");
+                System.err.println("TICKLE: Session id="+session.getId());
+                assertEquals(_session.getId(), session.getId());
+                return;
+            }
+        }
+    }
+    
+}
diff --git a/tests/test-sessions/test-mongodb-sessions/pom.xml b/tests/test-sessions/test-mongodb-sessions/pom.xml
index 7fa95c6..f98a290 100644
--- a/tests/test-sessions/test-mongodb-sessions/pom.xml
+++ b/tests/test-sessions/test-mongodb-sessions/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-sessions-parent</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-mongodb-sessions</artifactId>
   <name>Jetty Tests :: Sessions :: Mongo</name>
diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml
index 7e95511..980af41 100644
--- a/tests/test-sessions/test-sessions-common/pom.xml
+++ b/tests/test-sessions/test-sessions-common/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-sessions-parent</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-sessions-common</artifactId>
   <name>Jetty Tests :: Sessions :: Common</name>
diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml
index 649dd7a..af4877c 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>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-webapps-parent</artifactId>
   <name>Jetty Tests :: WebApps :: Parent</name>
diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml
index 7ba60af..92f4b3c 100644
--- a/tests/test-webapps/test-webapp-rfc2616/pom.xml
+++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>7.6.19-SNAPSHOT</version>
+    <version>8.1.19-SNAPSHOT</version>
   </parent>
   <artifactId>test-webapp-rfc2616</artifactId>
   <name>Jetty Tests :: WebApp :: RFC2616</name>