Merge pull request #125 from hboutemy/FELIX-6494

[FELIX-6494] add version to Created-By entry
diff --git a/http/base/pom.xml b/http/base/pom.xml
index 1924c90..84db8e3 100644
--- a/http/base/pom.xml
+++ b/http/base/pom.xml
@@ -46,6 +46,7 @@
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
+            <version>4.0.1</version>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
@@ -78,7 +79,7 @@
         <dependency>
             <groupId>commons-fileupload</groupId>
             <artifactId>commons-fileupload</artifactId>
-            <version>1.3.3</version>
+            <version>1.4</version>
             <scope>provided</scope>
         </dependency>
     </dependencies>
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
index 9c2fb35..47efa9b 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
@@ -75,7 +75,7 @@
         if ( mgr == null )
         {
             // not active, always return 404
-            if ( !res.isCommitted() ) 
+            if ( !res.isCommitted() )
             {
                 res.sendError(404);
             }
@@ -126,7 +126,7 @@
 		        final HttpServletResponse wrappedResponse = new ServletResponseWrapper(req, res, servletName, errorRegistry);
 		        if ( pr == null )
 		        {
-                    if ( !wrappedResponse.isCommitted() ) 
+                    if ( !wrappedResponse.isCommitted() )
                     {
                         wrappedResponse.sendError(404);
                     }
@@ -134,8 +134,7 @@
 		        }
 
 		        final ExtServletContext servletContext = pr.handler.getContext();
-		        final RequestInfo requestInfo = new RequestInfo(pr.servletPath, pr.pathInfo, null, req.getRequestURI());
-
+		        final RequestInfo requestInfo = new RequestInfo(pr.servletPath, pr.pathInfo, null, req.getRequestURI(), pr.handler.getName(), pr.matchedPattern, false);
 		        final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo, null,
 		                pr.handler.getServletInfo().isAsyncSupported(),
 		                pr.handler.getMultipartConfig(),
@@ -158,7 +157,7 @@
 		            req.setAttribute(RequestDispatcher.ERROR_EXCEPTION, e);
 		            req.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, e.getClass().getName());
 
-                    if ( !wrappedResponse.isCommitted() ) 
+                    if ( !wrappedResponse.isCommitted() )
                     {
                         wrappedResponse.sendError(500);
                     }
@@ -169,7 +168,8 @@
 		            {
 		                servletContext.getServletRequestListener().requestDestroyed(new ServletRequestEvent(servletContext, wrappedRequest));
 		            }
-		        }			}
+		        }
+		    }
 
 			@Override
 			public void destroy()
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
index 34427b2..ea9813c 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
@@ -29,6 +29,7 @@
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.registry.ServletResolution;
 import org.apache.felix.http.base.internal.util.UriUtils;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Wrapper implementation for {@link RequestDispatcher}.
@@ -38,8 +39,13 @@
     private final RequestInfo requestInfo;
     private final ServletResolution resolution;
 
