Skip to content

Commit a4daf00

Browse files
jacksontjkrasi-georgiev
authored andcommitted
Implement POST with get fallback for Query/QueryRange (#557)
* Implement POST with get fallback for Query/QueryRange Signed-off-by: Thomas Jackson <jacksontj.89@gmail.com>
1 parent f951755 commit a4daf00

File tree

6 files changed

+115
-19
lines changed

6 files changed

+115
-19
lines changed

api/client.go

+22
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,28 @@ type Client interface {
5858
Do(context.Context, *http.Request) (*http.Response, []byte, error)
5959
}
6060

61+
// DoGetFallback will attempt to do the request as-is, and on a 405 it will fallback to a GET request.
62+
func DoGetFallback(c Client, ctx context.Context, u *url.URL, args url.Values) (*http.Response, []byte, error) {
63+
req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(args.Encode()))
64+
if err != nil {
65+
return nil, nil, err
66+
}
67+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
68+
69+
resp, body, err := c.Do(ctx, req)
70+
if resp != nil && resp.StatusCode == http.StatusMethodNotAllowed {
71+
u.RawQuery = args.Encode()
72+
req, err = http.NewRequest(http.MethodGet, u.String(), nil)
73+
if err != nil {
74+
return nil, nil, err
75+
}
76+
77+
} else {
78+
return resp, body, err
79+
}
80+
return c.Do(ctx, req)
81+
}
82+
6183
// NewClient returns a new Client.
6284
//
6385
// It is safe to use the returned Client from multiple goroutines.

api/client_test.go

+72
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@
1414
package api
1515

1616
import (
17+
"context"
18+
"encoding/json"
1719
"net/http"
20+
"net/http/httptest"
1821
"net/url"
1922
"testing"
23+
24+
"github.com/prometheus/tsdb/testutil"
2025
)
2126

2227
func TestConfig(t *testing.T) {
@@ -111,3 +116,70 @@ func TestClientURL(t *testing.T) {
111116
}
112117
}
113118
}
119+
120+
func TestDoGetFallback(t *testing.T) {
121+
v := url.Values{"a": []string{"1", "2"}}
122+
123+
type testResponse struct {
124+
Values string
125+
Method string
126+
}
127+
128+
// Start a local HTTP server.
129+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
130+
req.ParseForm()
131+
r := &testResponse{
132+
Values: req.Form.Encode(),
133+
Method: req.Method,
134+
}
135+
136+
body, _ := json.Marshal(r)
137+
138+
if req.Method == http.MethodPost {
139+
if req.URL.Path == "/blockPost" {
140+
http.Error(w, string(body), http.StatusMethodNotAllowed)
141+
return
142+
}
143+
}
144+
145+
w.Write(body)
146+
}))
147+
// Close the server when test finishes.
148+
defer server.Close()
149+
150+
u, err := url.Parse(server.URL)
151+
testutil.Ok(t, err)
152+
client := &httpClient{client: *(server.Client())}
153+
154+
// Do a post, and ensure that the post succeeds.
155+
_, b, err := DoGetFallback(client, context.TODO(), u, v)
156+
if err != nil {
157+
t.Fatalf("Error doing local request: %v", err)
158+
}
159+
resp := &testResponse{}
160+
if err := json.Unmarshal(b, resp); err != nil {
161+
testutil.Ok(t, err)
162+
}
163+
if resp.Method != http.MethodPost {
164+
t.Fatalf("Mismatch method")
165+
}
166+
if resp.Values != v.Encode() {
167+
t.Fatalf("Mismatch in values")
168+
}
169+
170+
// Do a fallbcak to a get.
171+
u.Path = "/blockPost"
172+
_, b, err = DoGetFallback(client, context.TODO(), u, v)
173+
if err != nil {
174+
t.Fatalf("Error doing local request: %v", err)
175+
}
176+
if err := json.Unmarshal(b, resp); err != nil {
177+
testutil.Ok(t, err)
178+
}
179+
if resp.Method != http.MethodGet {
180+
t.Fatalf("Mismatch method")
181+
}
182+
if resp.Values != v.Encode() {
183+
t.Fatalf("Mismatch in values")
184+
}
185+
}

