Skip to content

Commit

Permalink
Fixing URL encoding when params in path already
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich Abdill authored and sethvargo committed Dec 22, 2017
1 parent ac049eb commit 629aea3
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 33 deletions.
33 changes: 32 additions & 1 deletion fastly/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ func (c *Client) RawRequest(verb, p string, ro *RequestOptions) (*http.Request,
params.Add(k, v)
}
u.RawQuery = params.Encode()

// Create the request object.
request, err := http.NewRequest(verb, u.String(), ro.Body)
if err != nil {
Expand All @@ -66,3 +65,35 @@ func (c *Client) RawRequest(verb, p string, ro *RequestOptions) (*http.Request,

return request, nil
}

// StraightGet combines the RawRequest and Request methods,
// but doesn't add any parameters or change any encoding in the URL
// passed to it. It's mostly for calling the URLs given to us
// directly from Fastly without mangling them.
func (c *Client) StraightGet(target string) (*http.Response, error) {
// We parse the URL and then convert it right back to a string
// later; this just acts as a check that Fastly isn't sending
// us nonsense.
url, err := url.Parse(target)
if err != nil {
return nil, err
}

// Create the request object.
request, err := http.NewRequest("GET", url.String(), nil)
if err != nil {
return nil, err
}

// Set the API key.
if len(c.apiKey) > 0 {
request.Header.Set(APIKeyHeader, c.apiKey)
}
request.Header.Set("User-Agent", UserAgent)

resp, err := checkResp(c.HTTPClient.Do(request))
if err != nil {
return resp, err
}
return resp, nil
}
76 changes: 44 additions & 32 deletions fastly/waf.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"io/ioutil"
"net/http"
"reflect"
"strconv"
"strings"
Expand All @@ -29,6 +30,10 @@ type WAF struct {
ConfigurationSet *WAFConfigurationSet `jsonapi:"relation,configuration_set"`
}

func (waf *WAF) String() string {
return fmt.Sprintf("<ID: |%v|, Version: |%v|>", waf.ID, waf.Version)
}

// wafType is used for reflection because JSONAPI wants to know what it's
// decoding into.
var wafType = reflect.TypeOf(new(WAF))
Expand Down Expand Up @@ -576,41 +581,43 @@ type GetWAFRuleStatusesInput struct {

// receivedWAFRuleStatus stores the information about a rule received from Fastly
type receivedWAFRuleStatus struct {
id string `jsonapi:"primary,rule_status"`
rule *ruleStatusRuleRelation `jsonapi:"relation,rule"`
waf *ruleStatusWAFRelation `jsonapi:"relation,waf"`
status string `jsonapi:"attr,status"`
}
ID string `jsonapi:"primary,rule_status"`
Status string `jsonapi:"attr,status"`

// ruleStatusRuleRelation is the information about a rule stored inside of
// its status, as sent by Fastly
type ruleStatusRuleRelation struct {
id int `jsonapi:"primary,rule"` // NOTE: Rule ID is int, all others are strings
}

// ruleStatusWAFRelation is the information received within a rule status
// about the WAF in which the rule exists
type ruleStatusWAFRelation struct {
id string `jsonapi:"primary,waf"`
// HACK: These two fields are supposed to be sent in response
// to requests for rule status data, but the entire "Relationships"
// field is currently missing from Fastly responses, so they are
// instead inferred from the status ID (see inferIDs method).
// waf newTypeThatDoesntExistNow `jsonapi:"relation,waf"`
// rule newTypeThatDoesntExistNow `jsonapi:"relation,rule"`
}

// WAFRuleStatus is the convenience type provided to gofastly users that
// flattens the structure of a rule status received from the Fastly API
type WAFRuleStatus struct {
RuleID int
RuleID string
WAFID string
StatusID string
Status string
}

func (r *WAFRuleStatus) String() string {
return fmt.Sprintf("<RuleID: %v, Status: %v>", r.RuleID, r.Status)
}

// simplify converts a rule status object from fastly into a more logical
// structure for use elsewhere
func (received receivedWAFRuleStatus) simplify() WAFRuleStatus {
func (r receivedWAFRuleStatus) simplify() WAFRuleStatus {
splitIt := strings.Split(r.ID, "-")
if len(splitIt) < 2 {
splitIt = []string{"", ""}
}

return WAFRuleStatus{
RuleID: received.rule.id,
WAFID: received.waf.id,
StatusID: received.id,
Status: received.status,
WAFID: splitIt[0],
RuleID: splitIt[1],
StatusID: r.ID,
Status: r.Status,
}
}

Expand Down Expand Up @@ -689,10 +696,17 @@ func (c *Client) GetWAFRuleStatuses(i *GetWAFRuleStatusesInput) (GetWAFRuleStatu
if i.WAF == "" {
return statusResponse, ErrMissingWAFID
}

path := fmt.Sprintf("/service/%s/wafs/%s/rule_statuses", i.Service, i.WAF)
filters := &RequestOptions{
Params: i.formatFilters(),
}
err := c.fetchWAFRuleStatusesPage(&statusResponse, fmt.Sprintf("/service/%s/wafs/%s/rule_statuses", i.Service, i.WAF), filters)

resp, err := c.Get(path, filters)
if err != nil {
return GetWAFRuleStatusesResponse{}, err
}
err = c.interpretWAFRuleStatusesPage(&statusResponse, resp)
// NOTE: It's possible for statusResponse to be partially completed before an error
// was encountered, so the presence of a statusResponse doesn't preclude the presence of
// an error.
Expand All @@ -701,20 +715,13 @@ func (c *Client) GetWAFRuleStatuses(i *GetWAFRuleStatusesInput) (GetWAFRuleStatu

// fetchWAFRuleStatusesPage recursively calls the fastly rules status endpoint until there
// are no more results to request.
func (c *Client) fetchWAFRuleStatusesPage(answer *GetWAFRuleStatusesResponse, path string, filters *RequestOptions) error {
resp, err := c.Get(path, filters)
if err != nil {
return err
}

func (c *Client) interpretWAFRuleStatusesPage(answer *GetWAFRuleStatusesResponse, received *http.Response) error {
// before we pull the status info out of the response body, fetch
// pagination info from it:
pages, body, err := getPages(resp.Body)
pages, body, err := getPages(received.Body)
if err != nil {
return err
}

// then grab all the rule status objects out of the response:
var statusType = reflect.TypeOf(new(receivedWAFRuleStatus))
data, err := jsonapi.UnmarshalManyPayload(body, statusType)
if err != nil {
Expand All @@ -729,7 +736,12 @@ func (c *Client) fetchWAFRuleStatusesPage(answer *GetWAFRuleStatusesResponse, pa
answer.Rules = append(answer.Rules, typed.simplify())
}
if pages.Next != "" {
c.fetchWAFRuleStatusesPage(answer, pages.Next, filters) // TODO: Does the "next" link include the filters already?
// NOTE: pages.Next URL includes filters already
resp, err := c.StraightGet(pages.Next)
if err != nil {
return err
}
c.interpretWAFRuleStatusesPage(answer, resp)
}
return nil
}
Expand Down

0 comments on commit 629aea3

Please sign in to comment.