PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/golang_impl/handler.go

https://gitlab.com/0072016/docker-registry
Go | 235 lines | 207 code | 25 blank | 3 comment | 42 complexity | 49d3b1c756e85556f3309e6aacbb315a MD5 | raw file
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "os"
  8. "path/filepath"
  9. "regexp"
  10. "time"
  11. )
  12. type Mapping struct {
  13. Method string
  14. Regexp *regexp.Regexp
  15. Handler func(http.ResponseWriter, *http.Request, [][]string)
  16. }
  17. func GenerateUUID() string {
  18. f, _ := os.Open("/dev/urandom")
  19. b := make([]byte, 16)
  20. f.Read(b)
  21. f.Close()
  22. return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
  23. }
  24. type Handler struct {
  25. DataDir string
  26. Mappings []*Mapping
  27. }
  28. func (h *Handler) WriteJsonHeader(w http.ResponseWriter) {
  29. w.Header().Add("Content-Type", "application/json")
  30. }
  31. func (h *Handler) WriteEndpointsHeader(w http.ResponseWriter, r *http.Request) {
  32. w.Header().Add("X-Docker-Endpoints", r.Host)
  33. }
  34. func (h *Handler) GetPing(w http.ResponseWriter, r *http.Request, p [][]string) {
  35. w.Header().Add("X-Docker-Registry-Version", "0.0.1")
  36. w.WriteHeader(200)
  37. fmt.Fprint(w, "pong")
  38. }
  39. func (h *Handler) GetUsers(w http.ResponseWriter, r *http.Request, p [][]string) {
  40. w.WriteHeader(201)
  41. fmt.Fprint(w, "OK")
  42. }
  43. func (h *Handler) GetRepositoryImages(w http.ResponseWriter, r *http.Request, p [][]string) {
  44. repo := &Repository{h.DataDir + "/repositories/" + p[0][2]}
  45. if images, err := repo.Images(); err == nil {
  46. h.WriteJsonHeader(w)
  47. h.WriteEndpointsHeader(w, r)
  48. w.WriteHeader(http.StatusOK)
  49. fmt.Fprintf(w, string(images))
  50. } else {
  51. logger.Error(err.Error())
  52. w.WriteHeader(http.StatusNotFound)
  53. return
  54. }
  55. return
  56. }
  57. func (h *Handler) GetImageAncestry(w http.ResponseWriter, r *http.Request, p [][]string) {
  58. idPrefix := p[0][2]
  59. if paths, err := filepath.Glob(h.DataDir + "/images/" + idPrefix + "*"); err == nil {
  60. if len(paths) > 0 {
  61. image := &Image{paths[0]}
  62. if out, err := json.Marshal(image.Ancestry()); err == nil {
  63. h.WriteJsonHeader(w)
  64. w.WriteHeader(http.StatusOK)
  65. fmt.Fprintf(w, string(out))
  66. return
  67. }
  68. }
  69. }
  70. http.NotFound(w, r)
  71. }
  72. func (h *Handler) GetImageLayer(w http.ResponseWriter, r *http.Request, p [][]string) {
  73. idPrefix := p[0][2]
  74. if paths, err := filepath.Glob(h.DataDir + "/images/" + idPrefix + "*"); err == nil {
  75. image := &Image{paths[0]}
  76. file, err := os.Open(image.LayerPath())
  77. if err == nil {
  78. w.Header().Add("Content-Type", "application/x-xz")
  79. w.WriteHeader(http.StatusOK)
  80. io.Copy(w, file)
  81. } else {
  82. w.WriteHeader(http.StatusNotFound)
  83. }
  84. }
  85. }
  86. func (h *Handler) GetImageJson(w http.ResponseWriter, r *http.Request, p [][]string) {
  87. idPrefix := p[0][2]
  88. if paths, err := filepath.Glob(h.DataDir + "/images/" + idPrefix + "*"); err == nil {
  89. if len(paths) > 0 {
  90. image := &Image{paths[0]}
  91. file, err := os.Open(image.Dir + "/json")
  92. if err == nil {
  93. if file, err := os.Open(image.LayerPath()); err == nil {
  94. if stat, err := file.Stat(); err == nil {
  95. w.Header().Add("X-Docker-Size", fmt.Sprintf("%d", stat.Size()))
  96. }
  97. }
  98. w.WriteHeader(http.StatusOK)
  99. io.Copy(w, file)
  100. return
  101. }
  102. }
  103. }
  104. w.WriteHeader(http.StatusNotFound)
  105. }
  106. func (h *Handler) GetRepositoryTags(w http.ResponseWriter, r *http.Request, p [][]string) {
  107. repo := &Repository{h.DataDir + "/repositories/" + p[0][2]}
  108. tagsJson, err := json.Marshal(repo.Tags())
  109. if err != nil {
  110. w.WriteHeader(http.StatusNotFound)
  111. fmt.Fprintf(w, err.Error())
  112. return
  113. }
  114. h.WriteJsonHeader(w)
  115. h.WriteEndpointsHeader(w, r)
  116. w.WriteHeader(http.StatusOK)
  117. fmt.Fprintf(w, string(tagsJson))
  118. return
  119. }
  120. func (h *Handler) PutImageResource(w http.ResponseWriter, r *http.Request, p [][]string) {
  121. imageId := p[0][2]
  122. tagName := p[0][3]
  123. err := writeFile(h.DataDir+"/images/"+imageId+"/"+tagName, r.Body)
  124. if err != nil {
  125. logger.Error(err.Error())
  126. } else {
  127. w.WriteHeader(http.StatusOK)
  128. }
  129. }
  130. func (h *Handler) PutRepositoryTags(w http.ResponseWriter, r *http.Request, p [][]string) {
  131. repoName := p[0][2]
  132. path := h.DataDir + "/repositories/" + repoName + "/tags/" + p[0][3]
  133. err := writeFile(path, r.Body)
  134. if err != nil {
  135. logger.Error(err.Error())
  136. } else {
  137. w.WriteHeader(http.StatusOK)
  138. }
  139. }
  140. func (h *Handler) PutRepositoryImages(w http.ResponseWriter, r *http.Request, p [][]string) {
  141. repoName := p[0][2]
  142. repo := &Repository{h.DataDir + "/repositories/" + repoName}
  143. err := writeFile(repo.ImagesPath(), r.Body)
  144. if err != nil {
  145. logger.Error(err.Error())
  146. } else {
  147. w.WriteHeader(http.StatusNoContent)
  148. }
  149. }
  150. func (h *Handler) PutRepository(w http.ResponseWriter, r *http.Request, p [][]string) {
  151. h.WriteJsonHeader(w)
  152. h.WriteEndpointsHeader(w, r)
  153. w.Header().Add("WWW-Authenticate", `Token signature=123abc,repository="dynport/test",access=write`)
  154. w.Header().Add("X-Docker-Token", "token")
  155. w.WriteHeader(http.StatusOK)
  156. repoName := p[0][2]
  157. repo := &Repository{h.DataDir + "/repositories/" + repoName}
  158. err := writeFile(repo.IndexPath(), r.Body)
  159. if err != nil {
  160. logger.Error(err.Error())
  161. }
  162. }
  163. func (h *Handler) Map(t, re string, f func(http.ResponseWriter, *http.Request, [][]string)) {
  164. if h.Mappings == nil {
  165. h.Mappings = make([]*Mapping, 0)
  166. }
  167. h.Mappings = append(h.Mappings, &Mapping{t, regexp.MustCompile("/v(\\d+)/" + re), f})
  168. }
  169. func (h *Handler) doHandle(w http.ResponseWriter, r *http.Request) (ok bool) {
  170. for _, mapping := range h.Mappings {
  171. if r.Method != mapping.Method {
  172. continue
  173. }
  174. if res := mapping.Regexp.FindAllStringSubmatch(r.URL.String(), -1); len(res) > 0 {
  175. mapping.Handler(w, r, res)
  176. return true
  177. }
  178. }
  179. return false
  180. }
  181. func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  182. started := time.Now()
  183. uuid := GenerateUUID()
  184. w.Header().Add("X-Request-ID", uuid)
  185. logger.Info(fmt.Sprintf("%s got request %s %s", uuid, r.Method, r.URL.String()))
  186. if ok := h.doHandle(w, r); !ok {
  187. logger.Info("returning 404")
  188. http.NotFound(w, r)
  189. }
  190. logger.Info(fmt.Sprintf("%s finished request in %.06f", uuid, time.Now().Sub(started).Seconds()))
  191. }
  192. func NewHandler(dataDir string) (handler *Handler) {
  193. handler = &Handler{DataDir: dataDir}
  194. // dummies
  195. handler.Map("GET", "_ping", handler.GetPing)
  196. handler.Map("GET", "users", handler.GetUsers)
  197. // images
  198. handler.Map("GET", "images/(.*?)/ancestry", handler.GetImageAncestry)
  199. handler.Map("GET", "images/(.*?)/layer", handler.GetImageLayer)
  200. handler.Map("GET", "images/(.*?)/json", handler.GetImageJson)
  201. handler.Map("PUT", "images/(.*?)/(.*)", handler.PutImageResource)
  202. // repositories
  203. handler.Map("GET", "repositories/library/(.*?)/tags", handler.GetRepositoryTags)
  204. handler.Map("GET", "repositories/(.*?)/tags", handler.GetRepositoryTags)
  205. handler.Map("GET", "repositories/(.*?)/images", handler.GetRepositoryImages)
  206. handler.Map("PUT", "repositories/(.*?)/tags/(.*)", handler.PutRepositoryTags)
  207. handler.Map("PUT", "repositories/(.*?)/images", handler.PutRepositoryImages)
  208. handler.Map("PUT", "repositories/(.*?)/$", handler.PutRepository)
  209. return
  210. }