瀏覽代碼

Merge pull request #8235 from duglin/Issue2515

Add checks for app/json - issue #2515
Victor Vieux 10 年之前
父節點
當前提交
e2728d9892
共有 2 個文件被更改,包括 84 次插入8 次删除
  1. 38 8
      api/server/server.go
  2. 46 0
      integration/api_test.go

+ 38 - 8
api/server/server.go

@@ -51,6 +51,24 @@ func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
 	return conn, conn, nil
 }
 
+// Check to make sure request's Content-Type is application/json
+func checkForJson(r *http.Request) error {
+	ct := r.Header.Get("Content-Type")
+
+	// No Content-Type header is ok as long as there's no Body
+	if ct == "" {
+		if r.Body == nil || r.ContentLength == 0 {
+			return nil
+		}
+	}
+
+	// Otherwise it better be json
+	if api.MatchesContentType(ct, "application/json") {
+		return nil
+	}
+	return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
+}
+
 //If we don't do this, POST method without Content-type (even with empty body) will fail
 func parseForm(r *http.Request) error {
 	if r == nil {
@@ -445,6 +463,11 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit
 		job          = eng.Job("commit", r.Form.Get("container"))
 		stdoutBuffer = bytes.NewBuffer(nil)
 	)
+
+	if err := checkForJson(r); err != nil {
+		return err
+	}
+
 	if err := config.Decode(r.Body); err != nil {
 		log.Errorf("%s", err)
 	}
@@ -651,6 +674,11 @@ func postContainersCreate(eng *engine.Engine, version version.Version, w http.Re
 		stdoutBuffer = bytes.NewBuffer(nil)
 		warnings     = bytes.NewBuffer(nil)
 	)
+
+	if err := checkForJson(r); err != nil {
+		return err
+	}
+
 	if err := job.DecodeEnv(r.Body); err != nil {
 		return err
 	}
@@ -734,8 +762,8 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res
 
 	// allow a nil body for backwards compatibility
 	if r.Body != nil && r.ContentLength > 0 {
-		if !api.MatchesContentType(r.Header.Get("Content-Type"), "application/json") {
-			return fmt.Errorf("Content-Type of application/json is required")
+		if err := checkForJson(r); err != nil {
+			return err
 		}
 
 		if err := job.DecodeEnv(r.Body); err != nil {
@@ -1001,12 +1029,12 @@ func postContainersCopy(eng *engine.Engine, version version.Version, w http.Resp
 
 	var copyData engine.Env
 
-	if contentType := r.Header.Get("Content-Type"); api.MatchesContentType(contentType, "application/json") {
-		if err := copyData.Decode(r.Body); err != nil {
-			return err
-		}
-	} else {
-		return fmt.Errorf("Content-Type not supported: %s", contentType)
+	if err := checkForJson(r); err != nil {
+		return err
+	}
+
+	if err := copyData.Decode(r.Body); err != nil {
+		return err
 	}
 
 	if copyData.Get("Resource") == "" {
@@ -1043,6 +1071,7 @@ func postContainerExecCreate(eng *engine.Engine, version version.Version, w http
 		job          = eng.Job("execCreate", name)
 		stdoutBuffer = bytes.NewBuffer(nil)
 	)
+
 	if err := job.DecodeEnv(r.Body); err != nil {
 		return err
 	}
@@ -1068,6 +1097,7 @@ func postContainerExecStart(eng *engine.Engine, version version.Version, w http.
 		job              = eng.Job("execStart", name)
 		errOut io.Writer = os.Stderr
 	)
+
 	if err := job.DecodeEnv(r.Body); err != nil {
 		return err
 	}

+ 46 - 0
integration/api_test.go

@@ -9,6 +9,7 @@ import (
 	"net"
 	"net/http"
 	"net/http/httptest"
+	"strings"
 	"testing"
 	"time"
 
@@ -356,6 +357,8 @@ func TestPostContainersCreate(t *testing.T) {
 		t.Fatal(err)
 	}
 
+	req.Header.Set("Content-Type", "application/json")
+
 	r := httptest.NewRecorder()
 	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
 		t.Fatal(err)
@@ -379,6 +382,49 @@ func TestPostContainersCreate(t *testing.T) {
 	}
 }
 
+func TestPostJsonVerify(t *testing.T) {
+	eng := NewTestEngine(t)
+	defer mkDaemonFromEngine(eng, t).Nuke()
+
+	configJSON, err := json.Marshal(&runconfig.Config{
+		Image:  unitTestImageID,
+		Memory: 33554432,
+		Cmd:    []string{"touch", "/test"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	r := httptest.NewRecorder()
+
+	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
+		t.Fatal(err)
+	}
+
+	// Don't add Content-Type header
+	// req.Header.Set("Content-Type", "application/json")
+
+	err = server.ServeRequest(eng, api.APIVERSION, r, req)
+	if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
+		t.Fatal("Create should have failed due to no Content-Type header - got:", r)
+	}
+
+	// Now add header but with wrong type and retest
+	req.Header.Set("Content-Type", "application/xml")
+
+	if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
+		t.Fatal(err)
+	}
+	if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
+		t.Fatal("Create should have failed due to wrong Content-Type header - got:", r)
+	}
+}
+
 func TestPostContainersKill(t *testing.T) {
 	eng := NewTestEngine(t)
 	defer mkDaemonFromEngine(eng, t).Nuke()