Skip to content

Commit 36c9486

Browse files
authored
Merge daa1a06 into 0b3c10f
2 parents 0b3c10f + daa1a06 commit 36c9486

File tree

7 files changed

+113
-83
lines changed

7 files changed

+113
-83
lines changed

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Let's clone this repository and execute the following commands.
1717

1818
```` zsh
1919
# docker build
20-
$ docker build -t git-http-xfer .
20+
$ docker build -t go-git-http-xfer .
2121

2222
# test
2323
$ docker run --rm -v $PWD:/go/src/github.com/nulab/go-git-http-xfer go-git-http-xfer \
@@ -91,12 +91,14 @@ func main() {
9191
// You can add some custom route.
9292
ghx.Router.Add(githttpxfer.NewRoute(
9393
http.MethodGet,
94-
func (path string) (match string) {
94+
func (u *url.URL) *Match {
9595
suffix := "/hello"
96-
if strings.HasSuffix(path, suffix) {
97-
match = suffix
96+
if !strings.HasSuffix(u.Path, suffix) {
97+
return nil
9898
}
99-
return
99+
repoPath := strings.Replace(u.Path, suffix, "", 1)
100+
filePath := strings.Replace(u.Path, repoPath+"/", "", 1)
101+
return &Match{repoPath, filePath}
100102
},
101103
func(ctx githttpxfer.Context) {
102104
resp, req := ctx.Response(), ctx.Request()

addon/handler/archive/archive.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,22 @@ import (
77
"regexp"
88
"strings"
99

10+
"net/url"
11+
1012
"github.com/nulab/go-git-http-xfer/githttpxfer"
1113
)
1214

1315
var (
1416
archiveRegexp = regexp.MustCompile(".*?(/archive/.*?\\.(zip|tar))$")
15-
Pattern = func(path string) (match string) {
16-
if m := archiveRegexp.FindStringSubmatch(path); m != nil {
17-
match = m[1]
17+
Pattern = func(u *url.URL) *githttpxfer.Match {
18+
m := archiveRegexp.FindStringSubmatch(u.Path)
19+
if m == nil {
20+
return nil
1821
}
19-
return
22+
suffix := m[1]
23+
repoPath := strings.Replace(u.Path, suffix, "", 1)
24+
filePath := strings.Replace(u.Path, repoPath+"/", "", 1)
25+
return &githttpxfer.Match{repoPath, filePath}
2026
}
2127
Method = http.MethodGet
2228
)

example/main.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010

1111
"strings"
1212

13+
"net/url"
14+
1315
"github.com/nulab/go-git-http-xfer/addon/handler/archive"
1416
"github.com/nulab/go-git-http-xfer/githttpxfer"
1517
)
@@ -41,12 +43,14 @@ func main() {
4143
// You can add some custom route.
4244
ghx.Router.Add(githttpxfer.NewRoute(
4345
http.MethodGet,
44-
func(path string) (match string) {
46+
func(u *url.URL) *githttpxfer.Match {
4547
suffix := "/hello"
46-
if strings.HasSuffix(path, suffix) {
47-
match = suffix
48+
if !strings.HasSuffix(u.Path, suffix) {
49+
return nil
4850
}
49-
return
51+
repoPath := strings.Replace(u.Path, suffix, "", 1)
52+
filePath := strings.Replace(u.Path, repoPath+"/", "", 1)
53+
return &githttpxfer.Match{repoPath, filePath}
5054
},
5155
func(ctx githttpxfer.Context) {
5256
resp, req := ctx.Response(), ctx.Request()

githttpxfer/githttpxfer.go

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,73 +5,84 @@ import (
55
"fmt"
66
"io"
77
"net/http"
8+
"net/url"
89
"os"
910
"regexp"
1011
"strings"
1112
"sync"
1213
)
1314

1415
var (
15-
serviceRPCUpload = func(path string) (match string) {
16-
return hasSuffix(path, "/git-upload-pack")
16+
serviceRPCUpload = func(u *url.URL) *Match {
17+
return matchSuffix(u.Path, "/git-upload-pack")
1718
}
18-
serviceRPCReceive = func(path string) (match string) {
19-
return hasSuffix(path, "/git-receive-pack")
19+
serviceRPCReceive = func(u *url.URL) *Match {
20+
return matchSuffix(u.Path, "/git-receive-pack")
2021
}
2122

22-
getInfoRefs = func(path string) (match string) {
23-
return hasSuffix(path, "/info/refs")
23+
getInfoRefs = func(u *url.URL) *Match {
24+
return matchSuffix(u.Path, "/info/refs")
2425
}
2526

26-
getHead = func(path string) (match string) {
27-
return hasSuffix(path, "/HEAD")
27+
getHead = func(u *url.URL) *Match {
28+
return matchSuffix(u.Path, "/HEAD")
2829
}
2930

30-
getAlternates = func(path string) (match string) {
31-
return hasSuffix(path, "/objects/info/alternates")
31+
getAlternates = func(u *url.URL) *Match {
32+
return matchSuffix(u.Path, "/objects/info/alternates")
3233
}
3334

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

38-
getInfoPacks = func(path string) (match string) {
39-
return hasSuffix(path, "/objects/info/packs")
39+
getInfoPacks = func(u *url.URL) *Match {
40+
return matchSuffix(u.Path, "/objects/info/packs")
4041
}
4142

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

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

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

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

63-
func hasSuffix(path, suffix string) (match string) {
64-
if strings.HasSuffix(path, suffix) {
65-
match = suffix
64+
type Match struct {
65+
RepoPath, FilePath string
66+
}
67+
68+
func matchSuffix(path, suffix string) *Match {
69+
if !strings.HasSuffix(path, suffix) {
70+
return nil
6671
}
67-
return
72+
repoPath := strings.Replace(path, suffix, "", 1)
73+
filePath := strings.Replace(path, repoPath+"/", "", 1)
74+
return &Match{repoPath, filePath}
6875
}
6976

70-
func findStringSubmatch(path string, prefix *regexp.Regexp) (match string) {
71-
if m := prefix.FindStringSubmatch(path); m != nil {
72-
match = m[1]
77+
func findStringSubmatch(path string, prefix *regexp.Regexp) *Match {
78+
m := prefix.FindStringSubmatch(path)
79+
if m == nil {
80+
return nil
7381
}
74-
return
82+
suffix := m[1]
83+
repoPath := strings.Replace(path, suffix, "", 1)
84+
filePath := strings.Replace(path, repoPath+"/", "", 1)
85+
return &Match{repoPath, filePath}
7586
}
7687

7788
type options struct {
@@ -151,7 +162,7 @@ func (ghx *GitHTTPXfer) SetLogger(logger Logger) {
151162
}
152163

153164
func (ghx *GitHTTPXfer) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
154-
repoPath, filePath, handler, err := ghx.matchRouting(r.Method, r.URL.Path)
165+
repoPath, filePath, handler, err := ghx.matchRouting(r.Method, r.URL)
155166
switch err.(type) {
156167
case *URLNotFoundError:
157168
RenderNotFound(rw)
@@ -173,11 +184,12 @@ func (ghx *GitHTTPXfer) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
173184
handler(ctx)
174185
}
175186

176-
func (ghx *GitHTTPXfer) matchRouting(method, path string) (repoPath string, filePath string, handler HandlerFunc, err error) {
177-
match, route, err := ghx.Router.Match(method, path)
187+
func (ghx *GitHTTPXfer) matchRouting(method string, u *url.URL) (repoPath string, filePath string, handler HandlerFunc, err error) {
188+
match, route, err := ghx.Router.Match(method, u)
189+
178190
if err == nil {
179-
repoPath = strings.Replace(path, match, "", 1)
180-
filePath = strings.Replace(path, repoPath+"/", "", 1)
191+
repoPath = match.RepoPath
192+
filePath = match.FilePath
181193
handler = route.Handler
182194
}
183195
return

githttpxfer/githttpxfer_test.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"log"
55
"net/http"
66
"net/http/httptest"
7+
"net/url"
78
"os/exec"
89
"testing"
910
)
@@ -77,8 +78,10 @@ func Test_GitHTTPXfer_MatchRouting_should_not_match(t *testing.T) {
7778
return
7879
}
7980
m := http.MethodGet
80-
p := "/base/foo/git-upload-pack"
81-
_, _, _, err = ghx.matchRouting(m, p)
81+
u := &url.URL{
82+
Path: "/base/foo/git-upload-pack",
83+
}
84+
_, _, _, err = ghx.matchRouting(m, u)
8285
if err == nil {
8386
t.Error("Allowed.")
8487
return
@@ -99,78 +102,78 @@ func Test_GitHTTPXfer_MatchRouting_should_match(t *testing.T) {
99102
tests := []struct {
100103
description string
101104
method string
102-
path string
105+
u *url.URL
103106
expectedRepoPath string
104107
expectedFilePath string
105108
}{
106109
{
107110
description: "it should match git-upload-pack",
108111
method: http.MethodPost,
109-
path: "/base/foo/git-upload-pack",
112+
u: &url.URL{Path: "/base/foo/git-upload-pack"},
110113
expectedRepoPath: "/base/foo",
111114
expectedFilePath: "git-upload-pack",
112115
},
113116
{
114117
description: "it should match get-info-refs",
115118
method: http.MethodGet,
116-
path: "/base/foo/info/refs",
119+
u: &url.URL{Path: "/base/foo/info/refs"},
117120
expectedRepoPath: "/base/foo",
118121
expectedFilePath: "info/refs",
119122
},
120123
{
121124
description: "it should match get-head",
122125
method: http.MethodGet,
123-
path: "/base/foo/HEAD",
126+
u: &url.URL{Path: "/base/foo/HEAD"},
124127
expectedRepoPath: "/base/foo",
125128
expectedFilePath: "HEAD",
126129
},
127130
{
128131
description: "it should match get-alternates",
129132
method: http.MethodGet,
130-
path: "/base/foo/objects/info/alternates",
133+
u: &url.URL{Path: "/base/foo/objects/info/alternates"},
131134
expectedRepoPath: "/base/foo",
132135
expectedFilePath: "objects/info/alternates",
133136
},
134137
{
135138
description: "it should match get-http-alternates",
136139
method: http.MethodGet,
137-
path: "/base/foo/objects/info/http-alternates",
140+
u: &url.URL{Path: "/base/foo/objects/info/http-alternates"},
138141
expectedRepoPath: "/base/foo",
139142
expectedFilePath: "objects/info/http-alternates",
140143
},
141144
{
142145
description: "it should match get-info-packs",
143146
method: http.MethodGet,
144-
path: "/base/foo/objects/info/packs",
147+
u: &url.URL{Path: "/base/foo/objects/info/packs"},
145148
expectedRepoPath: "/base/foo",
146149
expectedFilePath: "objects/info/packs",
147150
},
148151
{
149152
description: "it should match get-loose-object",
150153
method: http.MethodGet,
151-
path: "/base/foo/objects/3b/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacccccc",
154+
u: &url.URL{Path: "/base/foo/objects/3b/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacccccc"},
152155
expectedRepoPath: "/base/foo",
153156
expectedFilePath: "objects/3b/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacccccc",
154157
},
155158
{
156159
description: "it should match get-pack-file",
157160
method: http.MethodGet,
158-
path: "/base/foo/objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.pack",
161+
u: &url.URL{Path: "/base/foo/objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.pack"},
159162
expectedRepoPath: "/base/foo",
160163
expectedFilePath: "objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.pack",
161164
},
162165
{
163166
description: "it should match get-idx-file",
164167
method: http.MethodGet,
165-
path: "/base/foo/objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.idx",
168+
u: &url.URL{Path: "/base/foo/objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.idx"},
166169
expectedRepoPath: "/base/foo",
167170
expectedFilePath: "objects/pack/pack-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbb.idx",
168171
},
169172
}
170173

171174
for _, tc := range tests {
172175
t.Log(tc.description)
173-
repoPath, filePath, _, err := ghx.matchRouting(tc.method, tc.path)
176+
repoPath, filePath, _, err := ghx.matchRouting(tc.method, tc.u)
174177
if err != nil {
175178
t.Errorf("error is %s", err.Error())
176179
return

githttpxfer/router.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package githttpxfer
22

3+
import "net/url"
4+
35
type router struct {
46
routes []*Route
57
}
@@ -11,13 +13,13 @@ func (r *router) Add(route *Route) {
1113
r.routes = append(r.routes, route)
1214
}
1315

14-
func (r *router) Match(method string, path string) (match string, route *Route, err error) {
16+
func (r *router) Match(method string, u *url.URL) (match *Match, route *Route, err error) {
1517
for _, v := range r.routes {
16-
if m := v.Pattern(path); m != "" {
18+
if m := v.Pattern(u); m != nil {
1719
if v.Method != method {
1820
err = &MethodNotAllowedError{
1921
Method: method,
20-
Path: path,
22+
Path: u.Path,
2123
}
2224
return
2325
}
@@ -29,7 +31,7 @@ func (r *router) Match(method string, path string) (match string, route *Route,
2931

3032
err = &URLNotFoundError{
3133
Method: method,
32-
Path: path,
34+
Path: u.Path,
3335
}
3436
return
3537
}
@@ -38,7 +40,7 @@ func newRouter() *router {
3840
return &router{routes: []*Route{}}
3941
}
4042

41-
type Pattern = func(path string) (match string)
43+
type Pattern = func(u *url.URL) *Match
4244

4345
type Route struct {
4446
Method string

0 commit comments

Comments
 (0)