Ejemplo n.º 1
0
func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, corsHeaders string, dockerVersion version.Version) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// log the request
		log.Debugf("Calling %s %s", localMethod, localRoute)

		if logging {
			log.Infof("%s %s", r.Method, r.RequestURI)
		}

		if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
			userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
			if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
				log.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
			}
		}
		version := version.Version(mux.Vars(r)["version"])
		if version == "" {
			version = api.APIVERSION
		}
		if corsHeaders != "" {
			writeCorsHeaders(w, r, corsHeaders)
		}

		if version.GreaterThan(api.APIVERSION) {
			http.Error(w, fmt.Errorf("client and server don't have same version (client : %s, server: %s)", version, api.APIVERSION).Error(), http.StatusNotFound)
			return
		}

		if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil {
			log.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err)
			httpError(w, err)
		}
	}
}
Ejemplo n.º 2
0
func handlerPutImage(w http.ResponseWriter, r *http.Request) {
	if !requiresAuth(w, r) {
		return
	}
	vars := mux.Vars(r)
	imageID := vars["image_id"]
	action := vars["action"]
	layer, exists := testLayers[imageID]
	if !exists {
		if action != "json" {
			http.NotFound(w, r)
			return
		}
		layer = make(map[string]string)
		testLayers[imageID] = layer
	}
	if checksum := r.Header.Get("X-Docker-Checksum"); checksum != "" {
		if checksum != layer["checksum_simple"] && checksum != layer["checksum_tarsum"] {
			apiError(w, "Wrong checksum", 400)
			return
		}
	}
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		apiError(w, fmt.Sprintf("Error: %s", err), 500)
		return
	}
	layer[action] = string(body)
	writeResponse(w, true, 200)
}
Ejemplo n.º 3
0
func (s *DockerServer) inspectContainer(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	container, _, err := s.findContainer(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(container)
}
Ejemplo n.º 4
0
func (s *DockerServer) pushImage(w http.ResponseWriter, r *http.Request) {
	name := mux.Vars(r)["name"]
	s.iMut.RLock()
	if _, ok := s.imgIDs[name]; !ok {
		s.iMut.RUnlock()
		http.Error(w, "No such image", http.StatusNotFound)
		return
	}
	s.iMut.RUnlock()
	fmt.Fprintln(w, "Pushing...")
	fmt.Fprintln(w, "Pushed")
}
Ejemplo n.º 5
0
func handlerGetImage(w http.ResponseWriter, r *http.Request) {
	if !requiresAuth(w, r) {
		return
	}
	vars := mux.Vars(r)
	layer, exists := testLayers[vars["image_id"]]
	if !exists {
		http.NotFound(w, r)
		return
	}
	writeHeaders(w)
	layerSize := len(layer["layer"])
	w.Header().Add("X-Docker-Size", strconv.Itoa(layerSize))
	io.WriteString(w, layer[vars["action"]])
}
Ejemplo n.º 6
0
func (s *DockerServer) unpauseContainer(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	container, _, err := s.findContainer(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	s.cMut.Lock()
	defer s.cMut.Unlock()
	if !container.State.Paused {
		http.Error(w, "Container not paused", http.StatusBadRequest)
		return
	}
	w.WriteHeader(http.StatusNoContent)
	container.State.Paused = false
}
Ejemplo n.º 7
0
func (s *DockerServer) startContainer(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	container, _, err := s.findContainer(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	s.cMut.Lock()
	defer s.cMut.Unlock()
	if container.State.Running {
		http.Error(w, "Container already running", http.StatusBadRequest)
		return
	}
	container.State.Running = true
	s.notify(container)
}
Ejemplo n.º 8
0
func handlerPutTag(w http.ResponseWriter, r *http.Request) {
	if !requiresAuth(w, r) {
		return
	}
	vars := mux.Vars(r)
	repositoryName := vars["repository"]
	tagName := vars["tag"]
	tags, exists := testRepositories[repositoryName]
	if !exists {
		tags := make(map[string]string)
		testRepositories[repositoryName] = tags
	}
	tagValue := ""
	readJSON(r, tagValue)
	tags[tagName] = tagValue
	writeResponse(w, true, 200)
}
Ejemplo n.º 9
0
func handlerGetDeleteTags(w http.ResponseWriter, r *http.Request) {
	if !requiresAuth(w, r) {
		return
	}
	repositoryName := mux.Vars(r)["repository"]
	tags, exists := testRepositories[repositoryName]
	if !exists {
		apiError(w, "Repository not found", 404)
		return
	}
	if r.Method == "DELETE" {
		delete(testRepositories, repositoryName)
		writeResponse(w, true, 200)
		return
	}
	writeResponse(w, tags, 200)
}
Ejemplo n.º 10
0
func (s *DockerServer) attachContainer(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	container, _, err := s.findContainer(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	outStream := newStdWriter(w, stdout)
	fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
	if container.State.Running {
		fmt.Fprintf(outStream, "Container %q is running\n", container.ID)
	} else {
		fmt.Fprintf(outStream, "Container %q is not running\n", container.ID)
	}
	fmt.Fprintln(outStream, "What happened?")
	fmt.Fprintln(outStream, "Something happened")
}
Ejemplo n.º 11
0
func (s *DockerServer) stopContainer(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	container, _, err := s.findContainer(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	s.cMut.Lock()
	defer s.cMut.Unlock()
	if !container.State.Running {
		http.Error(w, "Container not running", http.StatusBadRequest)
		return
	}
	w.WriteHeader(http.StatusNoContent)
	container.State.Running = false
	s.notify(container)
}
Ejemplo n.º 12
0
func (s *DockerServer) inspectImage(w http.ResponseWriter, r *http.Request) {
	name := mux.Vars(r)["name"]
	if id, ok := s.imgIDs[name]; ok {
		s.iMut.Lock()
		defer s.iMut.Unlock()

		for _, img := range s.images {
			if img.ID == id {
				w.Header().Set("Content-Type", "application/json")
				w.WriteHeader(http.StatusOK)
				json.NewEncoder(w).Encode(img)
				return
			}
		}
	}
	http.Error(w, "not found", http.StatusNotFound)
}
Ejemplo n.º 13
0
func (s *DockerServer) removeContainer(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	_, index, err := s.findContainer(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	if s.containers[index].State.Running {
		msg := "Error: API error (406): Impossible to remove a running container, please stop it first"
		http.Error(w, msg, http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusNoContent)
	s.cMut.Lock()
	defer s.cMut.Unlock()
	s.containers[index] = s.containers[len(s.containers)-1]
	s.containers = s.containers[:len(s.containers)-1]
}
Ejemplo n.º 14
0
func handlerGetTag(w http.ResponseWriter, r *http.Request) {
	if !requiresAuth(w, r) {
		return
	}
	vars := mux.Vars(r)
	repositoryName := vars["repository"]
	tagName := vars["tag"]
	tags, exists := testRepositories[repositoryName]
	if !exists {
		apiError(w, "Repository not found", 404)
		return
	}
	tag, exists := tags[tagName]
	if !exists {
		apiError(w, "Tag not found", 404)
		return
	}
	writeResponse(w, tag, 200)
}
Ejemplo n.º 15
0
func (s *DockerServer) waitContainer(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	container, _, err := s.findContainer(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	for {
		time.Sleep(1e6)
		s.cMut.RLock()
		if !container.State.Running {
			s.cMut.RUnlock()
			break
		}
		s.cMut.RUnlock()
	}
	result := map[string]int{"StatusCode": container.State.ExitCode}
	json.NewEncoder(w).Encode(result)
}
Ejemplo n.º 16
0
func (s *DockerServer) removeImage(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	s.iMut.RLock()
	var tag string
	if img, ok := s.imgIDs[id]; ok {
		id, tag = img, id
	}
	s.iMut.RUnlock()
	_, index, err := s.findImageByID(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	w.WriteHeader(http.StatusNoContent)
	s.iMut.Lock()
	defer s.iMut.Unlock()
	s.images[index] = s.images[len(s.images)-1]
	s.images = s.images[:len(s.images)-1]
	if tag != "" {
		delete(s.imgIDs, tag)
	}
}
Ejemplo n.º 17
0
// TestRouter registers a test handler with all the routes and ensures that
// each route returns the expected path variables. Not method verification is
// present. This not meant to be exhaustive but as check to ensure that the
// expected variables are extracted.
//
// This may go away as the application structure comes together.
func TestRouter(t *testing.T) {

	router := Router()

	testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		testCase := routeTestCase{
			RequestURI: r.RequestURI,
			Vars:       mux.Vars(r),
			RouteName:  mux.CurrentRoute(r).GetName(),
		}

		enc := json.NewEncoder(w)

		if err := enc.Encode(testCase); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	})

	// Startup test server
	server := httptest.NewServer(router)

	for _, testcase := range []routeTestCase{
		{
			RouteName:  RouteNameBase,
			RequestURI: "/v2/",
			Vars:       map[string]string{},
		},
		{
			RouteName:  RouteNameManifest,
			RequestURI: "/v2/foo/manifests/bar",
			Vars: map[string]string{
				"name":      "foo",
				"reference": "bar",
			},
		},
		{
			RouteName:  RouteNameManifest,
			RequestURI: "/v2/foo/bar/manifests/tag",
			Vars: map[string]string{
				"name":      "foo/bar",
				"reference": "tag",
			},
		},
		{
			RouteName:  RouteNameTags,
			RequestURI: "/v2/foo/bar/tags/list",
			Vars: map[string]string{
				"name": "foo/bar",
			},
		},
		{
			RouteName:  RouteNameBlob,
			RequestURI: "/v2/foo/bar/blobs/tarsum.dev+foo:abcdef0919234",
			Vars: map[string]string{
				"name":   "foo/bar",
				"digest": "tarsum.dev+foo:abcdef0919234",
			},
		},
		{
			RouteName:  RouteNameBlob,
			RequestURI: "/v2/foo/bar/blobs/sha256:abcdef0919234",
			Vars: map[string]string{
				"name":   "foo/bar",
				"digest": "sha256:abcdef0919234",
			},
		},
		{
			RouteName:  RouteNameBlobUpload,
			RequestURI: "/v2/foo/bar/blobs/uploads/",
			Vars: map[string]string{
				"name": "foo/bar",
			},
		},
		{
			RouteName:  RouteNameBlobUploadChunk,
			RequestURI: "/v2/foo/bar/blobs/uploads/uuid",
			Vars: map[string]string{
				"name": "foo/bar",
				"uuid": "uuid",
			},
		},
		{
			RouteName:  RouteNameBlobUploadChunk,
			RequestURI: "/v2/foo/bar/blobs/uploads/D95306FA-FAD3-4E36-8D41-CF1C93EF8286",
			Vars: map[string]string{
				"name": "foo/bar",
				"uuid": "D95306FA-FAD3-4E36-8D41-CF1C93EF8286",
			},
		},
		{
			RouteName:  RouteNameBlobUploadChunk,
			RequestURI: "/v2/foo/bar/blobs/uploads/RDk1MzA2RkEtRkFEMy00RTM2LThENDEtQ0YxQzkzRUY4Mjg2IA==",
			Vars: map[string]string{
				"name": "foo/bar",
				"uuid": "RDk1MzA2RkEtRkFEMy00RTM2LThENDEtQ0YxQzkzRUY4Mjg2IA==",
			},
		},
		{
			// Check ambiguity: ensure we can distinguish between tags for
			// "foo/bar/image/image" and image for "foo/bar/image" with tag
			// "tags"
			RouteName:  RouteNameManifest,
			RequestURI: "/v2/foo/bar/manifests/manifests/tags",
			Vars: map[string]string{
				"name":      "foo/bar/manifests",
				"reference": "tags",
			},
		},
		{
			// This case presents an ambiguity between foo/bar with tag="tags"
			// and list tags for "foo/bar/manifest"
			RouteName:  RouteNameTags,
			RequestURI: "/v2/foo/bar/manifests/tags/list",
			Vars: map[string]string{
				"name": "foo/bar/manifests",
			},
		},
		{
			RouteName:  RouteNameBlobUploadChunk,
			RequestURI: "/v2/foo/../../blob/uploads/D95306FA-FAD3-4E36-8D41-CF1C93EF8286",
			StatusCode: http.StatusNotFound,
		},
	} {
		// Register the endpoint
		router.GetRoute(testcase.RouteName).Handler(testHandler)
		u := server.URL + testcase.RequestURI

		resp, err := http.Get(u)

		if err != nil {
			t.Fatalf("error issuing get request: %v", err)
		}

		if testcase.StatusCode == 0 {
			// Override default, zero-value
			testcase.StatusCode = http.StatusOK
		}

		if resp.StatusCode != testcase.StatusCode {
			t.Fatalf("unexpected status for %s: %v %v", u, resp.Status, resp.StatusCode)
		}

		if testcase.StatusCode != http.StatusOK {
			// We don't care about json response.
			continue
		}

		dec := json.NewDecoder(resp.Body)

		var actualRouteInfo routeTestCase
		if err := dec.Decode(&actualRouteInfo); err != nil {
			t.Fatalf("error reading json response: %v", err)
		}
		// Needs to be set out of band
		actualRouteInfo.StatusCode = resp.StatusCode

		if actualRouteInfo.RouteName != testcase.RouteName {
			t.Fatalf("incorrect route %q matched, expected %q", actualRouteInfo.RouteName, testcase.RouteName)
		}

		if !reflect.DeepEqual(actualRouteInfo, testcase) {
			t.Fatalf("actual does not equal expected: %#v != %#v", actualRouteInfo, testcase)
		}
	}

}