From d06690eb9022871475d9f30e1fdc389b22abdf77 Mon Sep 17 00:00:00 2001 From: Thomas Jackson Date: Tue, 23 Apr 2019 16:40:27 -0700 Subject: [PATCH] Implement POST with get fallback for Query/QueryRange Signed-off-by: Thomas Jackson Fixes #428 --- api/client.go | 22 ++++++++++++++++++++++ api/prometheus/v1/api.go | 16 ++-------------- api/prometheus/v1/api_test.go | 10 +++++----- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/api/client.go b/api/client.go index 9d5b1879c..b12d6617b 100644 --- a/api/client.go +++ b/api/client.go @@ -60,6 +60,28 @@ type Client interface { Do(context.Context, *http.Request) (*http.Response, []byte, error) } +// DoGetFallback will attempt to do the request as-is, and on a 405 it will fallback to a GET request +func DoGetFallback(c Client, ctx context.Context, u *url.URL, args url.Values) (*http.Response, []byte, error) { + req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(args.Encode())) + if err != nil { + return nil, nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + resp, body, err := c.Do(ctx, req) + if resp != nil && resp.StatusCode == http.StatusMethodNotAllowed { + u.RawQuery = args.Encode() + req, err = http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + return nil, nil, err + } + + } else { + return resp, body, err + } + return c.Do(ctx, req) +} + // NewClient returns a new Client. // // It is safe to use the returned Client from multiple goroutines. diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index c0481797e..32aa49f0c 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -542,12 +542,7 @@ func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model. u.RawQuery = q.Encode() - req, err := http.NewRequest(http.MethodGet, u.String(), nil) - if err != nil { - return nil, err - } - - _, body, err := h.client.Do(ctx, req) + _, body, err := api.DoGetFallback(h.client, ctx, u, q) if err != nil { return nil, err } @@ -573,14 +568,7 @@ func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model. q.Set("end", end) q.Set("step", step) - u.RawQuery = q.Encode() - - req, err := http.NewRequest(http.MethodGet, u.String(), nil) - if err != nil { - return nil, err - } - - _, body, err := h.client.Do(ctx, req) + _, body, err := api.DoGetFallback(h.client, ctx, u, q) if err != nil { return nil, err } diff --git a/api/prometheus/v1/api_test.go b/api/prometheus/v1/api_test.go index fec170ede..ca5c5a745 100644 --- a/api/prometheus/v1/api_test.go +++ b/api/prometheus/v1/api_test.go @@ -181,7 +181,7 @@ func TestAPIs(t *testing.T) { }, }, - reqMethod: "GET", + reqMethod: "POST", reqPath: "/api/v1/query", reqParam: url.Values{ "query": []string{"2"}, @@ -196,7 +196,7 @@ func TestAPIs(t *testing.T) { do: doQuery("2", testTime), inErr: fmt.Errorf("some error"), - reqMethod: "GET", + reqMethod: "POST", reqPath: "/api/v1/query", reqParam: url.Values{ "query": []string{"2"}, @@ -214,7 +214,7 @@ func TestAPIs(t *testing.T) { Detail: "some body", }, - reqMethod: "GET", + reqMethod: "POST", reqPath: "/api/v1/query", reqParam: url.Values{ "query": []string{"2"}, @@ -232,7 +232,7 @@ func TestAPIs(t *testing.T) { Detail: "some body", }, - reqMethod: "GET", + reqMethod: "POST", reqPath: "/api/v1/query", reqParam: url.Values{ "query": []string{"2"}, @@ -249,7 +249,7 @@ func TestAPIs(t *testing.T) { }), inErr: fmt.Errorf("some error"), - reqMethod: "GET", + reqMethod: "POST", reqPath: "/api/v1/query_range", reqParam: url.Values{ "query": []string{"2"},