All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gitbucket.core.servlet.GitLfsTransferServlet.scala Maven / Gradle / Ivy

package gitbucket.core.servlet

import java.io.{File, FileInputStream, FileOutputStream}
import java.text.MessageFormat
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}

import gitbucket.core.util.{FileUtil, StringUtil}
import org.apache.commons.io.{FileUtils, IOUtils}
import org.json4s.jackson.Serialization._
import org.apache.http.HttpStatus
import gitbucket.core.util.SyntaxSugars._

/**
 * Provides GitLFS Transfer API
 * https://github.com/git-lfs/git-lfs/blob/master/docs/api/basic-transfers.md
 */
class GitLfsTransferServlet extends HttpServlet {

  private implicit val jsonFormats = gitbucket.core.api.JsonFormat.jsonFormats
  private val LongObjectIdLength = 32
  private val LongObjectIdStringLength = LongObjectIdLength * 2

  override protected def doGet(req: HttpServletRequest, res: HttpServletResponse): Unit = {
    for {
      (owner, repository, oid) <- getPathInfo(req, res) if checkToken(req, oid)
    } yield {
      val file = new File(FileUtil.getLfsFilePath(owner, repository, oid))
      if(file.exists()){
        res.setStatus(HttpStatus.SC_OK)
        res.setContentType("application/octet-stream")
        res.setContentLength(file.length.toInt)
        using(new FileInputStream(file), res.getOutputStream){ (in, out) =>
          IOUtils.copy(in, out)
          out.flush()
        }
      } else {
        sendError(res, HttpStatus.SC_NOT_FOUND,
          MessageFormat.format("Object ''{0}'' not found", oid))
      }
    }
  }

  override protected def doPut(req: HttpServletRequest, res: HttpServletResponse): Unit = {
    for {
      (owner, repository, oid) <- getPathInfo(req, res) if checkToken(req, oid)
    } yield {
      val file = new File(FileUtil.getLfsFilePath(owner, repository, oid))
      FileUtils.forceMkdir(file.getParentFile)
      using(req.getInputStream, new FileOutputStream(file)){ (in, out) =>
        IOUtils.copy(in, out)
      }
      res.setStatus(HttpStatus.SC_OK)
    }
  }

  private def checkToken(req: HttpServletRequest, oid: String): Boolean = {
    val token = req.getHeader("Authorization")
    if(token != null){
      val Array(expireAt, targetOid) = StringUtil.decodeBlowfish(token).split(" ")
      oid == targetOid && expireAt.toLong > System.currentTimeMillis
    } else {
      false
    }
  }

  private def getPathInfo(req: HttpServletRequest, res: HttpServletResponse): Option[(String, String, String)] = {
    req.getRequestURI.substring(1).split("/").reverse match {
      case Array(oid, repository, owner, _*) => Some((owner, repository, oid))
      case _ => None
    }
  }

  private def sendError(res: HttpServletResponse, status: Int, message: String): Unit = {
    res.setStatus(status)
    using(res.getWriter()){ out =>
      out.write(write(GitLfs.Error(message)))
      out.flush()
    }
  }

}






© 2015 - 2025 Weber Informatics LLC | Privacy Policy