github.com/uppal0016/docker_new@v0.0.0-20240123060250-1c98be13ac2c/api/server/router/image/image_routes.go (about) 1 package image 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "io" 8 "net/http" 9 "net/url" 10 "strings" 11 12 "github.com/docker/distribution/registry/api/errcode" 13 "github.com/docker/docker/api/server/httputils" 14 "github.com/docker/docker/api/types/backend" 15 "github.com/docker/docker/pkg/ioutils" 16 "github.com/docker/docker/pkg/streamformatter" 17 "github.com/docker/engine-api/types" 18 "github.com/docker/engine-api/types/container" 19 "golang.org/x/net/context" 20 ) 21 22 func (s *imageRouter) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 23 if err := httputils.ParseForm(r); err != nil { 24 return err 25 } 26 27 if err := httputils.CheckForJSON(r); err != nil { 28 return err 29 } 30 31 cname := r.Form.Get("container") 32 33 pause := httputils.BoolValue(r, "pause") 34 version := httputils.VersionFromContext(ctx) 35 if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") { 36 pause = true 37 } 38 39 c, _, _, err := s.decoder.DecodeConfig(r.Body) 40 if err != nil && err != io.EOF { //Do not fail if body is empty. 41 return err 42 } 43 if c == nil { 44 c = &container.Config{} 45 } 46 47 commitCfg := &backend.ContainerCommitConfig{ 48 ContainerCommitConfig: types.ContainerCommitConfig{ 49 Pause: pause, 50 Repo: r.Form.Get("repo"), 51 Tag: r.Form.Get("tag"), 52 Author: r.Form.Get("author"), 53 Comment: r.Form.Get("comment"), 54 Config: c, 55 MergeConfigs: true, 56 }, 57 Changes: r.Form["changes"], 58 } 59 60 imgID, err := s.backend.Commit(cname, commitCfg) 61 if err != nil { 62 return err 63 } 64 65 return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerCommitResponse{ 66 ID: string(imgID), 67 }) 68 } 69 70 // Creates an image from Pull or from Import 71 func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 72 if err := httputils.ParseForm(r); err != nil { 73 return err 74 } 75 76 var ( 77 image = r.Form.Get("fromImage") 78 repo = r.Form.Get("repo") 79 tag = r.Form.Get("tag") 80 message = r.Form.Get("message") 81 err error 82 output = ioutils.NewWriteFlusher(w) 83 ) 84 defer output.Close() 85 86 w.Header().Set("Content-Type", "application/json") 87 88 if image != "" { //pull 89 metaHeaders := map[string][]string{} 90 for k, v := range r.Header { 91 if strings.HasPrefix(k, "X-Meta-") { 92 metaHeaders[k] = v 93 } 94 } 95 96 authEncoded := r.Header.Get("X-Registry-Auth") 97 authConfig := &types.AuthConfig{} 98 if authEncoded != "" { 99 authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) 100 if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil { 101 // for a pull it is not an error if no auth was given 102 // to increase compatibility with the existing api it is defaulting to be empty 103 authConfig = &types.AuthConfig{} 104 } 105 } 106 107 err = s.backend.PullImage(ctx, image, tag, metaHeaders, authConfig, output) 108 109 // Check the error from pulling an image to make sure the request 110 // was authorized. Modify the status if the request was 111 // unauthorized to respond with 401 rather than 500. 112 if err != nil && isAuthorizedError(err) { 113 err = errcode.ErrorCodeUnauthorized.WithMessage(fmt.Sprintf("Authentication is required: %s", err)) 114 } 115 } else { //import 116 src := r.Form.Get("fromSrc") 117 // 'err' MUST NOT be defined within this block, we need any error 118 // generated from the download to be available to the output 119 // stream processing below 120 err = s.backend.ImportImage(src, repo, tag, message, r.Body, output, r.Form["changes"]) 121 } 122 if err != nil { 123 if !output.Flushed() { 124 return err 125 } 126 sf := streamformatter.NewJSONStreamFormatter() 127 output.Write(sf.FormatError(err)) 128 } 129 130 return nil 131 } 132 133 func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 134 metaHeaders := map[string][]string{} 135 for k, v := range r.Header { 136 if strings.HasPrefix(k, "X-Meta-") { 137 metaHeaders[k] = v 138 } 139 } 140 if err := httputils.ParseForm(r); err != nil { 141 return err 142 } 143 authConfig := &types.AuthConfig{} 144 145 authEncoded := r.Header.Get("X-Registry-Auth") 146 if authEncoded != "" { 147 // the new format is to handle the authConfig as a header 148 authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) 149 if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil { 150 // to increase compatibility to existing api it is defaulting to be empty 151 authConfig = &types.AuthConfig{} 152 } 153 } else { 154 // the old format is supported for compatibility if there was no authConfig header 155 if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil { 156 return fmt.Errorf("Bad parameters and missing X-Registry-Auth: %v", err) 157 } 158 } 159 160 image := vars["name"] 161 tag := r.Form.Get("tag") 162 163 output := ioutils.NewWriteFlusher(w) 164 defer output.Close() 165 166 w.Header().Set("Content-Type", "application/json") 167 168 if err := s.backend.PushImage(ctx, image, tag, metaHeaders, authConfig, output); err != nil { 169 if !output.Flushed() { 170 return err 171 } 172 sf := streamformatter.NewJSONStreamFormatter() 173 output.Write(sf.FormatError(err)) 174 } 175 return nil 176 } 177 178 func (s *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 179 if err := httputils.ParseForm(r); err != nil { 180 return err 181 } 182 183 w.Header().Set("Content-Type", "application/x-tar") 184 185 output := ioutils.NewWriteFlusher(w) 186 defer output.Close() 187 var names []string 188 if name, ok := vars["name"]; ok { 189 names = []string{name} 190 } else { 191 names = r.Form["names"] 192 } 193 194 if err := s.backend.ExportImage(names, output); err != nil { 195 if !output.Flushed() { 196 return err 197 } 198 sf := streamformatter.NewJSONStreamFormatter() 199 output.Write(sf.FormatError(err)) 200 } 201 return nil 202 } 203 204 func (s *imageRouter) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 205 if err := httputils.ParseForm(r); err != nil { 206 return err 207 } 208 quiet := httputils.BoolValueOrDefault(r, "quiet", true) 209 210 if !quiet { 211 w.Header().Set("Content-Type", "application/json") 212 213 output := ioutils.NewWriteFlusher(w) 214 defer output.Close() 215 if err := s.backend.LoadImage(r.Body, output, quiet); err != nil { 216 output.Write(streamformatter.NewJSONStreamFormatter().FormatError(err)) 217 } 218 return nil 219 } 220 return s.backend.LoadImage(r.Body, w, quiet) 221 } 222 223 func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 224 if err := httputils.ParseForm(r); err != nil { 225 return err 226 } 227 228 name := vars["name"] 229 230 if strings.TrimSpace(name) == "" { 231 return fmt.Errorf("image name cannot be blank") 232 } 233 234 force := httputils.BoolValue(r, "force") 235 prune := !httputils.BoolValue(r, "noprune") 236 237 list, err := s.backend.ImageDelete(name, force, prune) 238 if err != nil { 239 return err 240 } 241 242 return httputils.WriteJSON(w, http.StatusOK, list) 243 } 244 245 func (s *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 246 imageInspect, err := s.backend.LookupImage(vars["name"]) 247 if err != nil { 248 return err 249 } 250 251 return httputils.WriteJSON(w, http.StatusOK, imageInspect) 252 } 253 254 func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 255 if err := httputils.ParseForm(r); err != nil { 256 return err 257 } 258 259 // FIXME: The filter parameter could just be a match filter 260 images, err := s.backend.Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all")) 261 if err != nil { 262 return err 263 } 264 265 return httputils.WriteJSON(w, http.StatusOK, images) 266 } 267 268 func (s *imageRouter) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 269 name := vars["name"] 270 history, err := s.backend.ImageHistory(name) 271 if err != nil { 272 return err 273 } 274 275 return httputils.WriteJSON(w, http.StatusOK, history) 276 } 277 278 func (s *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 279 if err := httputils.ParseForm(r); err != nil { 280 return err 281 } 282 if err := s.backend.TagImage(vars["name"], r.Form.Get("repo"), r.Form.Get("tag")); err != nil { 283 return err 284 } 285 w.WriteHeader(http.StatusCreated) 286 return nil 287 } 288 289 func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 290 if err := httputils.ParseForm(r); err != nil { 291 return err 292 } 293 var ( 294 config *types.AuthConfig 295 authEncoded = r.Header.Get("X-Registry-Auth") 296 headers = map[string][]string{} 297 ) 298 299 if authEncoded != "" { 300 authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) 301 if err := json.NewDecoder(authJSON).Decode(&config); err != nil { 302 // for a search it is not an error if no auth was given 303 // to increase compatibility with the existing api it is defaulting to be empty 304 config = &types.AuthConfig{} 305 } 306 } 307 for k, v := range r.Header { 308 if strings.HasPrefix(k, "X-Meta-") { 309 headers[k] = v 310 } 311 } 312 query, err := s.backend.SearchRegistryForImages(ctx, r.Form.Get("term"), config, headers) 313 if err != nil { 314 return err 315 } 316 return httputils.WriteJSON(w, http.StatusOK, query.Results) 317 } 318 319 func isAuthorizedError(err error) bool { 320 if urlError, ok := err.(*url.Error); ok { 321 err = urlError.Err 322 } 323 324 if dError, ok := err.(errcode.Error); ok { 325 if dError.ErrorCode() == errcode.ErrorCodeUnauthorized { 326 return true 327 } 328 } 329 return false 330 }