api/prometheus/v1/api.go

+2-14
Original file line numberDiff line numberDiff line change
@@ -540,12 +540,7 @@ func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.
540540

541541
u.RawQuery = q.Encode()
542542

543-
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
544-
if err != nil {
545-
return nil, err
546-
}
547-
548-
_, body, err := h.client.Do(ctx, req)
543+
_, body, err := api.DoGetFallback(h.client, ctx, u, q)
549544
if err != nil {
550545
return nil, err
551546
}
@@ -571,14 +566,7 @@ func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model.
571566
q.Set("end", end)
572567
q.Set("step", step)
573568

574-
u.RawQuery = q.Encode()
575-
576-
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
577-
if err != nil {
578-
return nil, err
579-
}
580-
581-
_, body, err := h.client.Do(ctx, req)
569+
_, body, err := api.DoGetFallback(h.client, ctx, u, q)
582570
if err != nil {
583571
return nil, err
584572
}

api/prometheus/v1/api_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ func TestAPIs(t *testing.T) {
179179
},
180180
},
181181

182-
reqMethod: "GET",
182+
reqMethod: "POST",
183183
reqPath: "/api/v1/query",
184184
reqParam: url.Values{
185185
"query": []string{"2"},
@@ -194,7 +194,7 @@ func TestAPIs(t *testing.T) {
194194
do: doQuery("2", testTime),
195195
inErr: fmt.Errorf("some error"),
196196

197-
reqMethod: "GET",
197+
reqMethod: "POST",
198198
reqPath: "/api/v1/query",
199199
reqParam: url.Values{
200200
"query": []string{"2"},
@@ -212,7 +212,7 @@ func TestAPIs(t *testing.T) {
212212
Detail: "some body",
213213
},
214214

215-
reqMethod: "GET",
215+
reqMethod: "POST",
216216
reqPath: "/api/v1/query",
217217
reqParam: url.Values{
218218
"query": []string{"2"},
@@ -230,7 +230,7 @@ func TestAPIs(t *testing.T) {
230230
Detail: "some body",
231231
},
232232

233-
reqMethod: "GET",
233+
reqMethod: "POST",
234234
reqPath: "/api/v1/query",
235235
reqParam: url.Values{
236236
"query": []string{"2"},
@@ -247,7 +247,7 @@ func TestAPIs(t *testing.T) {
247247
}),
248248
inErr: fmt.Errorf("some error"),
249249

250-
reqMethod: "GET",
250+
reqMethod: "POST",
251251
reqPath: "/api/v1/query_range",
252252
reqParam: url.Values{
253253
"query": []string{"2"},

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ require (
66
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
77
github.com/prometheus/common v0.3.0
88
github.com/prometheus/procfs v0.0.0-20190412120340-e22ddced7142
9+
github.com/prometheus/tsdb v0.7.1
910
)

go.sum

+13
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1+
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
12
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
23
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
34
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
45
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
56
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
67
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
8+
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
79
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10+
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
11+
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
812
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
13+
github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
914
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
15+
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
1016
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
1117
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
1218
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
@@ -15,23 +21,29 @@ github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg
1521
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
1622
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
1723
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
24+
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
1825
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
1926
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
2027
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
2128
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
29+
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
2230
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
2331
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2432
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
2533
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
2634
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
2735
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
2836
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
37+
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
2938
github.com/prometheus/common v0.3.0 h1:taZ4h8Tkxv2kNyoSctBvfXEHmBmxrwmIidZTIaHons4=
3039
github.com/prometheus/common v0.3.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
3140
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
3241
github.com/prometheus/procfs v0.0.0-20190412120340-e22ddced7142 h1:JO6VBMEDSBX/LT4GKwSdvuFigZNwVD4lkPyUE4BDCKE=
3342
github.com/prometheus/procfs v0.0.0-20190412120340-e22ddced7142/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
43+
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
44+
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
3445
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
46+
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
3547
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
3648
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
3749
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -41,6 +53,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
4153
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
4254
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
4355
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
56+
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
4457
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
4558
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
4659
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

0 commit comments

Comments
 (0)