diff --git a/state/remote/http.go b/state/remote/http.go index b30c15590c..6473d24771 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 15e5e8bfec..214dffa5c5 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" @@ -31,6 +32,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, @@ -52,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) { @@ -134,12 +156,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 { @@ -157,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))) + } +}