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  }