123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- package githttp
- import (
- "fmt"
- "net/http"
- "os"
- "regexp"
- "strings"
- )
- type Service struct {
- Method string
- Handler func(HandlerReq) error
- Rpc string
- }
- type HandlerReq struct {
- w http.ResponseWriter
- r *http.Request
- Rpc string
- Dir string
- File string
- }
- // Routing regexes
- var (
- _serviceRpcUpload = regexp.MustCompile("git/(.*?)/git-upload-pack$")
- _serviceRpcReceive = regexp.MustCompile("git/(.*?)/git-receive-pack$")
- _getInfoRefs = regexp.MustCompile("git/(.*?)/info/refs$")
- _getHead = regexp.MustCompile("git/(.*?)/HEAD$")
- _getAlternates = regexp.MustCompile("git/(.*?)/objects/info/alternates$")
- _getHttpAlternates = regexp.MustCompile("git/(.*?)/objects/info/http-alternates$")
- _getInfoPacks = regexp.MustCompile("git/(.*?)/objects/info/packs$")
- _getInfoFile = regexp.MustCompile("git/(.*?)/objects/info/[^/]*$")
- _getLooseObject = regexp.MustCompile("git/(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$")
- _getPackFile = regexp.MustCompile("git/(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$")
- _getIdxFile = regexp.MustCompile("git/(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$")
- )
- func (g *GitHttp) services() map[*regexp.Regexp]Service {
- return map[*regexp.Regexp]Service{
- _serviceRpcUpload: Service{"POST", g.serviceRpc, "upload-pack"},
- _serviceRpcReceive: Service{"POST", g.serviceRpc, "receive-pack"},
- _getInfoRefs: Service{"GET", g.getInfoRefs, ""},
- _getHead: Service{"GET", g.getTextFile, ""},
- _getAlternates: Service{"GET", g.getTextFile, ""},
- _getHttpAlternates: Service{"GET", g.getTextFile, ""},
- _getInfoPacks: Service{"GET", g.getInfoPacks, ""},
- _getInfoFile: Service{"GET", g.getTextFile, ""},
- _getLooseObject: Service{"GET", g.getLooseObject, ""},
- _getPackFile: Service{"GET", g.getPackFile, ""},
- _getIdxFile: Service{"GET", g.getIdxFile, ""},
- }
- }
- // getService return's the service corresponding to the
- // current http.Request's URL
- // as well as the name of the repo
- func (g *GitHttp) getService(path string) (string, *Service) {
- for re, service := range g.services() {
- if m := re.FindStringSubmatch(path); m != nil {
- return m[1], &service
- }
- }
- // No match
- return "", nil
- }
- // Request handling function
- func (g *GitHttp) requestHandler(w http.ResponseWriter, r *http.Request) {
- // Get service for URL
- repo, service := g.getService(r.URL.Path)
- fmt.Println("git handler", r.URL.Path, repo)
- // No url match
- if service == nil {
- renderNotFound(w)
- return
- }
- // Bad method
- if service.Method != r.Method {
- renderMethodNotAllowed(w, r)
- return
- }
- // Rpc type
- rpc := service.Rpc
- // Get specific file
- file := strings.Replace(r.URL.Path, repo+"/", "", 1)
- // Resolve directory
- dir, err := g.getGitDir(repo)
- // Repo not found on disk
- if err != nil {
- renderNotFound(w)
- return
- }
- // Build request info for handler
- hr := HandlerReq{w, r, rpc, dir, file}
- // Call handler
- if err := service.Handler(hr); err != nil {
- if os.IsNotExist(err) {
- renderNotFound(w)
- return
- }
- switch err.(type) {
- case *ErrorNoAccess:
- renderNoAccess(w)
- return
- }
- http.Error(w, err.Error(), 500)
- }
- }
|