This repository has been archived by the owner on May 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
server.go
131 lines (105 loc) · 2.91 KB
/
server.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
121
122
123
124
125
126
127
128
129
130
131
package server
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"strings"
log "github.com/sirupsen/logrus"
c3config "github.com/c3systems/c3-go/config"
"github.com/c3systems/c3-go/registry/util"
)
var listener net.Listener
var serverHost = fmt.Sprintf("0.0.0.0:%v", c3config.DockerRegistryPort)
// Run ...
func Run() error {
// already listening
if listener != nil {
return nil
}
var gw string
contentTypes := map[string]string{
"manifestV2Schema": "application/vnd.docker.distribution.manifest.v2+json",
"manifestListV2Schema": "application/vnd.docker.distribution.manifest.list.v2+json",
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
uri := r.RequestURI
log.Printf("[registry] %s", uri)
if uri == "/v2/" {
jsonstr := []byte(fmt.Sprintf(`{"what": "a registry", "gateway":%q, "handles": [%q, %q], "problematic": ["version 1 registries"], "project": "https://github.com/c3systems/c3-go"}`, gw, contentTypes["manifestListV2Schema"], contentTypes["manifestV2Schema"]))
w.Header().Set("Docker-Distribution-API-Version", "registry/2.0")
fmt.Fprintln(w, string(jsonstr))
return
}
if len(uri) <= 1 {
fmt.Fprintln(w, "invalid multihash")
return
}
var suffix string
if strings.HasSuffix(uri, "/latest") {
// docker daemon requesting the manifest
suffix = "-v1"
accepts := r.Header["Accept"]
for _, accept := range accepts {
if accept == contentTypes["manifestV2Schema"] ||
accept == contentTypes["manifestListV2Schema"] {
suffix = "-v2"
break
}
}
}
s := strings.Split(uri, "/")
if len(s) <= 2 {
fmt.Fprintln(w, "out of range")
return
}
hash := util.IpfsifyHash(s[2])
rest := strings.Join(s[3:], "/") // tag
path := hash + "/" + rest
// blob request
location := ipfsURL(path)
if suffix != "" {
// manifest request
location = location + suffix
}
log.Printf("[registy] location %s", location)
req, err := http.NewRequest("GET", location, nil)
if err != nil {
fmt.Fprintf(w, err.Error())
return
}
httpClient := http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
fmt.Fprintf(w, err.Error())
return
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Fprintf(w, err.Error())
return
}
//w.Header().Set("Location", location) // not required since we're fetching the content and proxying
w.Header().Set("Docker-Distribution-API-Version", "registry/2.0")
// if latest-v2 set header
w.Header().Set("Content-Type", contentTypes["manifestV2Schema"])
fmt.Fprintf(w, string(body))
})
var err error
listener, err = net.Listen("tcp", serverHost)
if err != nil {
return err
}
port := listener.Addr().(*net.TCPAddr).Port
log.Printf("[registry] port %v", port)
return http.Serve(listener, nil)
}
// Close ...
func Close() {
if listener != nil {
listener.Close()
}
}
func ipfsURL(hash string) string {
return c3config.IPFSGateway + "/ipfs/" + hash
}