-    public RequestDispatcherImpl(final ServletResolution resolution,
-            final RequestInfo requestInfo)
+    /**
+     * Create new dispatcher
+     * @param resolution The resolution
+     * @param requestInfo The request info
+     */
+    public RequestDispatcherImpl(@NotNull final ServletResolution resolution,
+            @NotNull final RequestInfo requestInfo)
     {
         this.resolution = resolution;
         this.requestInfo = requestInfo;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
index c9112dc..1b63f4f 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
@@ -16,22 +16,74 @@
  */
 package org.apache.felix.http.base.internal.dispatch;
 
-public final class RequestInfo
+import javax.servlet.http.HttpServletMapping;
+import javax.servlet.http.MappingMatch;
+
+/**
+ * Information about the request
+ */
+public final class RequestInfo implements HttpServletMapping
 {
     final String servletPath;
     final String pathInfo;
     final String queryString;
     final String requestURI;
+    private final String servletName;
+    private final String servletPattern;
+    private final MappingMatch match;
+    final boolean nameMatch;
 
+    /**
+     * Create a new request info
+     * @param servletPath The servlet path
+     * @param pathInfo The path info
+     * @param queryString The query string
+     * @param requestURI The request uri
+     * @param servletName The servlet name
+     * @param servletPattern The servlet pattern
+     * @param nameMatch Is named dispatcher
+     */
     public RequestInfo(final String servletPath,
             final String pathInfo,
             final String queryString,
-            final String requestURI)
+            final String requestURI,
+            final String servletName,
+            final String servletPattern,
+            final boolean nameMatch)
     {
         this.servletPath = servletPath;
         this.pathInfo = pathInfo;
         this.queryString = queryString;
         this.requestURI = requestURI;
+        this.servletName = servletName;
+        this.servletPattern = servletPattern;
+        if ( "".equals(servletPattern) ) {
+            this.match = MappingMatch.DEFAULT;
+        } else {
+            this.match = MappingMatch.PATH;
+        }
+        this.nameMatch = nameMatch;
+    }
+
+    @Override
+    public String getMatchValue() {
+        // TODO - this is wrong
+        return this.servletPattern;
+    }
+
+    @Override
+    public String getPattern() {
+        return this.servletPattern;
+    }
+
+    @Override
+    public String getServletName() {
+        return this.servletName;
+    }
+
+    @Override
+    public MappingMatch getMappingMatch() {
+        return this.match;
     }
 
     @Override
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
index 09b98b6..0c676c5 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
@@ -17,11 +17,13 @@
 package org.apache.felix.http.base.internal.dispatch;
 
 import static javax.servlet.RequestDispatcher.FORWARD_CONTEXT_PATH;
+import static javax.servlet.RequestDispatcher.FORWARD_MAPPING;
 import static javax.servlet.RequestDispatcher.FORWARD_PATH_INFO;
 import static javax.servlet.RequestDispatcher.FORWARD_QUERY_STRING;
 import static javax.servlet.RequestDispatcher.FORWARD_REQUEST_URI;
 import static javax.servlet.RequestDispatcher.FORWARD_SERVLET_PATH;
 import static javax.servlet.RequestDispatcher.INCLUDE_CONTEXT_PATH;
+import static javax.servlet.RequestDispatcher.INCLUDE_MAPPING;
 import static javax.servlet.RequestDispatcher.INCLUDE_PATH_INFO;
 import static javax.servlet.RequestDispatcher.INCLUDE_QUERY_STRING;
 import static javax.servlet.RequestDispatcher.INCLUDE_REQUEST_URI;
@@ -35,6 +37,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
@@ -47,6 +50,7 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletRequestAttributeEvent;
 import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletMapping;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpSession;
@@ -65,6 +69,11 @@
 
 final class ServletRequestWrapper extends HttpServletRequestWrapper
 {
+    private static final List<String> FORBIDDEN_ATTRIBUTES = Arrays.asList(FORWARD_CONTEXT_PATH,
+            FORWARD_MAPPING, FORWARD_PATH_INFO, FORWARD_QUERY_STRING, FORWARD_REQUEST_URI, FORWARD_SERVLET_PATH,
+            INCLUDE_CONTEXT_PATH, INCLUDE_MAPPING, INCLUDE_PATH_INFO, INCLUDE_QUERY_STRING, INCLUDE_REQUEST_URI,
+            INCLUDE_SERVLET_PATH);
+
     private final DispatcherType type;
     private final RequestInfo requestInfo;
     private final ExtServletContext servletContext;
@@ -96,7 +105,7 @@
     public Object getAttribute(String name)
     {
         HttpServletRequest request = (HttpServletRequest) getRequest();
-        if (isInclusionDispatcher())
+        if (isInclusionDispatcher() && !this.requestInfo.nameMatch)
         {
             // The javax.servlet.include.* attributes refer to the information of the *included* request,
             // meaning that the request information comes from the *original* request...
@@ -120,8 +129,12 @@
             {
                 return this.requestInfo.queryString;
             }
+            else if (INCLUDE_MAPPING.equals(name))
+            {
+                return this.requestInfo;
+            }
         }
-        else if (isForwardingDispatcher())
+        else if (isForwardingDispatcher() && !this.requestInfo.nameMatch)
         {
             // The javax.servlet.forward.* attributes refer to the information of the *original* request,
             // meaning that the request information comes from the *forwarded* request...
@@ -145,6 +158,13 @@
             {
                 return super.getQueryString();
             }
+            else if (FORWARD_MAPPING.equals(name))
+            {
+                return super.getHttpServletMapping();
+            }
+        }
+        if ( FORBIDDEN_ATTRIBUTES.contains(name) ) {
+            return null;
         }
         return super.getAttribute(name);
     }
@@ -322,12 +342,12 @@
 
     private boolean isForwardingDispatcher()
     {
-        return (DispatcherType.FORWARD == this.type) && (this.requestInfo != null);
+        return DispatcherType.FORWARD == this.type;
     }
 
     private boolean isInclusionDispatcher()
     {
-        return (DispatcherType.INCLUDE == this.type) && (this.requestInfo != null);
+        return DispatcherType.INCLUDE == this.type;
     }
 
     @Override
@@ -537,4 +557,8 @@
         return null;
     }
 
+    @Override
+    public HttpServletMapping getHttpServletMapping() {
+        return this.requestInfo;
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
index 8c61d7f..28e9071 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
@@ -19,8 +19,6 @@
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.annotations.NotNull;
 import javax.servlet.DispatcherType;
 import javax.servlet.FilterChain;
 import javax.servlet.RequestDispatcher;
@@ -32,6 +30,8 @@
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 final class ServletResponseWrapper extends HttpServletResponseWrapper
 {
@@ -86,7 +86,7 @@
                 {
                     try
                     {
-                        request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, new Integer(code));
+                        request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, code);
                         if ( message != null )
                         {
                             request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
@@ -101,7 +101,7 @@
                         final String pathInfo = request.getRequestURI();
                         final String queryString = null; // XXX
 
-                        final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString, pathInfo);
+                        final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString, pathInfo, request.getHttpServletMapping().getServletName(), request.getHttpServletMapping().getPattern(), false);
 
                         final FilterHandler[] filterHandlers = errorRegistry.getFilterHandlers(errorResolution, DispatcherType.ERROR, request.getRequestURI());
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
index 8287f33..696c931 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
@@ -16,7 +16,9 @@
  */
 package org.apache.felix.http.base.internal.registry;
 
-
+/**
+ * Resolution of a servlet based on the path
+ */
 public class PathResolution extends ServletResolution {
 
     public String servletPath;
@@ -26,4 +28,6 @@
     public String requestURI;
 
     public String[] patterns;
+
+    public String matchedPattern;
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
index e849278..ef40fa6 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
@@ -29,13 +29,12 @@
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 
-import org.jetbrains.annotations.NotNull;
-
 import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.apache.felix.http.base.internal.runtime.dto.BuilderConstants;
 import org.apache.felix.http.base.internal.runtime.dto.ResourceDTOBuilder;
 import org.apache.felix.http.base.internal.runtime.dto.ServletDTOBuilder;
+import org.jetbrains.annotations.NotNull;
 import org.osgi.service.http.runtime.dto.DTOConstants;
 import org.osgi.service.http.runtime.dto.FailedResourceDTO;
 import org.osgi.service.http.runtime.dto.FailedServletDTO;
@@ -81,6 +80,7 @@
             {
                 // TODO - we should have all patterns under which this servlet is actively registered
                 pr.patterns = new String[] {entry.getPattern()};
+                pr.matchedPattern = entry.getPattern();
                 return pr;
             }
         }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
index 668a935..7611f48 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
@@ -76,30 +76,6 @@
         this.types = names.toArray(new String[names.size()]);
     }
 
-    /**
-     * Constructor for Apache Felix proprietary listener support
-     * @param ref The service reference
-     * @param marker Just a marker parameter to distinguish from other constructor
-     */
-    public ListenerInfo(final ServiceReference<EventListener> ref, final boolean marker)
-    {
-        super(ref);
-        this.enabled = true;
-        final String[] objectClass = (String[])ref.getProperty(Constants.OBJECTCLASS);
-        final Set<String> names = new HashSet<String>();
-        for(final String name : objectClass)
-        {
-            if ( ALLOWED_INTERFACES.contains(name) )
-            {
-                names.add(name);
-            }
-        }
-        // remove interfaces not supported by Felix whiteboard
-        names.remove(HttpSessionIdListener.class.getName());
-        names.remove(ServletContextListener.class.getName());
-        this.types = names.toArray(new String[names.size()]);
-    }
-
     @Override
     public boolean isValid()
     {
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
index 9e9b499..fddff41 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
@@ -38,6 +38,7 @@
 import javax.servlet.ServletContextAttributeEvent;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRegistration.Dynamic;
 import javax.servlet.ServletRequestAttributeListener;
 import javax.servlet.ServletRequestListener;
 import javax.servlet.SessionCookieConfig;
@@ -508,7 +509,7 @@
         	resolution.handler = servletHandler;
             resolution.handlerRegistry = this.handlerRegistry;
             // TODO - what is the path of a named servlet?
-            final RequestInfo requestInfo = new RequestInfo("", null, null, null);
+            final RequestInfo requestInfo = new RequestInfo("", null, null, null, null, "", true);
             dispatcher = new RequestDispatcherImpl(resolution, requestInfo);
         }
         else
@@ -542,11 +543,10 @@
         final PathResolution pathResolution = this.handlerRegistry.resolve(requestURI);
         if ( pathResolution != null )
         {
-        	final ServletResolution resolution = new ServletResolution();
-        	resolution.handler = pathResolution.handler;
-            resolution.handlerRegistry = this.handlerRegistry;
-            final RequestInfo requestInfo = new RequestInfo(pathResolution.servletPath, pathResolution.pathInfo, query, UriUtils.concat(this.getContextPath(), encodedRequestURI));
-            dispatcher = new RequestDispatcherImpl(resolution, requestInfo);
+            pathResolution.handlerRegistry = this.handlerRegistry;
+            final RequestInfo requestInfo = new RequestInfo(pathResolution.servletPath, pathResolution.pathInfo, query, UriUtils.concat(this.getContextPath(), encodedRequestURI),
+                    pathResolution.handler.getName(), pathResolution.matchedPattern, false);
+            dispatcher = new RequestDispatcherImpl(pathResolution, requestInfo);
         }
         else
         {
@@ -555,6 +555,42 @@
         return dispatcher;
     }
 
+
+    @Override
+    public Dynamic addJspFile(final String servletName, final String jspFile) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public int getSessionTimeout() {
+        return context.getSessionTimeout();
+    }
+
+    @Override
+    public void setSessionTimeout(final int sessionTimeout) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public String getRequestCharacterEncoding() {
+        return context.getRequestCharacterEncoding();
+    }
+
+    @Override
+    public void setRequestCharacterEncoding(final String encoding) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public String getResponseCharacterEncoding() {
+        return context.getResponseCharacterEncoding();
+    }
+
+    @Override
+    public void setResponseCharacterEncoding(final String encoding) {
+        throw new IllegalStateException();
+    }
+
     @Override
     public HttpConfig getConfig()
     {
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
index 8230270..c3a4d61 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
@@ -461,4 +461,39 @@
     {
         return delegatee.getVirtualServerName();
     }
+
+    @Override
+    public Dynamic addJspFile(final String servletName, final String jspFile) {
+        return this.delegatee.addJspFile(servletName, jspFile);
+    }
+
+    @Override
+    public int getSessionTimeout() {
+        return this.delegatee.getSessionTimeout();
+    }
+
+    @Override
+    public void setSessionTimeout(final int sessionTimeout) {
+        this.delegatee.setSessionTimeout(sessionTimeout);
+    }
+
+    @Override
+    public String getRequestCharacterEncoding() {
+        return this.delegatee.getRequestCharacterEncoding();
+    }
+
+    @Override
+    public void setRequestCharacterEncoding(final String encoding) {
+        this.delegatee.setRequestCharacterEncoding(encoding);
+    }
+
+    @Override
+    public String getResponseCharacterEncoding() {
+        return this.delegatee.getResponseCharacterEncoding();
+    }
+
+    @Override
+    public void setResponseCharacterEncoding(final String encoding) {
+        this.delegatee.setResponseCharacterEncoding(encoding);
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
index f858bdf..5f74092 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
@@ -38,6 +38,7 @@
 import javax.servlet.ServletContextAttributeListener;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRegistration.Dynamic;
 import javax.servlet.SessionCookieConfig;
 import javax.servlet.SessionTrackingMode;
 import javax.servlet.descriptor.JspConfigDescriptor;
@@ -319,7 +320,7 @@
         	resolution.handler = servletHandler;
             resolution.handlerRegistry = this.registry;
             // TODO - what is the path of a named servlet?
-            final RequestInfo requestInfo = new RequestInfo("", null, null, null);
+            final RequestInfo requestInfo = new RequestInfo("", null, null, null, null, "", true);
             dispatcher = new RequestDispatcherImpl(resolution, requestInfo);
         }
         else
@@ -353,12 +354,11 @@
         final PathResolution pathResolution = this.registry.resolve(requestURI);
         if ( pathResolution != null )
         {
-        	final ServletResolution resolution = new ServletResolution();
-        	resolution.handler = pathResolution.handler;
-            resolution.handlerRegistry = this.registry;
+            pathResolution.handlerRegistry = this.registry;
             final RequestInfo requestInfo = new RequestInfo(pathResolution.servletPath, pathResolution.pathInfo, query,
-                    UriUtils.concat(this.contextPath, encodedRequestURI));
-            dispatcher = new RequestDispatcherImpl(resolution, requestInfo);
+                    UriUtils.concat(this.contextPath, encodedRequestURI),
+                    pathResolution.handler.getName(), pathResolution.matchedPattern, false);
+            dispatcher = new RequestDispatcherImpl(pathResolution, requestInfo);
         }
         else
         {
@@ -487,4 +487,39 @@
     {
         throw new IllegalStateException();
     }
+
+    @Override
+    public Dynamic addJspFile(final String servletName, final String jspFile) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public int getSessionTimeout() {
+        return context.getSessionTimeout();
+    }
+
+    @Override
+    public void setSessionTimeout(final int sessionTimeout) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public String getRequestCharacterEncoding() {
+        return context.getRequestCharacterEncoding();
+    }
+
+    @Override
+    public void setRequestCharacterEncoding(final String encoding) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public String getResponseCharacterEncoding() {
+        return context.getResponseCharacterEncoding();
+    }
+
+    @Override
+    public void setResponseCharacterEncoding(final String encoding) {
+        throw new IllegalStateException();
+    }
 }
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
index 24b6523..50dd584 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
@@ -39,6 +39,7 @@
 import javax.servlet.ServletContextAttributeListener;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRegistration.Dynamic;
 import javax.servlet.SessionCookieConfig;
 import javax.servlet.SessionTrackingMode;
 import javax.servlet.descriptor.JspConfigDescriptor;
@@ -453,6 +454,48 @@
         public void setSessionTrackingModes(Set<SessionTrackingMode> modes)
         {
         }
+
+        @Override
+        public Dynamic addJspFile(String servletName, String jspFile) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public int getSessionTimeout() {
+            // TODO Auto-generated method stub
+            return 0;
+        }
+
+        @Override
+        public void setSessionTimeout(int sessionTimeout) {
+            // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public String getRequestCharacterEncoding() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public void setRequestCharacterEncoding(String encoding) {
+            // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public String getResponseCharacterEncoding() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public void setResponseCharacterEncoding(String encoding) {
+            // TODO Auto-generated method stub
+
+        }
     }
 
     private Bundle bundle;
