Skip to content

Commit

Permalink
Merge pull request #38 from nulab/issue-36/change-matching-path-to-es…
Browse files Browse the repository at this point in the history
…caped-path

Issue 36/change matching path to escaped path
  • Loading branch information
vvatanabe committed Sep 11, 2018
2 parents 0b3c10f + daa1a06 commit 8c1746f
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 83 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Let's clone this repository and execute the following commands.

```` zsh
# docker build
$ docker build -t git-http-xfer .
$ docker build -t go-git-http-xfer .

# test
$ docker run --rm -v $PWD:/go/src/github.com/nulab/go-git-http-xfer go-git-http-xfer \
Expand Down Expand Up @@ -91,12 +91,14 @@ func main() {
// You can add some custom route.
ghx.Router.Add(githttpxfer.NewRoute(
http.MethodGet,
func (path string) (match string) {
func (u *url.URL) *Match {
suffix := "/hello"
if strings.HasSuffix(path, suffix) {
match = suffix
if !strings.HasSuffix(u.Path, suffix) {
return nil
}
return
repoPath := strings.Replace(u.Path, suffix, "", 1)
filePath := strings.Replace(u.Path, repoPath+"/", "", 1)
return &Match{repoPath, filePath}
},
func(ctx githttpxfer.Context) {
resp, req := ctx.Response(), ctx.Request()
Expand Down
14 changes: 10 additions & 4 deletions addon/handler/archive/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ import (
"regexp"
"strings"

"net/url"

"github.com/nulab/go-git-http-xfer/githttpxfer"
)

var (
archiveRegexp = regexp.MustCompile(".*?(/archive/.*?\\.(zip|tar))$")
Pattern = func(path string) (match string) {
if m := archiveRegexp.FindStringSubmatch(path); m != nil {
match = m[1]
Pattern = func(u *url.URL) *githttpxfer.Match {
m := archiveRegexp.FindStringSubmatch(u.Path)
if m == nil {
return nil
}
return
suffix := m[1]
repoPath := strings.Replace(u.Path, suffix, "", 1)
filePath := strings.Replace(u.Path, repoPath+"/", "", 1)
return &githttpxfer.Match{repoPath, filePath}
}
Method = http.MethodGet
)
Expand Down
12 changes: 8 additions & 4 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (

"strings"

"net/url"

"github.com/nulab/go-git-http-xfer/addon/handler/archive"
"github.com/nulab/go-git-http-xfer/githttpxfer"
)
Expand Down Expand Up @@ -41,12 +43,14 @@ func main() {
// You can add some custom route.
ghx.Router.Add(githttpxfer.NewRoute(
http.MethodGet,
func(path string) (match string) {
func(u *url.URL) *githttpxfer.Match {
suffix := "/hello"
if strings.HasSuffix(path, suffix) {
match = suffix
if !strings.HasSuffix(u.Path, suffix) {
return nil
}
return
repoPath := strings.Replace(u.Path, suffix, "", 1)
filePath := strings.Replace(u.Path, repoPath+"/", "", 1)
return &githttpxfer.Match{repoPath, filePath}
},
func(ctx githttpxfer.Context) {
resp, req := ctx.Response(), ctx.Request()
Expand Down
82 changes: 47 additions & 35 deletions githttpxfer/githttpxfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,73 +5,84 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"regexp"
"strings"
"sync"
)

var (
serviceRPCUpload = func(path string) (match string) {
return hasSuffix(path, "/git-upload-pack")
serviceRPCUpload = func(u *url.URL) *Match {
return matchSuffix(u.Path, "/git-upload-pack")
}
serviceRPCReceive = func(path string) (match string) {
return hasSuffix(path, "/git-receive-pack")
serviceRPCReceive = func(u *url.URL) *Match {
return matchSuffix(u.Path, "/git-receive-pack")
}

getInfoRefs = func(path string) (match string) {
return hasSuffix(path, "/info/refs")
getInfoRefs = func(u *url.URL) *Match {
return matchSuffix(u.Path, "/info/refs")
}

getHead = func(path string) (match string) {
return hasSuffix(path, "/HEAD")
getHead = func(u *url.URL) *Match {
return matchSuffix(u.Path, "/HEAD")
}

getAlternates = func(path string) (match string) {
return hasSuffix(path, "/objects/info/alternates")
getAlternates = func(u *url.URL) *Match {
return matchSuffix(u.Path, "/objects/info/alternates")
}

getHTTPAlternates = func(path string) (match string) {
return hasSuffix(path, "/objects/info/http-alternates")
getHTTPAlternates = func(u *url.URL) *Match {
return matchSuffix(u.Path, "/objects/info/http-alternates")
}

getInfoPacks = func(path string) (match string) {
return hasSuffix(path, "/objects/info/packs")
getInfoPacks = func(u *url.URL) *Match {
return matchSuffix(u.Path, "/objects/info/packs")
}

getInfoFileRegexp = regexp.MustCompile(".*?(/objects/info/[^/]*)$")
getInfoFile = func(path string) (match string) {
return findStringSubmatch(path, getInfoFileRegexp)
getInfoFile = func(u *url.URL) *Match {
return findStringSubmatch(u.Path, getInfoFileRegexp)
}

getLooseObjectRegexp = regexp.MustCompile(".*?(/objects/[0-9a-f]{2}/[0-9a-f]{38})$")
getLooseObject = func(path string) (match string) {
return findStringSubmatch(path, getLooseObjectRegexp)
getLooseObject = func(u *url.URL) *Match {
return findStringSubmatch(u.Path, getLooseObjectRegexp)
}

getPackFileRegexp = regexp.MustCompile(".*?(/objects/pack/pack-[0-9a-f]{40}\\.pack)$")
getPackFile = func(path string) (match string) {
return findStringSubmatch(path, getPackFileRegexp)
getPackFile = func(u *url.URL) *Match {
return findStringSubmatch(u.Path, getPackFileRegexp)
}

getIdxFileRegexp = regexp.MustCompile(".*?(/objects/pack/pack-[0-9a-f]{40}\\.idx)$")
getIdxFile = func(path string) (match string) {
return findStringSubmatch(path, getIdxFileRegexp)
getIdxFile = func(u *url.URL) *Match {
return findStringSubmatch(u.Path, getIdxFileRegexp)
}
)

func hasSuffix(path, suffix string) (match string) {
if strings.HasSuffix(path, suffix) {
match = suffix
type Match struct {
RepoPath, FilePath string
}

func matchSuffix(path, suffix string) *Match {
if !strings.HasSuffix(path, suffix) {
return nil
}
return
repoPath := strings.Replace(path, suffix, "", 1)
filePath := strings.Replace(path, repoPath+"/", "", 1)
return &Match{repoPath, filePath}
}

func findStringSubmatch(path string, prefix *regexp.Regexp) (match string) {
if m := prefix.FindStringSubmatch(path); m != nil {
match = m[1]
func findStringSubmatch(path string, prefix *regexp.Regexp) *Match {
m := prefix.FindStringSubmatch(path)
if m == nil {
return nil
}
return
suffix := m[1]
repoPath := strings.Replace(path, suffix, "", 1)
filePath := strings.Replace(path, repoPath+"/", "", 1)
return &Match{repoPath, filePath}
}

type options struct {
Expand Down Expand Up @@ -151,7 +162,7 @@ func (ghx *GitHTTPXfer) SetLogger(logger Logger) {
}

func (ghx *GitHTTPXfer) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
repoPath, filePath, handler, err := ghx.matchRouting(r.Method, r.URL.Path)
repoPath, filePath, handler, err := ghx.matchRouting(r.Method, r.URL)
switch err.(type) {
case *URLNotFoundError:
RenderNotFound(rw)
Expand All @@ -173,11 +184,12 @@ func (ghx *GitHTTPXfer) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
handler(ctx)
}

func (ghx *GitHTTPXfer) matchRouting(method, path string) (repoPath string, filePath string, handler HandlerFunc, err error) {
match, route, err := ghx.Router.Match(method, path)
func (ghx *GitHTTPXfer) matchRouting(method string, u *url.URL) (repoPath string, filePath string, handler HandlerFunc, err error) {
match, route, err := ghx.Router.Match(method, u)

if err == nil {
repoPath = strings.Replace(path, match, "", 1)
filePath = strings.Replace(path, repoPath+"/", "", 1)
repoPath = match.RepoPath
filePath = match.FilePath
handler = route.Handler
}
return
Expand Down
29 changes: 16 additions & 13 deletions githttpxfer/githttpxfer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"log"
"net/http"
"net/http/httptest"
"net/url"
"os/exec"
"testing"
)
Expand Down Expand Up @@ -77,8 +78,10 @@ func Test_GitHTTPXfer_MatchRouting_should_not_match(t *testing.T) {
return
}
m := http.MethodGet
p := "/base/foo/git-upload-pack"
_, _, _, err = ghx.matchRouting(m, p)
u := &url.URL{
Path: "/base/foo/git-upload-pack",
}
_, _, _, err = ghx.matchRouting(m, u)
if err == nil {
t.Error("Allowed.")
return
Expand All @@ -99,78 +102,78 @@ func Test_GitHTTPXfer_MatchRouting_should_match(t *testing.T) {
tests := []struct {
description string
method string
path string
u *url.URL
expectedRepoPath string
expectedFilePath string
}{
{
description: "it should match git-upload-pack",
method: http.MethodPost,
path: "/base/foo/git-upload-pack",
u: &url.URL{Path: "/base/foo/git-upload-pack"},
expectedRepoPath: "/base/foo",
expectedFilePath: "git-upload-pack",
},
{
description: "it should match get-info-refs",
method: http.MethodGet,
path: "/base/foo/info/refs",
u: &url.URL{Path: "/base/foo/info/refs"},
expectedRepoPath: "/base/foo",
expectedFilePath: "info/refs",
},
{
description: "it should match get-head",
method: http.MethodGet,
path: "/base/foo/HEAD",
u: &url.URL{Path: "/base/foo/HEAD"},
expectedRepoPath: "/base/foo",
expectedFilePath: "HEAD",
},
{
description: "it should match get-alternates",
method: http.MethodGet,
path: "/base/foo/objects/info/alternates",
u: &url.URL{Path: "/base/foo/objects/info/alternates"},
expectedRepoPath: "/base/foo",
expectedFilePath: "objects/info/alternates",
},
{
description: "it should match get-http-alternates",
method: http.MethodGet,
path: "/base/foo/objects/info/http-alternates",
u: &url.URL{Path: "/base/foo/objects/info/http-alternates"},
expectedRepoPath: "/base/foo",
expectedFilePath: "objects/info/http-alternates",
},
{
description: "it should match get-info-packs",
method: http.MethodGet,
path: "/base/foo/objects/info/packs",
u: &url.URL{Path: "/base/foo/objects/info/packs"},
expectedRepoPath: "/base/foo",
expectedFilePath: "objects/info/packs",
},
{
description: "it should match get-loose-object",
method: http.MethodGet,
path: "/base/foo/objects/3b/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacccccc",
u: &url.URL{Path: "/base/foo/objects/3b/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacccccc"},
expectedRepoPath: "/base/foo",
expectedFilePath: "objects/3b/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacccccc",
},
{
description: "it should match get-pack-file",
method: http.MethodGet,
path: "/base/foo/objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.pack",
u: &url.URL{Path: "/base/foo/objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.pack"},
expectedRepoPath: "/base/foo",
expectedFilePath: "objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.pack",
},
{
description: "it should match get-idx-file",
method: http.MethodGet,
path: "/base/foo/objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.idx",
u: &url.URL{Path: "/base/foo/objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.idx"},
expectedRepoPath: "/base/foo",
expectedFilePath: "objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.idx",
},
}

for _, tc := range tests {
t.Log(tc.description)
repoPath, filePath, _, err := ghx.matchRouting(tc.method, tc.path)
repoPath, filePath, _, err := ghx.matchRouting(tc.method, tc.u)
if err != nil {
t.Errorf("error is %s", err.Error())
return
Expand Down
12 changes: 7 additions & 5 deletions githttpxfer/router.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package githttpxfer

import "net/url"

type router struct {
routes []*Route
}
Expand All @@ -11,13 +13,13 @@ func (r *router) Add(route *Route) {
r.routes = append(r.routes, route)
}

func (r *router) Match(method string, path string) (match string, route *Route, err error) {
func (r *router) Match(method string, u *url.URL) (match *Match, route *Route, err error) {
for _, v := range r.routes {
if m := v.Pattern(path); m != "" {
if m := v.Pattern(u); m != nil {
if v.Method != method {
err = &MethodNotAllowedError{
Method: method,
Path: path,
Path: u.Path,
}
return
}
Expand All @@ -29,7 +31,7 @@ func (r *router) Match(method string, path string) (match string, route *Route,

err = &URLNotFoundError{
Method: method,
Path: path,
Path: u.Path,
}
return
}
Expand All @@ -38,7 +40,7 @@ func newRouter() *router {
return &router{routes: []*Route{}}
}

type Pattern = func(path string) (match string)
type Pattern = func(u *url.URL) *Match

type Route struct {
Method string
Expand Down

0 comments on commit 8c1746f

Please sign in to comment.