Skip to content

Commit 0836f37

Browse files
committed
fix: Allow OPTIONS method on every path
Signed-off-by: Célian Garcia <[email protected]>
1 parent 2e50cb2 commit 0836f37

File tree

2 files changed

+61
-14
lines changed

2 files changed

+61
-14
lines changed

Diff for: injectproxy/routes.go

+18-14
Original file line numberDiff line numberDiff line change
@@ -315,21 +315,21 @@ func NewRoutes(upstream *url.URL, label string, extractLabeler ExtractLabeler, o
315315
mux := newStrictMux(newInstrumentedMux(http.NewServeMux(), opt.registerer))
316316

317317
errs := merrors.New(
318-
mux.Handle("/federate", r.el.ExtractLabel(enforceMethods(r.matcher, "GET"))),
319-
mux.Handle("/api/v1/query", r.el.ExtractLabel(enforceMethods(r.query, "GET", "POST"))),
320-
mux.Handle("/api/v1/query_range", r.el.ExtractLabel(enforceMethods(r.query, "GET", "POST"))),
321-
mux.Handle("/api/v1/alerts", r.el.ExtractLabel(enforceMethods(r.passthrough, "GET"))),
322-
mux.Handle("/api/v1/rules", r.el.ExtractLabel(enforceMethods(r.passthrough, "GET"))),
323-
mux.Handle("/api/v1/series", r.el.ExtractLabel(enforceMethods(r.matcher, "GET", "POST"))),
324-
mux.Handle("/api/v1/query_exemplars", r.el.ExtractLabel(enforceMethods(r.query, "GET", "POST"))),
318+
mux.Handle("/federate", r.el.ExtractLabel(r.enforceMethods(r.matcher, "GET"))),
319+
mux.Handle("/api/v1/query", r.el.ExtractLabel(r.enforceMethods(r.query, "GET", "POST"))),
320+
mux.Handle("/api/v1/query_range", r.el.ExtractLabel(r.enforceMethods(r.query, "GET", "POST"))),
321+
mux.Handle("/api/v1/alerts", r.el.ExtractLabel(r.enforceMethods(r.passthrough, "GET"))),
322+
mux.Handle("/api/v1/rules", r.el.ExtractLabel(r.enforceMethods(r.passthrough, "GET"))),
323+
mux.Handle("/api/v1/series", r.el.ExtractLabel(r.enforceMethods(r.matcher, "GET", "POST"))),
324+
mux.Handle("/api/v1/query_exemplars", r.el.ExtractLabel(r.enforceMethods(r.query, "GET", "POST"))),
325325
)
326326

327327
if opt.enableLabelAPIs {
328328
errs.Add(
329-
mux.Handle("/api/v1/labels", r.el.ExtractLabel(enforceMethods(r.matcher, "GET", "POST"))),
329+
mux.Handle("/api/v1/labels", r.el.ExtractLabel(r.enforceMethods(r.matcher, "GET", "POST"))),
330330
// Full path is /api/v1/label/<label_name>/values but http mux does not support patterns.
331331
// This is fine though as we don't care about name for matcher injector.
332-
mux.Handle("/api/v1/label/", r.el.ExtractLabel(enforceMethods(r.matcher, "GET"))),
332+
mux.Handle("/api/v1/label/", r.el.ExtractLabel(r.enforceMethods(r.matcher, "GET"))),
333333
)
334334
}
335335

@@ -338,22 +338,22 @@ func NewRoutes(upstream *url.URL, label string, extractLabeler ExtractLabeler, o
338338
// semantics of the Silences API don't support multi-label matchers.
339339
mux.Handle("/api/v2/silences", r.el.ExtractLabel(
340340
r.errorIfRegexpMatch(
341-
enforceMethods(
341+
r.enforceMethods(
342342
assertSingleLabelValue(r.silences),
343343
"GET", "POST",
344344
),
345345
),
346346
)),
347347
mux.Handle("/api/v2/silence/", r.el.ExtractLabel(
348348
r.errorIfRegexpMatch(
349-
enforceMethods(
349+
r.enforceMethods(
350350
assertSingleLabelValue(r.deleteSilence),
351351
"DELETE",
352352
),
353353
),
354354
)),
355-
mux.Handle("/api/v2/alerts/groups", r.el.ExtractLabel(enforceMethods(r.enforceFilterParameter, "GET"))),
356-
mux.Handle("/api/v2/alerts", r.el.ExtractLabel(enforceMethods(r.alerts, "GET"))),
355+
mux.Handle("/api/v2/alerts/groups", r.el.ExtractLabel(r.enforceMethods(r.enforceFilterParameter, "GET"))),
356+
mux.Handle("/api/v2/alerts", r.el.ExtractLabel(r.enforceMethods(r.alerts, "GET"))),
357357
)
358358

359359
errs.Add(
@@ -422,8 +422,12 @@ func (r *routes) errorHandler(rw http.ResponseWriter, _ *http.Request, err error
422422
rw.WriteHeader(http.StatusBadGateway)
423423
}
424424

425-
func enforceMethods(h http.HandlerFunc, methods ...string) http.HandlerFunc {
425+
func (r *routes) enforceMethods(h http.HandlerFunc, methods ...string) http.HandlerFunc {
426426
return func(w http.ResponseWriter, req *http.Request) {
427+
if req.Method == http.MethodOptions {
428+
r.passthrough(w, req)
429+
return
430+
}
427431
for _, m := range methods {
428432
if m == req.Method {
429433
h(w, req)

Diff for: injectproxy/routes_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323
"strings"
2424
"testing"
2525
"time"
26+
27+
"gotest.tools/v3/assert"
2628
)
2729

2830
var okResponse = []byte(`ok`)
@@ -1334,3 +1336,44 @@ func TestQuery(t *testing.T) {
13341336
}
13351337
}
13361338
}
1339+
1340+
func TestOptionsHTTPMethod(t *testing.T) {
1341+
m := newMockUpstream(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
1342+
w.Header().Add("Access-Control-Allow-Origin", "*")
1343+
w.Write(okResponse)
1344+
}))
1345+
defer m.Close()
1346+
r, err := NewRoutes(m.url, proxyLabel, StaticLabelEnforcer{proxyLabel})
1347+
if err != nil {
1348+
t.Fatalf("unexpected error: %v", err)
1349+
}
1350+
1351+
for _, tcase := range []struct {
1352+
url string
1353+
method string
1354+
expCode int
1355+
}{
1356+
{
1357+
url: "http://prometheus.example.com/api/v1/query", method: http.MethodOptions,
1358+
expCode: http.StatusOK,
1359+
},
1360+
{
1361+
url: "http://prometheus.example.com/foo/bar", method: http.MethodOptions,
1362+
expCode: http.StatusNotFound,
1363+
},
1364+
} {
1365+
t.Run(tcase.url, func(t *testing.T) {
1366+
w := httptest.NewRecorder()
1367+
r.ServeHTTP(w, httptest.NewRequest(tcase.method, tcase.url, nil))
1368+
resp := w.Result()
1369+
1370+
if resp.StatusCode != tcase.expCode {
1371+
b, err := io.ReadAll(resp.Body)
1372+
fmt.Println(string(b), err)
1373+
t.Fatalf("expected status code %v, got %d", tcase.expCode, resp.StatusCode)
1374+
} else if resp.StatusCode == http.StatusOK {
1375+
assert.Equal(t, resp.Header.Get("Access-Control-Allow-Origin"), "*")
1376+
}
1377+
})
1378+
}
1379+
}

0 commit comments

Comments
 (0)