diff --git a/http/bridge/pom.xml b/http/bridge/pom.xml
index dd2b90f..14018ba 100644
--- a/http/bridge/pom.xml
+++ b/http/bridge/pom.xml
@@ -111,6 +111,7 @@
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
+            <version>4.0.1</version>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
@@ -131,7 +132,7 @@
         <dependency>
             <groupId>commons-fileupload</groupId>
             <artifactId>commons-fileupload</artifactId>
-            <version>1.3.3</version>
+            <version>1.4</version>
         </dependency>
         <dependency>
             <groupId>commons-io</groupId>
@@ -141,7 +142,7 @@
         <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.http.base</artifactId>
-            <version>4.1.6</version>
+            <version>4.1.7-SNAPSHOT</version>
         </dependency>
     </dependencies>
 
diff --git a/http/itest/pom.xml b/http/itest/pom.xml
index 4566d3e..444b451 100644
--- a/http/itest/pom.xml
+++ b/http/itest/pom.xml
@@ -34,7 +34,7 @@
         <felix.java.version>8</felix.java.version>
         <pax.exam.version>4.13.1</pax.exam.version>
         <pax.url.aether.version>2.6.2</pax.url.aether.version>
-        <http.servlet.api.version>1.1.2</http.servlet.api.version>
+        <http.servlet.api.version>1.1.5-SNAPSHOT</http.servlet.api.version>
         <http.jetty.version>4.1.15-SNAPSHOT</http.jetty.version>
     </properties>
 
