8e91c11d7fe90df2f495323b5c6c1faa501e809d
[scm/test.git] / lfsapi / endpoint.go
1 package lfsapi
2
3 import (
4         "fmt"
5         "net/url"
6         "regexp"
7         "strings"
8 )
9
10 const UrlUnknown = "<unknown>"
11
12 // An Endpoint describes how to access a Git LFS server.
13 type Endpoint struct {
14         Url            string
15         SshUserAndHost string
16         SshPath        string
17         SshPort        string
18         Operation      string
19 }
20
21 func endpointOperation(e Endpoint, method string) string {
22         if len(e.Operation) > 0 {
23                 return e.Operation
24         }
25
26         switch method {
27         case "GET", "HEAD":
28                 return "download"
29         default:
30                 return "upload"
31         }
32 }
33
34 // endpointFromBareSshUrl constructs a new endpoint from a bare SSH URL:
35 //
36 //   user@host.com:path/to/repo.git
37 //
38 func endpointFromBareSshUrl(rawurl string) Endpoint {
39         parts := strings.Split(rawurl, ":")
40         partsLen := len(parts)
41         if partsLen < 2 {
42                 return Endpoint{Url: rawurl}
43         }
44
45         // Treat presence of ':' as a bare URL
46         var newPath string
47         if len(parts) > 2 { // port included; really should only ever be 3 parts
48                 newPath = fmt.Sprintf("%v:%v", parts[0], strings.Join(parts[1:], "/"))
49         } else {
50                 newPath = strings.Join(parts, "/")
51         }
52         newrawurl := fmt.Sprintf("ssh://%v", newPath)
53         newu, err := url.Parse(newrawurl)
54         if err != nil {
55                 return Endpoint{Url: UrlUnknown}
56         }
57
58         return endpointFromSshUrl(newu)
59 }
60
61 // endpointFromSshUrl constructs a new endpoint from an ssh:// URL
62 func endpointFromSshUrl(u *url.URL) Endpoint {
63         var endpoint Endpoint
64         // Pull out port now, we need it separately for SSH
65         regex := regexp.MustCompile(`^([^\:]+)(?:\:(\d+))?$`)
66         match := regex.FindStringSubmatch(u.Host)
67         if match == nil || len(match) < 2 {
68                 endpoint.Url = UrlUnknown
69                 return endpoint
70         }
71
72         host := match[1]
73         if u.User != nil && u.User.Username() != "" {
74                 endpoint.SshUserAndHost = fmt.Sprintf("%s@%s", u.User.Username(), host)
75         } else {
76                 endpoint.SshUserAndHost = host
77         }
78
79         if len(match) > 2 {
80                 endpoint.SshPort = match[2]
81         }
82
83         // u.Path includes a preceding '/', strip off manually
84         // rooted paths in the URL will be '//path/to/blah'
85         // this is just how Go's URL parsing works
86         if strings.HasPrefix(u.Path, "/") {
87                 endpoint.SshPath = u.Path[1:]
88         } else {
89                 endpoint.SshPath = u.Path
90         }
91
92         // Fallback URL for using HTTPS while still using SSH for git
93         // u.Host includes host & port so can't use SSH port
94         endpoint.Url = fmt.Sprintf("https://%s%s", host, u.Path)
95
96         return endpoint
97 }
98
99 // Construct a new endpoint from a HTTP URL
100 func endpointFromHttpUrl(u *url.URL) Endpoint {
101         // just pass this straight through
102         return Endpoint{Url: u.String()}
103 }
104
105 func endpointFromGitUrl(u *url.URL, e *endpointGitFinder) Endpoint {
106         u.Scheme = e.gitProtocol
107         return Endpoint{Url: u.String()}
108 }