mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #1594 from unihorn/201
etcdhttp/etcdserver: support HEAD on /v2/keys/ namespace
This commit is contained in:
commit
ac49e1d50f
@ -93,7 +93,7 @@ type keysHandler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *keysHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *keysHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if !allowMethod(w, r.Method, "GET", "PUT", "POST", "DELETE") {
|
if !allowMethod(w, r.Method, "HEAD", "GET", "PUT", "POST", "DELETE") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("X-Etcd-Cluster-ID", h.clusterInfo.ID().String())
|
w.Header().Set("X-Etcd-Cluster-ID", h.clusterInfo.ID().String())
|
||||||
|
@ -63,6 +63,18 @@ func mustNewForm(t *testing.T, p string, vals url.Values) *http.Request {
|
|||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mustNewPostForm takes a set of Values and constructs a POST *http.Request,
|
||||||
|
// with a URL constructed from appending the given path to the standard keysPrefix
|
||||||
|
func mustNewPostForm(t *testing.T, p string, vals url.Values) *http.Request {
|
||||||
|
u := mustNewURL(t, path.Join(keysPrefix, p))
|
||||||
|
req, err := http.NewRequest("POST", u.String(), strings.NewReader(vals.Encode()))
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error creating new request: %v", err)
|
||||||
|
}
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
// mustNewRequest takes a path, appends it to the standard keysPrefix, and constructs
|
// mustNewRequest takes a path, appends it to the standard keysPrefix, and constructs
|
||||||
// a GET *http.Request referencing the resulting URL
|
// a GET *http.Request referencing the resulting URL
|
||||||
func mustNewRequest(t *testing.T, p string) *http.Request {
|
func mustNewRequest(t *testing.T, p string) *http.Request {
|
||||||
@ -1171,6 +1183,55 @@ func TestBadServeKeys(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServeKeysGood(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
req *http.Request
|
||||||
|
wcode int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
mustNewMethodRequest(t, "HEAD", "foo"),
|
||||||
|
http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewMethodRequest(t, "GET", "foo"),
|
||||||
|
http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewForm(t, "foo", url.Values{"value": []string{"bar"}}),
|
||||||
|
http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewMethodRequest(t, "DELETE", "foo"),
|
||||||
|
http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mustNewPostForm(t, "foo", url.Values{"value": []string{"bar"}}),
|
||||||
|
http.StatusOK,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
server := &resServer{
|
||||||
|
etcdserver.Response{
|
||||||
|
Event: &store.Event{
|
||||||
|
Action: store.Get,
|
||||||
|
Node: &store.NodeExtern{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
h := &keysHandler{
|
||||||
|
timeout: time.Hour,
|
||||||
|
server: server,
|
||||||
|
timer: &dummyRaftTimer{},
|
||||||
|
clusterInfo: &fakeCluster{id: 1},
|
||||||
|
}
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(rw, tt.req)
|
||||||
|
if rw.Code != tt.wcode {
|
||||||
|
t.Errorf("#%d: got code=%d, want %d", i, rw.Code, tt.wcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestServeKeysEvent(t *testing.T) {
|
func TestServeKeysEvent(t *testing.T) {
|
||||||
req := mustNewRequest(t, "foo")
|
req := mustNewRequest(t, "foo")
|
||||||
server := &resServer{
|
server := &resServer{
|
||||||
|
@ -409,6 +409,12 @@ func (s *EtcdServer) Do(ctx context.Context, r pb.Request) (Response, error) {
|
|||||||
}
|
}
|
||||||
return Response{Event: ev}, nil
|
return Response{Event: ev}, nil
|
||||||
}
|
}
|
||||||
|
case "HEAD":
|
||||||
|
ev, err := s.store.Get(r.Path, r.Recursive, r.Sorted)
|
||||||
|
if err != nil {
|
||||||
|
return Response{}, err
|
||||||
|
}
|
||||||
|
return Response{Event: ev}, nil
|
||||||
default:
|
default:
|
||||||
return Response{}, ErrUnknownMethod
|
return Response{}, ErrUnknownMethod
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,16 @@ func TestDoLocalAction(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pb.Request{Method: "HEAD", ID: 1},
|
||||||
|
Response{Event: &store.Event{}}, nil,
|
||||||
|
[]action{
|
||||||
|
action{
|
||||||
|
name: "Get",
|
||||||
|
params: []interface{}{"", false, false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
pb.Request{Method: "BADMETHOD", ID: 1},
|
pb.Request{Method: "BADMETHOD", ID: 1},
|
||||||
Response{}, ErrUnknownMethod, []action{},
|
Response{}, ErrUnknownMethod, []action{},
|
||||||
@ -127,6 +137,10 @@ func TestDoBadLocalAction(t *testing.T) {
|
|||||||
pb.Request{Method: "GET", ID: 1},
|
pb.Request{Method: "GET", ID: 1},
|
||||||
[]action{action{name: "Get"}},
|
[]action{action{name: "Get"}},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pb.Request{Method: "HEAD", ID: 1},
|
||||||
|
[]action{action{name: "Get"}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
st := &errStoreRecorder{err: storeErr}
|
st := &errStoreRecorder{err: storeErr}
|
||||||
|
@ -912,8 +912,6 @@ func TestV2WatchKeyInDir(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jonboulle): enable once #1590 is fixed
|
|
||||||
/*
|
|
||||||
func TestV2Head(t *testing.T) {
|
func TestV2Head(t *testing.T) {
|
||||||
cl := cluster{Size: 1}
|
cl := cluster{Size: 1}
|
||||||
cl.Launch(t)
|
cl.Launch(t)
|
||||||
@ -930,8 +928,8 @@ func TestV2Head(t *testing.T) {
|
|||||||
if resp.StatusCode != http.StatusNotFound {
|
if resp.StatusCode != http.StatusNotFound {
|
||||||
t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusNotFound)
|
t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusNotFound)
|
||||||
}
|
}
|
||||||
if resp.ContentLength != -1 {
|
if resp.ContentLength <= 0 {
|
||||||
t.Errorf("ContentLength = %d, want -1", resp.ContentLength)
|
t.Errorf("ContentLength = %d, want > 0", resp.ContentLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, _ = tc.PutForm(fullURL, v)
|
resp, _ = tc.PutForm(fullURL, v)
|
||||||
@ -942,11 +940,10 @@ func TestV2Head(t *testing.T) {
|
|||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusOK)
|
t.Errorf("status = %d, want %d", resp.StatusCode, http.StatusOK)
|
||||||
}
|
}
|
||||||
if resp.ContentLength != -1 {
|
if resp.ContentLength <= 0 {
|
||||||
t.Errorf("ContentLength = %d, want -1", resp.ContentLength)
|
t.Errorf("ContentLength = %d, want > 0", resp.ContentLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
func checkBody(body map[string]interface{}, w map[string]interface{}) error {
|
func checkBody(body map[string]interface{}, w map[string]interface{}) error {
|
||||||
if body["node"] != nil {
|
if body["node"] != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user