Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 36/change matching path to escaped path #38

Merged
merged 2 commits into from
Sep 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
83 changes: 47 additions & 36 deletions githttpxfer/githttpxfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,72 +5,83 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"regexp"
"strings"
)

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 @@ -150,7 +161,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 @@ -172,11 +183,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 Expand Up @@ -292,7 +304,6 @@ func (ghx *GitHTTPXfer) serviceRPC(ctx Context, rpc string) {
return
}


if err = cmd.Wait(); err != nil {
ghx.logger.Error("specified command fails to run or doesn't complete successfully. ", err.Error())
}
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