Skip to content

Commit

Permalink
Add set cache settings action support for rulesets
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis Davydov committed Jun 10, 2022
1 parent 270cf73 commit edbcd70
Show file tree
Hide file tree
Showing 2 changed files with 278 additions and 18 deletions.
141 changes: 123 additions & 18 deletions rulesets.go
Expand Up @@ -20,6 +20,7 @@ const (
RulesetPhaseDDoSL4 RulesetPhase = "ddos_l4"
RulesetPhaseDDoSL7 RulesetPhase = "ddos_l7"
RulesetPhaseHTTPLogCustomFields RulesetPhase = "http_log_custom_fields"
RulesetPhaseHTTPRequestCacheSettings RulesetPhase = "http_request_cache_settings"
RulesetPhaseHTTPRequestFirewallCustom RulesetPhase = "http_request_firewall_custom"
RulesetPhaseHTTPRequestFirewallManaged RulesetPhase = "http_request_firewall_managed"
RulesetPhaseHTTPRequestLateTransform RulesetPhase = "http_request_late_transform"
Expand Down Expand Up @@ -47,6 +48,7 @@ const (
RulesetRuleActionScore RulesetRuleAction = "score"
RulesetRuleActionSkip RulesetRuleAction = "skip"
RulesetRuleActionRoute RulesetRuleAction = "route"
RulesetRuleActionSetCacheSettings RulesetRuleAction = "set_cache_settings"

RulesetActionParameterProductBIC RulesetActionParameterProduct = "bic"
RulesetActionParameterProductHOT RulesetActionParameterProduct = "hot"
Expand Down Expand Up @@ -79,6 +81,7 @@ func RulesetPhaseValues() []string {
string(RulesetPhaseDDoSL4),
string(RulesetPhaseDDoSL7),
string(RulesetPhaseHTTPLogCustomFields),
string(RulesetPhaseHTTPRequestCacheSettings),
string(RulesetPhaseHTTPRequestFirewallCustom),
string(RulesetPhaseHTTPRequestFirewallManaged),
string(RulesetPhaseHTTPRequestLateTransform),
Expand Down Expand Up @@ -112,6 +115,7 @@ func RulesetRuleActionValues() []string {
string(RulesetRuleActionScore),
string(RulesetRuleActionSkip),
string(RulesetRuleActionRoute),
string(RulesetRuleActionSetCacheSettings),
}
}

Expand Down Expand Up @@ -181,24 +185,125 @@ type RulesetActionParametersLogCustomField struct {
// RulesetRuleActionParameters specifies the action parameters for a Ruleset
// rule.
type RulesetRuleActionParameters struct {
ID string `json:"id,omitempty"`
Ruleset string `json:"ruleset,omitempty"`
Rulesets []string `json:"rulesets,omitempty"`
Rules map[string][]string `json:"rules,omitempty"`
Increment int `json:"increment,omitempty"`
URI *RulesetRuleActionParametersURI `json:"uri,omitempty"`
Headers map[string]RulesetRuleActionParametersHTTPHeader `json:"headers,omitempty"`
Products []string `json:"products,omitempty"`
Phases []string `json:"phases,omitempty"`
Overrides *RulesetRuleActionParametersOverrides `json:"overrides,omitempty"`
MatchedData *RulesetRuleActionParametersMatchedData `json:"matched_data,omitempty"`
Version string `json:"version,omitempty"`
Response *RulesetRuleActionParametersBlockResponse `json:"response,omitempty"`
HostHeader string `json:"host_header,omitempty"`
Origin *RulesetRuleActionParametersOrigin `json:"origin,omitempty"`
RequestFields []RulesetActionParametersLogCustomField `json:"request_fields,omitempty"`
ResponseFields []RulesetActionParametersLogCustomField `json:"response_fields,omitempty"`
CookieFields []RulesetActionParametersLogCustomField `json:"cookie_fields,omitempty"`
ID string `json:"id,omitempty"`
Ruleset string `json:"ruleset,omitempty"`
Rulesets []string `json:"rulesets,omitempty"`
Rules map[string][]string `json:"rules,omitempty"`
Increment int `json:"increment,omitempty"`
URI *RulesetRuleActionParametersURI `json:"uri,omitempty"`
Headers map[string]RulesetRuleActionParametersHTTPHeader `json:"headers,omitempty"`
Products []string `json:"products,omitempty"`
Phases []string `json:"phases,omitempty"`
Overrides *RulesetRuleActionParametersOverrides `json:"overrides,omitempty"`
MatchedData *RulesetRuleActionParametersMatchedData `json:"matched_data,omitempty"`
Version string `json:"version,omitempty"`
Response *RulesetRuleActionParametersBlockResponse `json:"response,omitempty"`
HostHeader string `json:"host_header,omitempty"`
Origin *RulesetRuleActionParametersOrigin `json:"origin,omitempty"`
RequestFields []RulesetActionParametersLogCustomField `json:"request_fields,omitempty"`
ResponseFields []RulesetActionParametersLogCustomField `json:"response_fields,omitempty"`
CookieFields []RulesetActionParametersLogCustomField `json:"cookie_fields,omitempty"`
ByPassCache *bool `json:"bypass_cache,omitempty"`
EdgeTTL *RulesetRuleActionParametersEdgeTTL `json:"edge_ttl,omitempty"`
BrowserTTL *RulesetRuleActionParametersBrowserTTL `json:"browser_ttl,omitempty"`
ServeStale *RulesetRuleActionParametersServeStale `json:"serve_stale,omitempty"`
RespectStrongETags *bool `json:"respect_strong_etags,omitempty"`
CacheKey *RulesetRuleActionParametersCacheKey `json:"cache_key,omitempty"`
OriginErrorPagePassthru *bool `json:"origin_error_page_passthru,omitempty"`
}

type RulesetRuleActionParametersEdgeTTL struct {
Mode string `json:"mode,omitempty"`
Default *uint `json:"default,omitempty"`
StatusCodeTTL []RulesetRuleActionParametersStatusCodeTTL `json:"status_code_ttl,omitempty"`
}

type RulesetRuleActionParametersStatusCodeTTL struct {
StatusCodeRange *RulesetRuleActionParametersStatusCodeRange `json:"status_code_range,omitempty"`
StatusCodeValue *uint `json:"status_code,omitempty"`
Value *int `json:"value,omitempty"`
}

type RulesetRuleActionParametersStatusCodeRange struct {
From *uint `json:"from,omitempty"`
To *uint `json:"to,omitempty"`
}

type RulesetRuleActionParametersBrowserTTL struct {
Mode string `json:"mode"`
Default *uint `json:"default,omitempty"`
}

type RulesetRuleActionParametersServeStale struct {
DisableStaleWhileUpdating *bool `json:"disable_stale_while_updating,omitempty"`
}

type RulesetRuleActionParametersCacheKey struct {
CacheByDeviceType *bool `json:"cache_by_device_type,omitempty"`
IgnoreQueryStringsOrder *bool `json:"ignore_query_strings_order,omitempty"`
CacheDeceptionArmor *bool `json:"cache_deception_armor,omitempty"`
CustomKey *RulesetRuleActionParametersCustomKey `json:"custom_key,omitempty"`
}

type RulesetRuleActionParametersCustomKey struct {
Query *RulesetRuleActionParametersCustomKeyQuery `json:"query_string,omitempty"`
Header *RulesetRuleActionParametersCustomKeyHeader `json:"header,omitempty"`
Cookie *RulesetRuleActionParametersCustomKeyCookie `json:"cookie,omitempty"`
User *RulesetRuleActionParametersCustomKeyUser `json:"user,omitempty"`
Host *RulesetRuleActionParametersCustomKeyHost `json:"host,omitempty"`
}

type RulesetRuleActionParametersCustomKeyHeader struct {
RulesetRuleActionParametersCustomKeyFields
ExcludeOrigin *bool `json:"exclude_origin,omitempty"`
}

type RulesetRuleActionParametersCustomKeyCookie RulesetRuleActionParametersCustomKeyFields

type RulesetRuleActionParametersCustomKeyFields struct {
Include []string `json:"include,omitempty"`
CheckPresence []string `json:"check_presence,omitempty"`
}

type RulesetRuleActionParametersCustomKeyQuery struct {
Include *RulesetRuleActionParametersCustomKeyList `json:"include,omitempty"`
Exclude *RulesetRuleActionParametersCustomKeyList `json:"exclude,omitempty"`
}

type RulesetRuleActionParametersCustomKeyList struct {
List []string
All bool
}

func (s *RulesetRuleActionParametersCustomKeyList) UnmarshalJSON(data []byte) error {
var all string
if err := json.Unmarshal(data, &all); err == nil {
s.All = all == "*"
return nil
}
var list []string
if err := json.Unmarshal(data, &list); err == nil {
s.List = list
}

return nil
}

func (s RulesetRuleActionParametersCustomKeyList) MarshalJSON() ([]byte, error) {
if s.All {
return json.Marshal("*")
}
return json.Marshal(s.List)
}

type RulesetRuleActionParametersCustomKeyUser struct {
DeviceType *bool `json:"device_type,omitempty"`
Geo *bool `json:"geo,omitempty"`
Lang *bool `json:"lang,omitempty"`
}

type RulesetRuleActionParametersCustomKeyHost struct {
Resolved *bool `json:"resolved,omitempty"`
}

// RulesetRuleActionParametersBlockResponse holds the BlockResponse struct
Expand Down
155 changes: 155 additions & 0 deletions rulesets_test.go
Expand Up @@ -199,6 +199,161 @@ func TestGetRuleset_WAF(t *testing.T) {
}
}

func TestGetRuleset_SetCacheSettings(t *testing.T) {
setup()
defer teardown()

handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
fmt.Fprint(w, `{
"result": {
"id": "70339d97bdb34195bbf054b1ebe81f76",
"name": "Cloudflare Cache Rules Ruleset",
"description": "This ruleset provides cache settings modifications",
"kind": "zone",
"version": "1",
"rules": [
{
"id": "78723a9e0c7c4c6dbec5684cb766231d",
"version": "1",
"action": "set_cache_settings",
"action_parameters": {
"bypass_cache": false,
"edge_ttl":{"mode":"respect_origin","default":60,"status_code_ttl":[{"status_code":200,"value":30},{"status_code_range":{"from":201,"to":300},"value":20}]},
"browser_ttl":{"mode":"override_origin","default":10},
"serve_stale":{"disable_stale_while_updating":true},
"respect_strong_etags":true,
"cache_key":{
"cache_deception_armor":true,
"ignore_query_strings_order":true,
"custom_key": {
"query_string":{"include":"*"},
"header":{"include":["habc","hdef"],"check_presence":["hfizz","hbuzz"],"exclude_origin":true},
"cookie":{"include":["cabc","cdef"],"check_presence":["cfizz","cbuzz"]},
"user":{
"device_type":true,
"geo":true,
"lang":true
},
"host":{
"resolved":true
}
}
},
"origin_error_page_passthru":true
},
"description": "Set all available cache settings in one rule",
"last_updated": "2020-12-18T09:28:09.655749Z",
"ref": "272936dc447b41fe976255ff6b768ec0",
"enabled": true
}
],
"last_updated": "2020-12-18T09:28:09.655749Z",
"phase": "http_request_cache_settings"
},
"success": true,
"errors": [],
"messages": []
}`)
}

mux.HandleFunc("/accounts/"+testAccountID+"/rulesets/b232b534beea4e00a21dcbb7a8a545e9", handler)
mux.HandleFunc("/zones/"+testZoneID+"/rulesets/b232b534beea4e00a21dcbb7a8a545e9", handler)

lastUpdated, _ := time.Parse(time.RFC3339, "2020-12-18T09:28:09.655749Z")

rules := []RulesetRule{{
ID: "78723a9e0c7c4c6dbec5684cb766231d",
Version: "1",
Action: string(RulesetRuleActionSetCacheSettings),
ActionParameters: &RulesetRuleActionParameters{
ByPassCache: BoolPtr(false),
EdgeTTL: &RulesetRuleActionParametersEdgeTTL{
Mode: "respect_origin",
Default: UintPtr(60),
StatusCodeTTL: []RulesetRuleActionParametersStatusCodeTTL{
{
StatusCodeValue: UintPtr(200),
Value: IntPtr(30),
},
{
StatusCodeRange: &RulesetRuleActionParametersStatusCodeRange{
From: UintPtr(201),
To: UintPtr(300),
},
Value: IntPtr(20),
},
},
},
BrowserTTL: &RulesetRuleActionParametersBrowserTTL{
Mode: "override_origin",
Default: UintPtr(10),
},
ServeStale: &RulesetRuleActionParametersServeStale{
DisableStaleWhileUpdating: BoolPtr(true),
},
RespectStrongETags: BoolPtr(true),
CacheKey: &RulesetRuleActionParametersCacheKey{
IgnoreQueryStringsOrder: BoolPtr(true),
CacheDeceptionArmor: BoolPtr(true),
CustomKey: &RulesetRuleActionParametersCustomKey{
Query: &RulesetRuleActionParametersCustomKeyQuery{
Include: &RulesetRuleActionParametersCustomKeyList{
All: true,
},
},
Header: &RulesetRuleActionParametersCustomKeyHeader{
RulesetRuleActionParametersCustomKeyFields: RulesetRuleActionParametersCustomKeyFields{
Include: []string{"habc", "hdef"},
CheckPresence: []string{"hfizz", "hbuzz"},
},
ExcludeOrigin: BoolPtr(true),
},
Cookie: &RulesetRuleActionParametersCustomKeyCookie{
Include: []string{"cabc", "cdef"},
CheckPresence: []string{"cfizz", "cbuzz"},
},
User: &RulesetRuleActionParametersCustomKeyUser{
DeviceType: BoolPtr(true),
Geo: BoolPtr(true),
Lang: BoolPtr(true),
},
Host: &RulesetRuleActionParametersCustomKeyHost{
Resolved: BoolPtr(true),
},
},
},
OriginErrorPagePassthru: BoolPtr(true),
},
Description: "Set all available cache settings in one rule",
LastUpdated: &lastUpdated,
Ref: "272936dc447b41fe976255ff6b768ec0",
Enabled: true,
}}

want := Ruleset{
ID: "70339d97bdb34195bbf054b1ebe81f76",
Name: "Cloudflare Cache Rules Ruleset",
Description: "This ruleset provides cache settings modifications",
Kind: string(RulesetKindZone),
Version: "1",
LastUpdated: &lastUpdated,
Phase: string(RulesetPhaseHTTPRequestCacheSettings),
Rules: rules,
}

zoneActual, err := client.GetZoneRuleset(context.Background(), testZoneID, "b232b534beea4e00a21dcbb7a8a545e9")
if assert.NoError(t, err) {
assert.Equal(t, want, zoneActual)
}

accountActual, err := client.GetAccountRuleset(context.Background(), testAccountID, "b232b534beea4e00a21dcbb7a8a545e9")
if assert.NoError(t, err) {
assert.Equal(t, want, accountActual)
}
}

func TestCreateRuleset(t *testing.T) {
setup()
defer teardown()
Expand Down

0 comments on commit edbcd70

Please sign in to comment.