ref: a4eea12d15491ea8dba736f9a6fff09630a77f97
pkg/go-git-http/routing.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
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) } } |