From 772ac80764e1d2a0f39d02f76125f316e3b79cac Mon Sep 17 00:00:00 2001 From: Hidetake Iwata Date: Wed, 16 Aug 2017 00:19:12 +0900 Subject: [PATCH 1/2] Improve GitHub compatible URL --- .../GHCompatRepositoryAccessFilter.scala | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/main/scala/gitbucket/core/servlet/GHCompatRepositoryAccessFilter.scala b/src/main/scala/gitbucket/core/servlet/GHCompatRepositoryAccessFilter.scala index 0a190606c..7fa5fc9aa 100644 --- a/src/main/scala/gitbucket/core/servlet/GHCompatRepositoryAccessFilter.scala +++ b/src/main/scala/gitbucket/core/servlet/GHCompatRepositoryAccessFilter.scala @@ -4,35 +4,33 @@ 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 { - /** - * Pattern of GitHub compatible repository URL. - * /:user/:repo.git/ - */ - private val githubRepositoryPattern = """^/[^/]+/[^/]+\.git/.*""".r + override def init(filterConfig: FilterConfig): Unit = {} - override def init(filterConfig: FilterConfig) = {} + 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) - override def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) = { - implicit val request = req.asInstanceOf[HttpServletRequest] - val agent = request.getHeader("USER-AGENT") - val response = res.asInstanceOf[HttpServletResponse] - val requestPath = request.getRequestURI.substring(request.getContextPath.length) - val queryString = if (request.getQueryString != null) "?" + request.getQueryString else "" - - requestPath match { - case githubRepositoryPattern() if agent != null && agent.toLowerCase.indexOf("git") >= 0 => - response.sendRedirect(baseUrl + "/git" + requestPath + queryString) - case _ => - chain.doFilter(req, res) + case _ => chain.doFilter(req, res) } } - override def destroy() = {} + 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 = {} } From e208dd596613ddc643b7da1100cc52aaa2fbeffc Mon Sep 17 00:00:00 2001 From: Hidetake Iwata Date: Fri, 18 Aug 2017 18:55:05 +0900 Subject: [PATCH 2/2] Implement as controller instead of filter --- src/main/scala/ScalatraBootstrap.scala | 3 +- .../GitHubCompatibleAccessController.scala | 29 +++++++++++++++ .../GHCompatRepositoryAccessFilter.scala | 36 ------------------- 3 files changed, 30 insertions(+), 38 deletions(-) create mode 100644 src/main/scala/gitbucket/core/controller/GitHubCompatibleAccessController.scala delete mode 100644 src/main/scala/gitbucket/core/servlet/GHCompatRepositoryAccessFilter.scala diff --git a/src/main/scala/ScalatraBootstrap.scala b/src/main/scala/ScalatraBootstrap.scala index 7bc40ca37..e2749a2eb 100644 --- a/src/main/scala/ScalatraBootstrap.scala +++ b/src/main/scala/ScalatraBootstrap.scala @@ -25,10 +25,9 @@ class ScalatraBootstrap extends LifeCycle with SystemSettingsService { 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 000000000..2bd9abb71 --- /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. + * + * + */ +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 7fa5fc9aa..000000000 --- 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 = {} - -}