From 5fbef59dbc2db6a2b48947ef615a67f927e152f9 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Mon, 3 Nov 2014 15:43:54 -0800 Subject: [PATCH] error: use application/json as the content-type Fixes #1584 --- error/error.go | 35 +++++++++++++++++------------- error/error_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 error/error_test.go diff --git a/error/error.go b/error/error.go index 33869de07..beb21d924 100644 --- a/error/error.go +++ b/error/error.go @@ -63,6 +63,16 @@ var errors = map[int]string{ EcodeClientInternal: "Client Internal Error", } +var errorStatus = map[int]int{ + EcodeKeyNotFound: http.StatusNotFound, + EcodeNotFile: http.StatusForbidden, + EcodeDirNotEmpty: http.StatusForbidden, + EcodeTestFailed: http.StatusPreconditionFailed, + EcodeNodeExist: http.StatusPreconditionFailed, + EcodeRaftInternal: http.StatusInternalServerError, + EcodeLeaderElect: http.StatusInternalServerError, +} + const ( EcodeKeyNotFound = 100 EcodeTestFailed = 101 @@ -133,22 +143,17 @@ func (e Error) toJsonString() string { return string(b) } +func (e Error) statusCode() int { + status, ok := errorStatus[e.ErrorCode] + if !ok { + status = http.StatusBadRequest + } + return status +} + func (e Error) WriteTo(w http.ResponseWriter) { w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index)) - // 3xx is raft internal error - status := http.StatusBadRequest - switch e.ErrorCode { - case EcodeKeyNotFound: - status = http.StatusNotFound - case EcodeNotFile, EcodeDirNotEmpty: - status = http.StatusForbidden - case EcodeTestFailed, EcodeNodeExist: - status = http.StatusPreconditionFailed - default: - if e.ErrorCode/100 == 3 { - status = http.StatusInternalServerError - } - } - w.WriteHeader(status) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(e.statusCode()) fmt.Fprintln(w, e.toJsonString()) } diff --git a/error/error_test.go b/error/error_test.go new file mode 100644 index 000000000..e1cfa124f --- /dev/null +++ b/error/error_test.go @@ -0,0 +1,52 @@ +/* + Copyright 2014 CoreOS, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package error + +import ( + "net/http" + "net/http/httptest" + "reflect" + "strings" + "testing" +) + +func TestErrorWriteTo(t *testing.T) { + for k, _ := range errors { + err := NewError(k, "", 1) + rr := httptest.NewRecorder() + err.WriteTo(rr) + + if err.statusCode() != rr.Code { + t.Errorf("HTTP status code %d, want %d", rr.Code, err.statusCode()) + } + + gbody := strings.TrimSuffix(rr.Body.String(), "\n") + if err.toJsonString() != gbody { + t.Errorf("HTTP body %q, want %q", gbody, err.toJsonString()) + } + + wheader := http.Header(map[string][]string{ + "Content-Type": []string{"application/json"}, + "X-Etcd-Index": []string{"1"}, + }) + + if !reflect.DeepEqual(wheader, rr.HeaderMap) { + t.Errorf("HTTP headers %v, want %v", rr.HeaderMap, wheader) + } + } + +}