diff --git a/http/jetty/pom.xml b/http/jetty/pom.xml
index 9587234..9972376 100644
--- a/http/jetty/pom.xml
+++ b/http/jetty/pom.xml
@@ -207,7 +207,7 @@
                             osgi.serviceloader;osgi.serviceloader="org.eclipse.jetty.http.HttpFieldPreEncoder"
                         </Provide-Capability>
                         <Require-Capability>
-                            osgi.contract;filter:="(&amp;(osgi.contract=JavaServlet)(version=3.1))",
+                            osgi.contract;filter:="(&amp;(osgi.contract=JavaServlet)(version=4.0))",
                             osgi.extender;filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional,
                             osgi.extender;filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional,
                             osgi.serviceloader;filter:="(osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder)";resolution:=optional;cardinality:=multiple,
@@ -274,7 +274,7 @@
                                 </Provide-Capability>
                                 <!-- We need to override this from the base configuration to exclude the ServiceLoader capabilities -->
                                 <Require-Capability>
-                                    osgi.contract;filter:="(&amp;(osgi.contract=JavaServlet)(version=3.1))"
+                                    osgi.contract;filter:="(&amp;(osgi.contract=JavaServlet)(version=4.0))"
                                 </Require-Capability>
                                 <!-- We need to override this from the base configuration to exclude the ServiceLoader resources -->
                                 <Include-Resource>
