(refs #1101)Fix Batch API url mapping

This commit is contained in:
Naoki Takezoe
2017-01-04 06:17:35 +09:00
parent 30c8d3c39c
commit bfc88a489a
3 changed files with 91 additions and 112 deletions

View File

@@ -1,96 +0,0 @@
package gitbucket.core.servlet
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}
import org.json4s._
import org.json4s.jackson.Serialization.{read, write}
import java.util.Date
import gitbucket.core.service.SystemSettingsService
/**
* Provides GitLFS Batch API.
*
* https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md
*/
class GitLfsBatchServlet extends HttpServlet with SystemSettingsService {
private implicit val jsonFormats = gitbucket.core.api.JsonFormat.jsonFormats
override protected def doPost(req: HttpServletRequest, res: HttpServletResponse): Unit = {
val batchRequest = read[BatchRequest](req.getInputStream)
val settings = loadSystemSettings()
settings.lfs.serverUrl match {
case None =>
throw new IllegalStateException("lfs.server_url is not configured.")
case Some(serverUrl) =>
val batchResponse = batchRequest.operation match {
case "upload" =>
BatchUploadResponse("basic", batchRequest.objects.map { requestObject =>
BatchResponseObject(requestObject.oid, requestObject.size, true,
Actions(
upload = Some(Action(
href = serverUrl + "/" + requestObject.oid,
expires_at = new Date(System.currentTimeMillis + 60000L)
))
)
)
})
case "download" =>
BatchUploadResponse("basic", batchRequest.objects.map { requestObject =>
BatchResponseObject(requestObject.oid, requestObject.size, true,
Actions(
download = Some(Action(
href = serverUrl + "/" + requestObject.oid,
expires_at = new Date(System.currentTimeMillis + 60000L)
))
)
)
})
}
res.setContentType("application/vnd.git-lfs+json")
val out = res.getWriter
out.print(write(batchResponse))
out.flush()
}
}
}
case class BatchRequest(
operation: String,
transfers: Seq[String],
objects: Seq[BatchRequestObject]
)
case class BatchRequestObject(
oid: String,
size: Long
)
case class BatchUploadResponse(
transfer: String,
objects: Seq[BatchResponseObject]
)
case class BatchResponseObject(
oid: String,
size: Long,
authenticated: Boolean,
actions: Actions
)
case class Actions(
download: Option[Action] = None,
upload: Option[Action] = None
)
case class Action(
href: String,
header: Map[String, String] = Map.empty,
expires_at: Date
)

View File

@@ -1,6 +1,7 @@
package gitbucket.core.servlet
import java.io.File
import java.util.Date
import gitbucket.core.api
import gitbucket.core.model.{Session, WebHook}
@@ -11,16 +12,16 @@ import gitbucket.core.service._
import gitbucket.core.util.ControlUtil._
import gitbucket.core.util.Implicits._
import gitbucket.core.util._
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.http.server.GitServlet
import org.eclipse.jgit.lib._
import org.eclipse.jgit.transport._
import org.eclipse.jgit.transport.resolver._
import org.slf4j.LoggerFactory
import javax.servlet.ServletConfig
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
import org.json4s.jackson.Serialization._
/**
@@ -32,7 +33,8 @@ import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
class GitRepositoryServlet extends GitServlet with SystemSettingsService {
private val logger = LoggerFactory.getLogger(classOf[GitRepositoryServlet])
private implicit val jsonFormats = gitbucket.core.api.JsonFormat.jsonFormats
override def init(config: ServletConfig): Unit = {
setReceivePackFactory(new GitBucketReceivePackFactory())
@@ -45,15 +47,61 @@ class GitRepositoryServlet extends GitServlet with SystemSettingsService {
override def service(req: HttpServletRequest, res: HttpServletResponse): Unit = {
val agent = req.getHeader("USER-AGENT")
val index = req.getRequestURI.indexOf(".git")
if(index >= 0 && (agent == null || agent.toLowerCase.indexOf("git/") < 0)){
if(index >= 0 && (agent == null || agent.toLowerCase.indexOf("git") < 0)){
// redirect for browsers
val paths = req.getRequestURI.substring(0, index).split("/")
res.sendRedirect(baseUrl(req) + "/" + paths.dropRight(1).last + "/" + paths.last)
} else if(req.getMethod.toUpperCase == "POST" && req.getRequestURI.endsWith("/info/lfs/objects/batch")){
serviceGitLfsBatchAPI(req, res)
} else {
// response for git client
super.service(req, res)
}
}
protected def serviceGitLfsBatchAPI(req: HttpServletRequest, res: HttpServletResponse): Unit = {
val batchRequest = read[GitLfs.BatchRequest](req.getInputStream)
val settings = loadSystemSettings()
settings.lfs.serverUrl match {
case None =>
throw new IllegalStateException("lfs.server_url is not configured.")
case Some(serverUrl) =>
val batchResponse = batchRequest.operation match {
case "upload" =>
GitLfs.BatchUploadResponse("basic", batchRequest.objects.map { requestObject =>
GitLfs.BatchResponseObject(requestObject.oid, requestObject.size, true,
GitLfs.Actions(
upload = Some(GitLfs.Action(
href = serverUrl + "/" + requestObject.oid,
expires_at = new Date(System.currentTimeMillis + 60000L)
))
)
)
})
case "download" =>
GitLfs.BatchUploadResponse("basic", batchRequest.objects.map { requestObject =>
GitLfs.BatchResponseObject(requestObject.oid, requestObject.size, true,
GitLfs.Actions(
download = Some(GitLfs.Action(
href = serverUrl + "/" + requestObject.oid,
expires_at = new Date(System.currentTimeMillis + 60000L)
))
)
)
})
}
res.setContentType("application/vnd.git-lfs+json")
val out = res.getWriter
out.print(write(batchResponse))
out.flush()
}
}
}
class GitBucketRepositoryResolver(parent: FileResolver[HttpServletRequest]) extends RepositoryResolver[HttpServletRequest] {
@@ -232,3 +280,41 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
}
}
object GitLfs {
case class BatchRequest(
operation: String,
transfers: Seq[String],
objects: Seq[BatchRequestObject]
)
case class BatchRequestObject(
oid: String,
size: Long
)
case class BatchUploadResponse(
transfer: String,
objects: Seq[BatchResponseObject]
)
case class BatchResponseObject(
oid: String,
size: Long,
authenticated: Boolean,
actions: Actions
)
case class Actions(
download: Option[Action] = None,
upload: Option[Action] = None
)
case class Action(
href: String,
header: Map[String, String] = Map.empty,
expires_at: Date
)
}

View File

@@ -46,17 +46,6 @@
<url-pattern>/git/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>GitLfsBatchServlet</servlet-name>
<servlet-class>gitbucket.core.servlet.GitLfsBatchServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>GitLfsBatchServlet</servlet-name>
<url-pattern>/git/root/git-lfs-test.git/info/lfs/*</url-pattern>
</servlet-mapping>
<!-- ===================================================================== -->
<!-- Supply assets which are provided by plugins -->
<!-- ===================================================================== -->