diff --git a/src/main/scala/ScalatraBootstrap.scala b/src/main/scala/ScalatraBootstrap.scala
index 7bc40ca..e2749a2 100644
--- a/src/main/scala/ScalatraBootstrap.scala
+++ b/src/main/scala/ScalatraBootstrap.scala
@@ -25,10 +25,9 @@
context.getFilterRegistration("gitAuthenticationFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/git/*")
context.addFilter("apiAuthenticationFilter", new ApiAuthenticationFilter)
context.getFilterRegistration("apiAuthenticationFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/api/v3/*")
- context.addFilter("ghCompatRepositoryAccessFilter", new GHCompatRepositoryAccessFilter)
- context.getFilterRegistration("ghCompatRepositoryAccessFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/*")
// Register controllers
+ context.mount(new GitHubCompatibleAccessController, "/*")
context.mount(new AnonymousAccessController, "/*")
context.addFilter("pluginControllerFilter", new PluginControllerFilter)
diff --git a/src/main/scala/gitbucket/core/controller/GitHubCompatibleAccessController.scala b/src/main/scala/gitbucket/core/controller/GitHubCompatibleAccessController.scala
new file mode 100644
index 0000000..2bd9abb
--- /dev/null
+++ b/src/main/scala/gitbucket/core/controller/GitHubCompatibleAccessController.scala
@@ -0,0 +1,29 @@
+package gitbucket.core.controller
+
+import org.scalatra.MovedPermanently
+
+class GitHubCompatibleAccessController extends GitHubCompatibleAccessControllerBase
+
+/**
+ * Provides GitHub compatible URLs for Git client.
+ *
+ *
+ * - git clone http://localhost:8080/owner/repo
+ * - git clone http://localhost:8080/owner/repo.git
+ *
+ */
+trait GitHubCompatibleAccessControllerBase extends ControllerBase {
+ /**
+ * Git client initiates a connection with /info/refs
+ *
+ * @see https://git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols
+ */
+ get("/*/*/info/refs") {
+ redirectToGitServlet()
+ }
+
+ private def redirectToGitServlet(): Unit = {
+ val query = Option(request.getQueryString).map("?" + _).getOrElse("")
+ halt(MovedPermanently(baseUrl + "/git" + request.getRequestURI + query))
+ }
+}
diff --git a/src/main/scala/gitbucket/core/servlet/GHCompatRepositoryAccessFilter.scala b/src/main/scala/gitbucket/core/servlet/GHCompatRepositoryAccessFilter.scala
deleted file mode 100644
index 7fa5fc9..0000000
--- a/src/main/scala/gitbucket/core/servlet/GHCompatRepositoryAccessFilter.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-package gitbucket.core.servlet
-
-import javax.servlet._
-import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
-
-import gitbucket.core.service.SystemSettingsService
-import gitbucket.core.util.Implicits._
-
-/**
- * A controller to provide GitHub compatible URL for Git clients.
- */
-class GHCompatRepositoryAccessFilter extends Filter with SystemSettingsService {
-
- override def init(filterConfig: FilterConfig): Unit = {}
-
- override def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = {
- val request = req.asInstanceOf[HttpServletRequest]
- request.paths match {
- // baseUrl/repositoryOwner/repositoryName/info/refs
- // baseUrl/repositoryOwner/repositoryName.git/info/refs
- case Array(repositoryOwner, repositoryName, "info", "refs", _*) => redirectToGitServlet(req, res)
-
- case _ => chain.doFilter(req, res)
- }
- }
-
- private def redirectToGitServlet(req: ServletRequest, res: ServletResponse): Unit = {
- val request = req.asInstanceOf[HttpServletRequest]
- val response = res.asInstanceOf[HttpServletResponse]
- val query = Option(request.getQueryString).map("?" + _).getOrElse("")
- response.sendRedirect(baseUrl(request) + "/git" + request.getRequestURI + query)
- }
-
- override def destroy(): Unit = {}
-
-}