@@ -404,7 +404,7 @@
         <dependency>
             <groupId>commons-fileupload</groupId>
             <artifactId>commons-fileupload</artifactId>
-            <version>1.3.3</version>
+            <version>1.4</version>
         </dependency>
         <dependency>
             <groupId>commons-io</groupId>
diff --git a/http/servlet-api/pom.xml b/http/servlet-api/pom.xml
index e291150..97b1543 100644
--- a/http/servlet-api/pom.xml
+++ b/http/servlet-api/pom.xml
@@ -36,6 +36,7 @@
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
+                <version>5.1.3</version>
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
@@ -54,14 +55,19 @@
                             javax.servlet.annotation;
                             javax.servlet.descriptor;
                             javax.servlet.http;
-                                version=3.1
+                                version=3.1,
+                            javax.servlet;
+                            javax.servlet.annotation;
+                            javax.servlet.descriptor;
+                            javax.servlet.http;
+                                version=4.0
                         </Export-Package>
                         <Import-Package>!*</Import-Package>
                         <Provide-Capability>
-                            osgi.contract;osgi.contract="JavaServlet";version:Version="3.1";
+                            osgi.contract;osgi.contract="JavaServlet";version:List&lt;Version&gt;="2.6,3.0,3.1,4.0";
                             uses:="javax.servlet,javax.servlet.http,javax.servlet.descriptor,javax.servlet.annotation"
                         </Provide-Capability>
