Skip to content

Commit 35476d2

Browse files
jRiestpatryk
authored andcommitted
Fix API token support for create/update/list worker routes (cloudflare#369)
Previously, creating or updating a worker route would default to the deprecated `filters` endpoints when Enabled == false and ScriptName == "". This would cause errors when using API tokens since the filter endpoints don't support API tokens. This change will use the `routes` endpoints in that scenario instead, which do support API tokens. It also updates `ListWorkerRoutes` to use the `routes` endpoint instead of `filters` when an API token is supplied. Deleting worker routes suffers from the same problem, but that will be fixed in cloudflare#367
1 parent 6d259c5 commit 35476d2

File tree

2 files changed

+80
-20
lines changed

2 files changed

+80
-20
lines changed

workers.go

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ type WorkerScriptParams struct {
3030
Bindings map[string]WorkerBinding
3131
}
3232

33-
// WorkerRoute aka filters are patterns used to enable or disable workers that match requests.
33+
// WorkerRoute is used to map traffic matching a URL pattern to a workers
3434
//
35-
// API reference: https://api.cloudflare.com/#worker-filters-properties
35+
// API reference: https://api.cloudflare.com/#worker-routes-properties
3636
type WorkerRoute struct {
3737
ID string `json:"id,omitempty"`
3838
Pattern string `json:"pattern"`
39-
Enabled bool `json:"enabled"`
39+
Enabled bool `json:"enabled"` // this is deprecated: https://api.cloudflare.com/#worker-filters-deprecated--properties
4040
Script string `json:"script,omitempty"`
4141
}
4242

@@ -566,14 +566,9 @@ func formatMultipartBody(params *WorkerScriptParams) (string, []byte, error) {
566566
//
567567
// API reference: https://api.cloudflare.com/#worker-filters-create-filter, https://api.cloudflare.com/#worker-routes-create-route
568568
func (api *API) CreateWorkerRoute(zoneID string, route WorkerRoute) (WorkerRouteResponse, error) {
569-
// Check whether a script name is defined in order to determine whether
570-
// to use the single-script or multi-script endpoint.
571-
pathComponent := "filters"
572-
if route.Script != "" {
573-
if api.AccountID == "" {
574-
return WorkerRouteResponse{}, errors.New("account ID required for enterprise only request")
575-
}
576-
pathComponent = "routes"
569+
pathComponent, err := getRouteEndpoint(api, route)
570+
if err != nil {
571+
return WorkerRouteResponse{}, err
577572
}
578573

579574
uri := "/zones/" + zoneID + "/workers/" + pathComponent
@@ -611,7 +606,16 @@ func (api *API) DeleteWorkerRoute(zoneID string, routeID string) (WorkerRouteRes
611606
// API reference: https://api.cloudflare.com/#worker-filters-list-filters, https://api.cloudflare.com/#worker-routes-list-routes
612607
func (api *API) ListWorkerRoutes(zoneID string) (WorkerRoutesResponse, error) {
613608
pathComponent := "filters"
614-
if api.AccountID != "" {
609+
// Unfortunately we don't have a good signal of whether the user is wanting
610+
// to use the deprecated filters endpoint (https://api.cloudflare.com/#worker-filters-list-filters)
611+
// or the multi-script routes endpoint (https://api.cloudflare.com/#worker-script-list-workers)
612+
//
613+
// The filters endpoint does not support API tokens, so if an API token is specified we need to use
614+
// the routes endpoint. Otherwise, since the multi-script API endpoints that operate on a script
615+
// require an AccountID, we assume that anyone specifying an AccountID is using the routes endpoint.
616+
// This is likely too presumptuous. In the next major version, we should just remove the deprecated
617+
// filter endpoints entirely to avoid this ambiguity.
618+
if api.AccountID != "" || api.APIToken != "" {
615619
pathComponent = "routes"
616620
}
617621
uri := "/zones/" + zoneID + "/workers/" + pathComponent
@@ -640,14 +644,9 @@ func (api *API) ListWorkerRoutes(zoneID string) (WorkerRoutesResponse, error) {
640644
//
641645
// API reference: https://api.cloudflare.com/#worker-filters-update-filter, https://api.cloudflare.com/#worker-routes-update-route
642646
func (api *API) UpdateWorkerRoute(zoneID string, routeID string, route WorkerRoute) (WorkerRouteResponse, error) {
643-
// Check whether a script name is defined in order to determine whether
644-
// to use the single-script or multi-script endpoint.
645-
pathComponent := "filters"
646-
if route.Script != "" {
647-
if api.AccountID == "" {
648-
return WorkerRouteResponse{}, errors.New("account ID required for enterprise only request")
649-
}
650-
pathComponent = "routes"
647+
pathComponent, err := getRouteEndpoint(api, route)
648+
if err != nil {
649+
return WorkerRouteResponse{}, err
651650
}
652651
uri := "/zones/" + zoneID + "/workers/" + pathComponent + "/" + routeID
653652
res, err := api.makeRequest("PUT", uri, route)
@@ -661,3 +660,18 @@ func (api *API) UpdateWorkerRoute(zoneID string, routeID string, route WorkerRou
661660
}
662661
return r, nil
663662
}
663+
664+
func getRouteEndpoint(api *API, route WorkerRoute) (string, error) {
665+
if route.Script != "" && route.Enabled == true {
666+
return "", errors.New("Only `Script` or `Enabled` may be specified for a WorkerRoute, not both")
667+
}
668+
669+
// For backwards-compatability, fallback to the deprecated filter
670+
// endpoint if Enabled == true
671+
// https://api.cloudflare.com/#worker-filters-deprecated--properties
672+
if route.Enabled == true {
673+
return "filters", nil
674+
}
675+
676+
return "routes", nil
677+
}

workers_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,29 @@ func TestWorkers_CreateWorkerRouteSingleScriptWithAccount(t *testing.T) {
628628
}
629629
}
630630

631+
func TestWorkers_CreateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties(t *testing.T) {
632+
setup(UsingAccount("foo"))
633+
defer teardown()
634+
635+
route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script", Enabled: true}
636+
_, err := client.CreateWorkerRoute("foo", route)
637+
assert.EqualError(t, err, "Only `Script` or `Enabled` may be specified for a WorkerRoute, not both")
638+
}
639+
640+
func TestWorkers_CreateWorkerRouteWithNoScript(t *testing.T) {
641+
setup(UsingAccount("foo"))
642+
643+
mux.HandleFunc("/zones/foo/workers/routes", func(w http.ResponseWriter, r *http.Request) {
644+
assert.Equal(t, "POST", r.Method, "Expected method 'POST', got %s", r.Method)
645+
w.Header().Set("content-type", "application-json")
646+
fmt.Fprintf(w, createWorkerRouteResponse)
647+
})
648+
649+
route := WorkerRoute{Pattern: "app1.example.com/*"}
650+
_, err := client.CreateWorkerRoute("foo", route)
651+
assert.NoError(t, err)
652+
}
653+
631654
func TestWorkers_DeleteWorkerRoute(t *testing.T) {
632655
setup()
633656
defer teardown()
@@ -822,3 +845,26 @@ func TestWorkers_ListWorkerBindingsMultiScript(t *testing.T) {
822845
})
823846
assert.Equal(t, WorkerInheritBindingType, res.BindingList[2].Binding.Type())
824847
}
848+
849+
func TestWorkers_UpdateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties(t *testing.T) {
850+
setup(UsingAccount("foo"))
851+
defer teardown()
852+
853+
route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script", Enabled: true}
854+
_, err := client.UpdateWorkerRoute("foo", "e7a57d8746e74ae49c25994dadb421b1", route)
855+
assert.EqualError(t, err, "Only `Script` or `Enabled` may be specified for a WorkerRoute, not both")
856+
}
857+
858+
func TestWorkers_UpdateWorkerRouteWithNoScript(t *testing.T) {
859+
setup(UsingAccount("foo"))
860+
861+
mux.HandleFunc("/zones/foo/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) {
862+
assert.Equal(t, "PUT", r.Method, "Expected method 'PUT', got %s", r.Method)
863+
w.Header().Set("content-type", "application-json")
864+
fmt.Fprintf(w, updateWorkerRouteEntResponse)
865+
})
866+
867+
route := WorkerRoute{Pattern: "app1.example.com/*"}
868+
_, err := client.UpdateWorkerRoute("foo", "e7a57d8746e74ae49c25994dadb421b1", route)
869+
assert.NoError(t, err)
870+
}

0 commit comments

Comments
 (0)