James Moger
2014-05-23 c828cf2db88956094a31a79741145688876879df
Use Guice-Servlet rather than custom code and expose the Injector

This is a fairly functional variation of Gitblit with one notable
exception:

The security filters are not working properly.

This is a design flaw in Guice that I have reported upstream [1]. The
general idea is that Guice-Servlet filters are not properly wrapping the
ServletRequest. This has historically been a problem for Guice-Servlet
servlets but Google has fixed most of those issues. Unfortunately, all
the same flaws reported against the servlet delegation also exist in
Guice-Servlet filter delegation. :(

[1]: https://code.google.com/p/google-guice/issues/detail?id=807
1 files added
1 files renamed
10 files modified
2 files deleted
577 ■■■■■ changed files
.classpath 1 ●●●● patch | view | raw | blame | history
build.moxie 4 ●●● patch | view | raw | blame | history
gitblit.iml 11 ●●●●● patch | view | raw | blame | history
src/main/java/WEB-INF/web.xml 18 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/guice/CoreModule.java 4 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/guice/GuiceContext.java 86 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/guice/WebModule.java 99 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/manager/GitblitManager.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/manager/IRuntimeManager.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/manager/RuntimeManager.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/servlet/AuthenticationFilter.java 8 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/servlet/GitblitContext.java 81 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/servlet/InjectionContextListener.java 241 ●●●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java 6 ●●●●● patch | view | raw | blame | history
.classpath
@@ -9,6 +9,7 @@
    <classpathentry kind="lib" path="ext/javax.inject-1.jar" sourcepath="ext/src/javax.inject-1.jar" />
    <classpathentry kind="lib" path="ext/aopalliance-1.0.jar" sourcepath="ext/src/aopalliance-1.0.jar" />
    <classpathentry kind="lib" path="ext/guava-16.0.1.jar" sourcepath="ext/src/guava-16.0.1.jar" />
    <classpathentry kind="lib" path="ext/guice-servlet-4.0-beta4.jar" sourcepath="ext/src/guice-servlet-4.0-beta4.jar" />
    <classpathentry kind="lib" path="ext/annotations-12.0.jar" sourcepath="ext/src/annotations-12.0.jar" />
    <classpathentry kind="lib" path="ext/log4j-1.2.17.jar" sourcepath="ext/src/log4j-1.2.17.jar" />
    <classpathentry kind="lib" path="ext/slf4j-api-1.7.7.jar" sourcepath="ext/src/slf4j-api-1.7.7.jar" />
build.moxie
@@ -112,6 +112,7 @@
  wikitext.version : 1.4
  sshd.version: 0.11.1-atlassian-1
  mina.version: 2.0.7
  guice.version : 4.0-beta4
  }
# Dependencies
@@ -127,7 +128,8 @@
dependencies:
# Dagger dependency injection library (annotation processor)
- compile 'com.google.inject:guice:4.0-beta4' :war
- compile 'com.google.inject:guice:${guice.version}' :war
- compile 'com.google.inject.extensions:guice-servlet:${guice.version}' :war
- compile 'com.google.guava:guava:16.0.1' :war
# Standard dependencies
- compile 'com.intellij:annotations:12.0' :war
gitblit.iml
@@ -58,6 +58,17 @@
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="guice-servlet-4.0-beta4.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/guice-servlet-4.0-beta4.jar!/" />
        </CLASSES>
        <JAVADOC />
        <SOURCES>
          <root url="jar://$MODULE_DIR$/ext/src/guice-servlet-4.0-beta4.jar!/" />
        </SOURCES>
      </library>
    </orderEntry>
    <orderEntry type="module-library">
      <library name="annotations-12.0.jar">
        <CLASSES>
          <root url="jar://$MODULE_DIR$/ext/annotations-12.0.jar!/" />
src/main/java/WEB-INF/web.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
<web-app version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd">
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <!-- The base folder is used to specify the root location of your Gitblit data.
    
@@ -32,4 +32,18 @@
    <!-- Gitblit Displayname -->
    <display-name>Gitblit - @gb.version@</display-name>
    <listener>
          <listener-class>com.gitblit.servlet.GitblitContext</listener-class>
    </listener>
    <filter>
        <filter-name>guiceFilter</filter-name>
        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>guiceFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