-						<Embed-Dependency>tomcat-servlet-api;inline=true</Embed-Dependency>
+			<Embed-Dependency>tomcat-servlet-api;inline=true</Embed-Dependency>
                     </instructions>
                     <!-- Skip baselining -->
                     <skip>true</skip>
@@ -74,7 +80,7 @@
         <dependency>
             <groupId>org.apache.tomcat</groupId>
             <artifactId>tomcat-servlet-api</artifactId>
-            <version>8.5.66</version>
+            <version>9.0.56</version>
         </dependency>
     </dependencies>
 
diff --git a/tools/maven-bundle-plugin/src/it/reproducible-manifest/pom.xml b/tools/maven-bundle-plugin/src/it/reproducible-manifest/pom.xml
new file mode 100644
index 0000000..def3e69
--- /dev/null
+++ b/tools/maven-bundle-plugin/src/it/reproducible-manifest/pom.xml
@@ -0,0 +1,70 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.felix.bundleits</groupId>
+  <artifactId>reproducible</artifactId>
+  <version>1-SNAPSHOT</version>
+  <!-- default packaging: jar -->
+
+  <properties>
+    <project.build.outputTimestamp>1</project.build.outputTimestamp>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-compress</artifactId>
+      <version>1.19</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <version>@project.version@</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+        <plugin>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>maven-bundle-plugin</artifactId>
+            <executions>
+                <execution>
+                    <id>bundle-manifest</id>
+                    <goals>
+                        <goal>manifest</goal>
+                    </goals>
+                </execution>
+            </executions>
+        </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/tools/maven-bundle-plugin/src/it/reproducible-manifest/verify.groovy b/tools/maven-bundle-plugin/src/it/reproducible-manifest/verify.groovy
new file mode 100644
index 0000000..08c1c4b
--- /dev/null
+++ b/tools/maven-bundle-plugin/src/it/reproducible-manifest/verify.groovy
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+String manifest = new File( basedir, "target/classes/META-INF/MANIFEST.MF" ).text;
+
+assert !manifest.contains( "Build-Jdk:" )
+assert manifest.contains( "Build-Jdk-Spec:" )
+
+assert !manifest.contains( "Build-By:" )
+
+assert !manifest.contains( "Bnd-LastModified:" )
diff --git a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java
index b3575f7..3a55677 100644
--- a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java
+++ b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java
@@ -470,6 +470,7 @@
             }
 
             // attach bundle to maven project
