github.com/apcera/util@v0.0.0-20180322191801-7a50bc84ee48/dockertest/v1/mock_v1_registry.go (about) 1 // Copyright 2014-2015 Apcera Inc. All rights reserved. 2 3 package v1 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "io" 9 "net/http" 10 "net/http/httptest" 11 "net/url" 12 "strconv" 13 "sync" 14 "time" 15 16 "github.com/gorilla/mux" 17 ) 18 19 var ( 20 testVerbose = false // Change to true in order to see HTTP requests in test output. 21 testHttpServer *httptest.Server 22 testLayers = map[string]map[string]string{ 23 "badcafe": { 24 "json": `{"id":"badcafe","k1": "v1"}`, 25 "ancestry": `["badcafe"]`, 26 "layer": string([]byte{0xa1, 0xb2, 0xc3}), 27 "checksum": "1ac330d", 28 }, 29 "deadbeef": { 30 "json": `{"id":"deadbeef","k2": "v2"}`, 31 "ancestry": `["deadbeef", "badcafe"]`, 32 "layer": string([]byte{0xd4, 0xe5, 0xf6}), 33 "checksum": "2bd330f", 34 }, 35 "bd51c4e1b5aceec2ff4bdd87d3fe5f1f16e1120490dee47e2999036f5bc55ccf": { // A random (valid) LayerID 36 "json": `{"id":"bd51c4e1b5aceec2ff4bdd87d3fe5f1f16e1120490dee47e2999036f5bc55ccf","k1": "v1"}`, 37 "ancestry": `["bd51c4e1b5aceec2ff4bdd87d3fe5f1f16e1120490dee47e2999036f5bc55ccf"]`, 38 "layer": string([]byte{0xa1, 0xb2, 0xc3}), 39 "checksum": "abcd1234", 40 }, 41 } 42 testRepositories = map[string]map[string]string{ 43 "foo/bar": { 44 "latest": "deadbeef", 45 "base": "badcafe", 46 }, 47 "some/image": { 48 "latest": "bd51c4e1b5aceec2ff4bdd87d3fe5f1f16e1120490dee47e2999036f5bc55ccf", 49 }, 50 "base": { 51 "latest": "badcafe", 52 }, 53 } 54 mu sync.Mutex 55 ) 56 57 func RunMockRegistry() *httptest.Server { 58 mu.Lock() 59 defer mu.Unlock() 60 61 if testHttpServer != nil { 62 return testHttpServer 63 } 64 65 r := mux.NewRouter() 66 r.HandleFunc("/v1/images/{image_id:[^/]+}/{data_type:json|layer|ancestry}", handlerImage).Methods("GET") 67 r.HandleFunc("/v1/repositories/{repository:.+}/tags", handlerTags).Methods("GET") 68 r.HandleFunc("/v1/repositories/{repository:.+}/images", handlerImages).Methods("GET") 69 70 testHttpServer = httptest.NewServer(logHandler(r)) 71 return testHttpServer 72 } 73 74 func logHandler(handler http.Handler) http.Handler { 75 if !testVerbose { 76 return handler 77 } 78 lh := func(w http.ResponseWriter, r *http.Request) { 79 fmt.Printf("%s \"%s %s\"\n", r.RemoteAddr, r.Method, r.URL) 80 handler.ServeHTTP(w, r) 81 } 82 return http.HandlerFunc(lh) 83 } 84 85 func writeResponse(w http.ResponseWriter, httpStatus int, payload interface{}) { 86 w.WriteHeader(httpStatus) 87 body, err := json.Marshal(payload) 88 if err != nil { 89 io.WriteString(w, err.Error()) 90 return 91 } 92 w.Write(body) 93 } 94 95 func checkAuth(w http.ResponseWriter, r *http.Request) bool { 96 writeAuth := func() { 97 sessionID := fmt.Sprintf("FAKE-SESSION-%d", time.Now().UnixNano()) 98 token := fmt.Sprintf("FAKE-TOKEN-%d", time.Now().UnixNano()) 99 100 http.SetCookie(w, &http.Cookie{Name: "session", Value: sessionID, MaxAge: 3600}) 101 w.Header().Add("X-Docker-Token", token) 102 } 103 104 // Mock registry doesn't really perform any auth. 105 if len(r.Cookies()) > 0 { 106 writeAuth() 107 return true 108 } 109 110 if (len(r.Header.Get("Authorization"))) > 0 { 111 writeAuth() 112 return true 113 } 114 w.Header().Add("WWW-Authenticate", "token") 115 writeResponse(w, 401, "Bad auth") 116 return false 117 } 118 119 func handlerImages(w http.ResponseWriter, r *http.Request) { 120 u, _ := url.Parse(testHttpServer.URL) // Ignoring error, URL is guaranteed to be OK. 121 122 w.Header().Add("X-Docker-Endpoints", fmt.Sprintf("%s , %s", u.Host, "test.example.com")) 123 w.Header().Add("X-Docker-Token", fmt.Sprintf("FAKE-SESSION-%d", time.Now().UnixNano())) 124 125 var images []map[string]string 126 127 for imageID, layer := range testLayers { 128 image := make(map[string]string) 129 image["id"] = imageID 130 image["checksum"] = layer["checksum"] 131 images = append(images, image) 132 } 133 writeResponse(w, 200, images) 134 } 135 136 func handlerImage(w http.ResponseWriter, r *http.Request) { 137 if !checkAuth(w, r) { 138 return 139 } 140 141 vars := mux.Vars(r) 142 layer, exists := testLayers[vars["image_id"]] 143 if !exists { 144 http.NotFound(w, r) 145 return 146 } 147 148 layer_size := len(layer["layer"]) 149 w.Header().Add("X-Docker-Size", strconv.Itoa(layer_size)) 150 io.WriteString(w, layer[vars["data_type"]]) 151 } 152 153 func handlerTags(w http.ResponseWriter, r *http.Request) { 154 if !checkAuth(w, r) { 155 return 156 } 157 158 vars := mux.Vars(r) 159 tags, exists := testRepositories[vars["repository"]] 160 if !exists { 161 http.NotFound(w, r) 162 return 163 } 164 165 writeResponse(w, 200, tags) 166 }