From b3d432e6bc9ef21e6f75e35a4476946008724dc3 Mon Sep 17 00:00:00 2001 From: jwa Date: Thu, 11 Jan 2018 22:09:59 +0000 Subject: [PATCH 1/2] allow HTTP 201 & 204 when storing remote state Apache mod_dav returns 201 (created) and 204 (no content) during PUTs; treat these as valid responses when using Apache as a http backend. --- state/remote/http.go | 2 +- state/remote/http_test.go | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/state/remote/http.go b/state/remote/http.go index b30c15590..6473d2477 100644 --- a/state/remote/http.go +++ b/state/remote/http.go @@ -313,7 +313,7 @@ func (c *HTTPClient) Put(data []byte) error { // Handle the error codes switch resp.StatusCode { - case http.StatusOK: + case http.StatusOK, http.StatusCreated, http.StatusNoContent: return nil default: return fmt.Errorf("HTTP error: %d", resp.StatusCode) diff --git a/state/remote/http_test.go b/state/remote/http_test.go index 15e5e8bfe..904d830b1 100644 --- a/state/remote/http_test.go +++ b/state/remote/http_test.go @@ -31,6 +31,14 @@ func TestHTTPClient(t *testing.T) { client := &HTTPClient{URL: url, Client: cleanhttp.DefaultClient()} testClient(t, client) + // test just a single PUT + p := &HTTPClient{ + URL: url, + UpdateMethod: "PUT", + Client: cleanhttp.DefaultClient(), + } + testClient(t, p) + // Test locking and alternative UpdateMethod a := &HTTPClient{ URL: url, @@ -134,12 +142,18 @@ func (h *testHTTPHandler) Handle(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": w.Write(h.Data) - case "POST", "PUT": + case "PUT": + buf := new(bytes.Buffer) + if _, err := io.Copy(buf, r.Body); err != nil { + w.WriteHeader(500) + } + w.WriteHeader(201) + h.Data = buf.Bytes() + case "POST": buf := new(bytes.Buffer) if _, err := io.Copy(buf, r.Body); err != nil { w.WriteHeader(500) } - h.Data = buf.Bytes() case "LOCK": if h.Locked { From 3d4642719f273a97c1c65c142c476bda52d4821c Mon Sep 17 00:00:00 2001 From: jwa Date: Fri, 19 Jan 2018 02:30:21 +0000 Subject: [PATCH 2/2] simulate a webdav backend --- state/remote/http_test.go | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/state/remote/http_test.go b/state/remote/http_test.go index 904d830b1..214dffa5c 100644 --- a/state/remote/http_test.go +++ b/state/remote/http_test.go @@ -7,6 +7,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "reflect" "testing" "github.com/hashicorp/go-cleanhttp" @@ -60,6 +61,19 @@ func TestHTTPClient(t *testing.T) { } TestRemoteLocks(t, a, b) + // test a WebDAV-ish backend + davhandler := new(testHTTPHandler) + ts = httptest.NewServer(http.HandlerFunc(davhandler.HandleWebDAV)) + defer ts.Close() + + url, err = url.Parse(ts.URL) + c := &HTTPClient{ + URL: url, + UpdateMethod: "PUT", + Client: cleanhttp.DefaultClient(), + } + testClient(t, c) // first time through: 201 + testClient(t, c) // second time, with identical data: 204 } func assertError(t *testing.T, err error, expected string) { @@ -171,3 +185,29 @@ func (h *testHTTPHandler) Handle(w http.ResponseWriter, r *http.Request) { w.Write([]byte(fmt.Sprintf("Unknown method: %s", r.Method))) } } + +// mod_dav-ish behavior +func (h *testHTTPHandler) HandleWebDAV(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + w.Write(h.Data) + case "PUT": + buf := new(bytes.Buffer) + if _, err := io.Copy(buf, r.Body); err != nil { + w.WriteHeader(500) + } + if reflect.DeepEqual(h.Data, buf.Bytes()) { + h.Data = buf.Bytes() + w.WriteHeader(204) + } else { + h.Data = buf.Bytes() + w.WriteHeader(201) + } + case "DELETE": + h.Data = nil + w.WriteHeader(200) + default: + w.WriteHeader(500) + w.Write([]byte(fmt.Sprintf("Unknown method: %s", r.Method))) + } +}