+            getLog().info("Building bundle: " + jarFile.getPath());
             jarFile.getParentFile().mkdirs();
             builder.getJar().write( jarFile );
 
@@ -545,7 +546,7 @@
 
         if ( new MavenArchiver().parseOutputTimestamp( outputTimestamp ) != null )
         {
-          properties.put( "-reproducible", "true" );
+          properties.put( Constants.REPRODUCIBLE, "true" );
         }
 
         // process overrides from project
diff --git a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java
index b15c26b..e47e3fe 100644
--- a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java
+++ b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java
@@ -47,6 +47,7 @@
 
 import aQute.bnd.osgi.Analyzer;
 import aQute.bnd.osgi.Builder;
+import aQute.bnd.osgi.Constants;
 import aQute.bnd.osgi.Instructions;
 import aQute.bnd.osgi.Jar;
 import aQute.bnd.osgi.Resource;
@@ -318,6 +319,9 @@
         }
         else
         {
+            // FELIX-6495: workaround BND inconsistency: internal jar does not take "-reproducible" flag into account...
+            analyzer.getJar().setReproducible( "true".equals( analyzer.getProperties().getProperty( Constants.REPRODUCIBLE ) ) );
+
             analyzer.mergeManifest( analyzer.getJar().getManifest() );
             analyzer.getJar().setManifest( analyzer.calcManifest() );
         }
@@ -494,7 +498,7 @@
     public static void writeManifest( Manifest manifest, File outputFile, boolean niceManifest,
             BuildContext buildContext, Log log ) throws IOException
     {
-        log.debug("Write manifest to " + outputFile.getPath());
+        log.info("Writing manifest: " + outputFile.getPath());
         outputFile.getParentFile().mkdirs();
 
         try ( ByteArrayOutputStream baos = new ByteArrayOutputStream() )