func (r *Route53) query(method, path string, req, resp interface{}) error { params := make(map[string]string) endpoint, err := url.Parse(r.Region.Route53Endpoint) if err != nil { return err } endpoint.Path = path sign(r.Auth, endpoint.Path, params) // If they look like url.Values, just encode... if queryArgs, ok := req.(url.Values); ok { endpoint.RawQuery = queryArgs.Encode() req = nil } // Encode the body var body io.ReadWriter if req != nil { bodyBuf := bytes.NewBuffer(nil) enc := xml.NewEncoder(bodyBuf) start := xml.StartElement{ Name: xml.Name{ Space: "", Local: reflect.Indirect(reflect.ValueOf(req)).Type().Name(), }, Attr: []xml.Attr{{xml.Name{"", "xmlns"}, "https://route53.amazonaws.com/doc/2013-04-01/"}}, } if err := enc.EncodeElement(req, start); err != nil { return err } // This is really a sadness, but can't think of a better way to // do this for now in Go's constructs. replace := "<ResourceRecords><ResourceRecord></ResourceRecord></ResourceRecords>" if strings.Contains(bodyBuf.String(), replace) { var newBuf bytes.Buffer newBuf.WriteString(strings.Replace(bodyBuf.String(), replace, "", -1)) bodyBuf = &newBuf } // http://docs.aws.amazon.com/Route53/latest/APIReference/CreateAliasRRSAPI.html if reflect.Indirect(reflect.ValueOf(req)).Type().Name() == "ChangeResourceRecordSetsRequest" { for _, change := range req.(ChangeResourceRecordSetsRequest).Changes { if change.Record.AliasTarget != nil { replace := change.Record.Type + "</Type><TTL>0</TTL>" var newBuf bytes.Buffer newBuf.WriteString(strings.Replace(bodyBuf.String(), replace, change.Record.Type+"</Type>", -1)) bodyBuf = &newBuf } } } body = bodyBuf } // Make the http request hReq, err := http.NewRequest(method, endpoint.String(), body) if err != nil { return err } for k, v := range params { hReq.Header.Set(k, v) } re, err := r.httpClient.Do(hReq) if err != nil { return err } defer re.Body.Close() // Check the status code switch re.StatusCode { case 200: case 201: default: var body bytes.Buffer io.Copy(&body, re.Body) return fmt.Errorf("Request failed, got status code: %d. Response: %s", re.StatusCode, body.Bytes()) } // Decode the response decoder := xml.NewDecoder(re.Body) return decoder.Decode(resp) }