diff --git a/src/main/scala/gitbucket/core/servlet/GitLfsBatchServlet.scala b/src/main/scala/gitbucket/core/servlet/GitLfsBatchServlet.scala
new file mode 100644
index 0000000..d592299
--- /dev/null
+++ b/src/main/scala/gitbucket/core/servlet/GitLfsBatchServlet.scala
@@ -0,0 +1,97 @@
+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
+
+/**
+ * Provides GitLFS Batch API.
+ *
+ * https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md
+ */
+class GitLfsBatchServlet extends HttpServlet {
+
+ // TODO GitLFS server url must be configurable
+ private val GitLfsServerUrl = "http://localhost:9090/git-lfs"
+
+ 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 batchResponse = batchRequest.operation match {
+ case "upload" =>
+ BatchUploadResponse("basic", batchRequest.objects.map { requestObject =>
+ BatchResponseObject(
+ requestObject.oid,
+ requestObject.size,
+ true,
+ Actions(
+ upload = Some(Action(
+ href = GitLfsServerUrl + "/" + requestObject.oid,
+ expires_at = new Date(System.currentTimeMillis + 60000)
+ ))
+ )
+ )
+ })
+ case "download" =>
+ BatchUploadResponse("basic", batchRequest.objects.map { requestObject =>
+ BatchResponseObject(
+ requestObject.oid,
+ requestObject.size,
+ true,
+ Actions(
+ download = Some(Action(
+ href = GitLfsServerUrl + "/" + requestObject.oid,
+ expires_at = new Date(System.currentTimeMillis + 60000)
+ ))
+ )
+ )
+ })
+ }
+
+ 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
+)
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
index 9634066..066f99f 100644
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -46,6 +46,17 @@
/git/*
+
+ GitLfsBatchServlet
+ gitbucket.core.servlet.GitLfsBatchServlet
+ true
+
+
+
+ GitLfsBatchServlet
+ /git/root/git-lfs-test.git/info/lfs/*
+
+