Signed-off-by: Doug Davis <dug@us.ibm.com>
| ... | ... |
@@ -51,6 +51,24 @@ func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
|
| 51 | 51 |
return conn, conn, nil |
| 52 | 52 |
} |
| 53 | 53 |
|
| 54 |
+// Check to make sure request's Content-Type is application/json |
|
| 55 |
+func checkForJson(r *http.Request) error {
|
|
| 56 |
+ ct := r.Header.Get("Content-Type")
|
|
| 57 |
+ |
|
| 58 |
+ // No Content-Type header is ok as long as there's no Body |
|
| 59 |
+ if ct == "" {
|
|
| 60 |
+ if r.Body == nil || r.ContentLength == 0 {
|
|
| 61 |
+ return nil |
|
| 62 |
+ } |
|
| 63 |
+ } |
|
| 64 |
+ |
|
| 65 |
+ // Otherwise it better be json |
|
| 66 |
+ if api.MatchesContentType(ct, "application/json") {
|
|
| 67 |
+ return nil |
|
| 68 |
+ } |
|
| 69 |
+ return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
|
|
| 70 |
+} |
|
| 71 |
+ |
|
| 54 | 72 |
//If we don't do this, POST method without Content-type (even with empty body) will fail |
| 55 | 73 |
func parseForm(r *http.Request) error {
|
| 56 | 74 |
if r == nil {
|
| ... | ... |
@@ -445,6 +463,11 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit |
| 445 | 445 |
job = eng.Job("commit", r.Form.Get("container"))
|
| 446 | 446 |
stdoutBuffer = bytes.NewBuffer(nil) |
| 447 | 447 |
) |
| 448 |
+ |
|
| 449 |
+ if err := checkForJson(r); err != nil {
|
|
| 450 |
+ return err |
|
| 451 |
+ } |
|
| 452 |
+ |
|
| 448 | 453 |
if err := config.Decode(r.Body); err != nil {
|
| 449 | 454 |
log.Errorf("%s", err)
|
| 450 | 455 |
} |
| ... | ... |
@@ -651,6 +674,11 @@ func postContainersCreate(eng *engine.Engine, version version.Version, w http.Re |
| 651 | 651 |
stdoutBuffer = bytes.NewBuffer(nil) |
| 652 | 652 |
warnings = bytes.NewBuffer(nil) |
| 653 | 653 |
) |
| 654 |
+ |
|
| 655 |
+ if err := checkForJson(r); err != nil {
|
|
| 656 |
+ return err |
|
| 657 |
+ } |
|
| 658 |
+ |
|
| 654 | 659 |
if err := job.DecodeEnv(r.Body); err != nil {
|
| 655 | 660 |
return err |
| 656 | 661 |
} |
| ... | ... |
@@ -734,8 +762,8 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res |
| 734 | 734 |
|
| 735 | 735 |
// allow a nil body for backwards compatibility |
| 736 | 736 |
if r.Body != nil && r.ContentLength > 0 {
|
| 737 |
- if !api.MatchesContentType(r.Header.Get("Content-Type"), "application/json") {
|
|
| 738 |
- return fmt.Errorf("Content-Type of application/json is required")
|
|
| 737 |
+ if err := checkForJson(r); err != nil {
|
|
| 738 |
+ return err |
|
| 739 | 739 |
} |
| 740 | 740 |
|
| 741 | 741 |
if err := job.DecodeEnv(r.Body); err != nil {
|
| ... | ... |
@@ -1001,12 +1029,12 @@ func postContainersCopy(eng *engine.Engine, version version.Version, w http.Resp |
| 1001 | 1001 |
|
| 1002 | 1002 |
var copyData engine.Env |
| 1003 | 1003 |
|
| 1004 |
- if contentType := r.Header.Get("Content-Type"); api.MatchesContentType(contentType, "application/json") {
|
|
| 1005 |
- if err := copyData.Decode(r.Body); err != nil {
|
|
| 1006 |
- return err |
|
| 1007 |
- } |
|
| 1008 |
- } else {
|
|
| 1009 |
- return fmt.Errorf("Content-Type not supported: %s", contentType)
|
|
| 1004 |
+ if err := checkForJson(r); err != nil {
|
|
| 1005 |
+ return err |
|
| 1006 |
+ } |
|
| 1007 |
+ |
|
| 1008 |
+ if err := copyData.Decode(r.Body); err != nil {
|
|
| 1009 |
+ return err |
|
| 1010 | 1010 |
} |
| 1011 | 1011 |
|
| 1012 | 1012 |
if copyData.Get("Resource") == "" {
|
| ... | ... |
@@ -1043,6 +1071,7 @@ func postContainerExecCreate(eng *engine.Engine, version version.Version, w http |
| 1043 | 1043 |
job = eng.Job("execCreate", name)
|
| 1044 | 1044 |
stdoutBuffer = bytes.NewBuffer(nil) |
| 1045 | 1045 |
) |
| 1046 |
+ |
|
| 1046 | 1047 |
if err := job.DecodeEnv(r.Body); err != nil {
|
| 1047 | 1048 |
return err |
| 1048 | 1049 |
} |
| ... | ... |
@@ -1068,6 +1097,7 @@ func postContainerExecStart(eng *engine.Engine, version version.Version, w http. |
| 1068 | 1068 |
job = eng.Job("execStart", name)
|
| 1069 | 1069 |
errOut io.Writer = os.Stderr |
| 1070 | 1070 |
) |
| 1071 |
+ |
|
| 1071 | 1072 |
if err := job.DecodeEnv(r.Body); err != nil {
|
| 1072 | 1073 |
return err |
| 1073 | 1074 |
} |
| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
"net" |
| 10 | 10 |
"net/http" |
| 11 | 11 |
"net/http/httptest" |
| 12 |
+ "strings" |
|
| 12 | 13 |
"testing" |
| 13 | 14 |
"time" |
| 14 | 15 |
|
| ... | ... |
@@ -356,6 +357,8 @@ func TestPostContainersCreate(t *testing.T) {
|
| 356 | 356 |
t.Fatal(err) |
| 357 | 357 |
} |
| 358 | 358 |
|
| 359 |
+ req.Header.Set("Content-Type", "application/json")
|
|
| 360 |
+ |
|
| 359 | 361 |
r := httptest.NewRecorder() |
| 360 | 362 |
if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
|
| 361 | 363 |
t.Fatal(err) |
| ... | ... |
@@ -379,6 +382,49 @@ func TestPostContainersCreate(t *testing.T) {
|
| 379 | 379 |
} |
| 380 | 380 |
} |
| 381 | 381 |
|
| 382 |
+func TestPostJsonVerify(t *testing.T) {
|
|
| 383 |
+ eng := NewTestEngine(t) |
|
| 384 |
+ defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 385 |
+ |
|
| 386 |
+ configJSON, err := json.Marshal(&runconfig.Config{
|
|
| 387 |
+ Image: unitTestImageID, |
|
| 388 |
+ Memory: 33554432, |
|
| 389 |
+ Cmd: []string{"touch", "/test"},
|
|
| 390 |
+ }) |
|
| 391 |
+ if err != nil {
|
|
| 392 |
+ t.Fatal(err) |
|
| 393 |
+ } |
|
| 394 |
+ |
|
| 395 |
+ req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
|
|
| 396 |
+ if err != nil {
|
|
| 397 |
+ t.Fatal(err) |
|
| 398 |
+ } |
|
| 399 |
+ |
|
| 400 |
+ r := httptest.NewRecorder() |
|
| 401 |
+ |
|
| 402 |
+ if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
|
|
| 403 |
+ t.Fatal(err) |
|
| 404 |
+ } |
|
| 405 |
+ |
|
| 406 |
+ // Don't add Content-Type header |
|
| 407 |
+ // req.Header.Set("Content-Type", "application/json")
|
|
| 408 |
+ |
|
| 409 |
+ err = server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 410 |
+ if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
|
|
| 411 |
+ t.Fatal("Create should have failed due to no Content-Type header - got:", r)
|
|
| 412 |
+ } |
|
| 413 |
+ |
|
| 414 |
+ // Now add header but with wrong type and retest |
|
| 415 |
+ req.Header.Set("Content-Type", "application/xml")
|
|
| 416 |
+ |
|
| 417 |
+ if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
|
|
| 418 |
+ t.Fatal(err) |
|
| 419 |
+ } |
|
| 420 |
+ if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
|
|
| 421 |
+ t.Fatal("Create should have failed due to wrong Content-Type header - got:", r)
|
|
| 422 |
+ } |
|
| 423 |
+} |
|
| 424 |
+ |
|
| 382 | 425 |
func TestPostContainersKill(t *testing.T) {
|
| 383 | 426 |
eng := NewTestEngine(t) |
| 384 | 427 |
defer mkDaemonFromEngine(eng, t).Nuke() |