2
// goamz - Go packages to interact with the Amazon Web Services.
4
// https://wiki.ubuntu.com/goamz
6
// Copyright (c) 2011-2015 Canonical Ltd.
8
// This file contains shared helpers and related code used internally.
27
const defaultXMLName = "http://ec2.amazonaws.com/doc/2014-10-01/"
29
var b64 = base64.StdEncoding
31
// writeError writes an appropriate error response.
32
// TODO how should we deal with errors when the
33
// error itself is potentially generated by backend-agnostic
35
func writeError(w http.ResponseWriter, err *ec2.Error) {
36
// Error encapsulates an error returned by EC2.
37
// TODO merge with ec2.Error when xml supports ignoring a field.
38
type ec2error struct {
39
Code string // EC2 error code ("UnsupportedOperation", ...)
40
Message string // The human-oriented error message
44
type Response struct {
46
Errors []ec2error `xml:"Errors>Error"`
49
w.Header().Set("Content-Type", `xml version="1.0" encoding="UTF-8"`)
50
w.WriteHeader(err.StatusCode)
51
xmlMarshal(w, Response{
52
RequestId: err.RequestId,
60
// xmlMarshal is the same as xml.Marshal except that
61
// it panics on error. The marshalling should not fail,
62
// but we want to know if it does.
63
func xmlMarshal(w io.Writer, x interface{}) {
64
encoder := xml.NewEncoder(w)
65
encoder.Indent("", " ")
66
if err := encoder.Encode(x); err != nil {
67
panic(fmt.Errorf("error marshalling %#v: %v", x, err))
71
func parseCidr(val string) string {
73
fatalf(400, "MissingParameter", "missing cidrBlock")
75
if _, _, err := net.ParseCIDR(val); err != nil {
76
fatalf(400, "InvalidParameterValue", "bad CIDR %q: %v", val, err)
81
// parseIDs takes all form fields with the given prefix and returns a
82
// map with their values as keys.
83
func parseIDs(form url.Values, prefix string) map[string]bool {
84
idMap := make(map[string]bool)
85
for field, allValues := range form {
87
if strings.HasPrefix(field, prefix) && !idMap[value] {
94
// parseInOrder takes all form fields with the given prefix and
95
// returns their values in request order. Suitable for AWS API
96
// parameters defining lists, e.g. with fields like
97
// "PrivateIpAddress.0": v1, "PrivateIpAddress.1" v2, it returns
99
func parseInOrder(form url.Values, prefix string) []string {
100
idMap := parseIDs(form, prefix)
101
results := make([]string, len(idMap))
102
for field, allValues := range form {
103
if !strings.HasPrefix(field, prefix) {
106
value := allValues[0]
107
parts := strings.Split(field, ".")
109
panic(fmt.Sprintf("expected indexed key %q", field))
111
index := atoi(parts[1])
113
results[index] = value
119
type counter struct {
123
func (c *counter) next() int {
124
i := atomic.AddInt32(&c.value, 1)
128
func (c *counter) get() (i int) {
129
return int(atomic.LoadInt32(&c.value))
132
func (c *counter) reset() {
133
atomic.StoreInt32(&c.value, 0)
136
// atoi is like strconv.Atoi but is fatal if the
137
// string is not well formed.
138
func atoi(s string) int {
139
i, err := strconv.Atoi(s)
141
fatalf(400, "InvalidParameterValue", "bad number: %v", err)
146
func fatalf(statusCode int, code string, f string, a ...interface{}) {
148
StatusCode: statusCode,
150
Message: fmt.Sprintf(f, a...),