src/main/java/com/gitblit/guice/CoreModule.java
File was renamed from src/main/java/com/gitblit/guice/GuiceModule.java
@@ -47,12 +47,12 @@
import com.google.inject.Provides;
/**
 * GuiceModule references all injectable objects.
 * CoreModule references all the core business objects.
 *
 * @author James Moger
 *
 */
public class GuiceModule extends AbstractModule {
public class CoreModule extends AbstractModule {
    @Override
    protected void configure() {
src/main/java/com/gitblit/guice/GuiceContext.java
File was deleted
src/main/java/com/gitblit/guice/WebModule.java
New file
@@ -0,0 +1,99 @@
/*
 * Copyright 2014 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit.guice;
import java.util.HashMap;
import java.util.Map;
import com.gitblit.Constants;
import com.gitblit.servlet.BranchGraphServlet;
import com.gitblit.servlet.DownloadZipServlet;
import com.gitblit.servlet.EnforceAuthenticationFilter;
import com.gitblit.servlet.FederationServlet;
import com.gitblit.servlet.GitServlet;
import com.gitblit.servlet.LogoServlet;
import com.gitblit.servlet.PagesServlet;
import com.gitblit.servlet.ProxyFilter;
import com.gitblit.servlet.PtServlet;
import com.gitblit.servlet.RawServlet;
import com.gitblit.servlet.RobotsTxtServlet;
import com.gitblit.servlet.RpcServlet;
import com.gitblit.servlet.SparkleShareInviteServlet;
import com.gitblit.servlet.SyndicationServlet;
import com.gitblit.wicket.GitblitWicketFilter;
import com.google.common.base.Joiner;
import com.google.inject.servlet.ServletModule;
/**
 * Defines all the web servlets & filters.
 *
 * @author James Moger
 *
 */
public class WebModule extends ServletModule {
    final static String ALL = "/*";
    @Override
    protected void configureServlets() {
        // servlets
        serve(fuzzy(Constants.R_PATH), fuzzy(Constants.GIT_PATH)).with(GitServlet.class);
        serve(fuzzy(Constants.RAW_PATH)).with(RawServlet.class);
        serve(fuzzy(Constants.PAGES)).with(PagesServlet.class);
        serve(fuzzy(Constants.RPC_PATH)).with(RpcServlet.class);
        serve(fuzzy(Constants.ZIP_PATH)).with(DownloadZipServlet.class);
        serve(fuzzy(Constants.SYNDICATION_PATH)).with(SyndicationServlet.class);
        serve(fuzzy(Constants.FEDERATION_PATH)).with(FederationServlet.class);
        serve(fuzzy(Constants.SPARKLESHARE_INVITE_PATH)).with(SparkleShareInviteServlet.class);
        serve(fuzzy(Constants.BRANCH_GRAPH_PATH)).with(BranchGraphServlet.class);
        serve(Constants.PT_PATH).with(PtServlet.class);
        serve("/robots.txt").with(RobotsTxtServlet.class);
        serve("/logo.png").with(LogoServlet.class);
        // global filters
        filter(ALL).through(ProxyFilter.class);
        filter(ALL).through(EnforceAuthenticationFilter.class);
        // security filters
//        filter(fuzzy(Constants.R_PATH), fuzzy(Constants.GIT_PATH)).through(GitFilter.class);
//        filter(fuzzy(Constants.RAW_PATH)).through(RawFilter.class);
//        filter(fuzzy(Constants.PAGES)).through(PagesFilter.class);
//        filter(fuzzy(Constants.RPC_PATH)).through(RpcFilter.class);
//        filter(fuzzy(Constants.ZIP_PATH)).through(DownloadZipFilter.class);
//        filter(fuzzy(Constants.SYNDICATION_PATH)).through(SyndicationFilter.class);
        // Wicket
        String toIgnore = Joiner.on(",").join(Constants.R_PATH, Constants.GIT_PATH, Constants.RAW_PATH,
                Constants.PAGES, Constants.RPC_PATH, Constants.ZIP_PATH, Constants.SYNDICATION_PATH,
                Constants.FEDERATION_PATH, Constants.SPARKLESHARE_INVITE_PATH, Constants.BRANCH_GRAPH_PATH,
                Constants.PT_PATH, "/robots.txt", "/logo.png");
        Map<String, String> params = new HashMap<String, String>();
        params.put(GitblitWicketFilter.FILTER_MAPPING_PARAM, ALL);
        params.put(GitblitWicketFilter.IGNORE_PATHS_PARAM, toIgnore);
        filter(ALL).through(GitblitWicketFilter.class, params);
    }
    private String fuzzy(String path) {
        if (path.endsWith(ALL)) {
            return path;
        } else if (path.endsWith("/")) {
            return path + "*";
        }
        return path + ALL;
    }
}
src/main/java/com/gitblit/manager/GitblitManager.java
@@ -87,6 +87,7 @@
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Injector;
/**
 * GitblitManager is an aggregate interface delegate.  It implements all the manager
@@ -656,6 +657,11 @@
        return runtimeManager.getStatus();
    }
    @Override
    public Injector getInjector() {
        return runtimeManager.getInjector();
    }
    /*
     * NOTIFICATION MANAGER
     */
src/main/java/com/gitblit/manager/IRuntimeManager.java
@@ -24,9 +24,12 @@
import com.gitblit.IStoredSettings;
import com.gitblit.models.ServerSettings;
import com.gitblit.models.ServerStatus;
import com.google.inject.Injector;
public interface IRuntimeManager extends IManager {
    Injector getInjector();
    void setBaseFolder(File folder);
    File getBaseFolder();
src/main/java/com/gitblit/manager/RuntimeManager.java
@@ -34,6 +34,7 @@
import com.gitblit.models.ServerStatus;
import com.gitblit.models.SettingModel;
import com.gitblit.utils.StringUtils;
import com.google.inject.Injector;
public class RuntimeManager implements IRuntimeManager {
@@ -48,6 +49,9 @@
    private File baseFolder;
    private TimeZone timezone;
    @Inject
    private Injector injector;
    @Inject
    public RuntimeManager(IStoredSettings settings) {
@@ -78,6 +82,11 @@
    }
    @Override
    public Injector getInjector() {
        return injector;
    }
    @Override
    public File getBaseFolder() {
        return baseFolder;
    }
src/main/java/com/gitblit/servlet/AuthenticationFilter.java
@@ -99,8 +99,12 @@
     * @return url
     */
    protected String getFullUrl(HttpServletRequest httpRequest) {
        String servletUrl = httpRequest.getContextPath() + httpRequest.getServletPath();
        String url = httpRequest.getRequestURI().substring(servletUrl.length());
        String contextPath = httpRequest.getContextPath();
        String servletPath = httpRequest.getServletPath();
        String pathInfo = httpRequest.getPathInfo();
        String servletUrl = contextPath + servletPath;
        String requestURI = httpRequest.getRequestURI();
        String url = requestURI.substring(servletUrl.length());
        String params = httpRequest.getQueryString();
        if (url.length() > 0 && url.charAt(0) == '/') {
            url = url.substring(1);
src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -23,15 +23,17 @@
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
import com.gitblit.FileSettings;
@@ -39,8 +41,8 @@
import com.gitblit.Keys;
import com.gitblit.WebXmlSettings;
import com.gitblit.extensions.LifeCycleListener;
import com.gitblit.guice.GuiceContext;
import com.gitblit.guice.GuiceModule;
import com.gitblit.guice.CoreModule;
import com.gitblit.guice.WebModule;
import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IFederationManager;
import com.gitblit.manager.IGitblit;
@@ -54,9 +56,10 @@
import com.gitblit.transport.ssh.IPublicKeyManager;
import com.gitblit.utils.ContainerUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitblitWicketFilter;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;
/**
 * This class is the main entry point for the entire webapp.  It is a singleton
@@ -70,9 +73,11 @@
 *
 */
@WebListener
public class GitblitContext extends GuiceContext {
public class GitblitContext extends GuiceServletContextListener {
    private static GitblitContext gitblit;
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    private final List<IManager> managers = new ArrayList<IManager>();
@@ -115,20 +120,37 @@
        return null;
    }
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(getModules());
    }
    /**
     * Returns Gitblit's Guice injection modules.
     */
    @Override
    protected AbstractModule [] getModules() {
        return new AbstractModule [] { new GuiceModule() };
        return new AbstractModule [] { new CoreModule(), new WebModule() };
    }
    /**
     * Configure Gitblit from the web.xml, if no configuration has already been
     * specified.
     *
     * @see ServletContextListener.contextInitialize(ServletContextEvent)
     */
    @Override
    public final void contextInitialized(ServletContextEvent contextEvent) {
        super.contextInitialized(contextEvent);
        ServletContext context = contextEvent.getServletContext();
        startCore(context);
    }
    /**
     * Prepare runtime settings and start all manager instances.
     */
    @Override
    protected void beforeServletInjection(ServletContext context) {
        Injector injector = getInjector(context);
    protected void startCore(ServletContext context) {
        Injector injector = (Injector) context.getAttribute(Injector.class.getName());
        // create the runtime settings object
        IStoredSettings runtimeSettings = injector.getInstance(IStoredSettings.class);
@@ -229,46 +251,17 @@
        logger.info("----[{}]----", clazz.getName());
    }
    /**
     * Instantiate and inject all filters and servlets into the container using
     * the servlet 3 specification.
     */
    @Override
    protected void injectServlets(ServletContext context) {
        // access restricted servlets
        serve(context, Constants.R_PATH, GitServlet.class, GitFilter.class);
        serve(context, Constants.GIT_PATH, GitServlet.class, GitFilter.class);
        serve(context, Constants.RAW_PATH, RawServlet.class, RawFilter.class);
        serve(context, Constants.PAGES, PagesServlet.class, PagesFilter.class);
        serve(context, Constants.RPC_PATH, RpcServlet.class, RpcFilter.class);
        serve(context, Constants.ZIP_PATH, DownloadZipServlet.class, DownloadZipFilter.class);
        serve(context, Constants.SYNDICATION_PATH, SyndicationServlet.class, SyndicationFilter.class);
        // servlets
        serve(context, Constants.FEDERATION_PATH, FederationServlet.class);
        serve(context, Constants.SPARKLESHARE_INVITE_PATH, SparkleShareInviteServlet.class);
        serve(context, Constants.BRANCH_GRAPH_PATH, BranchGraphServlet.class);
        serve(context, Constants.PT_PATH, PtServlet.class);
        file(context, "/robots.txt", RobotsTxtServlet.class);
        file(context, "/logo.png", LogoServlet.class);
        // global filters
        filter(context, "/*", ProxyFilter.class, null);
        filter(context, "/*", EnforceAuthenticationFilter.class, null);
        // Wicket
        String toIgnore = StringUtils.flattenStrings(getRegisteredPaths(), ",");
        Map<String, String> params = new HashMap<String, String>();
        params.put(GitblitWicketFilter.FILTER_MAPPING_PARAM, "/*");
        params.put(GitblitWicketFilter.IGNORE_PATHS_PARAM, toIgnore);
        filter(context, "/*", GitblitWicketFilter.class, params);
    public final void contextDestroyed(ServletContextEvent contextEvent) {
        super.contextDestroyed(contextEvent);
        ServletContext context = contextEvent.getServletContext();
        destroyContext(context);
    }
    /**
     * Gitblit is being shutdown either because the servlet container is
     * shutting down or because the servlet container is re-deploying Gitblit.
     */
    @Override
    protected void destroyContext(ServletContext context) {
        logger.info("Gitblit context destroyed by servlet container.");
src/main/java/com/gitblit/servlet/InjectionContextListener.java
File was deleted
src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
@@ -28,6 +28,7 @@
import com.gitblit.models.ServerSettings;
import com.gitblit.models.ServerStatus;
import com.gitblit.models.SettingModel;
import com.google.inject.Injector;
public class MockRuntimeManager implements IRuntimeManager {
@@ -57,6 +58,11 @@
    }
    @Override
    public Injector getInjector() {
        return null;
    }
    @Override
    public void setBaseFolder(File folder) {
        this.baseFolder = folder;
    }