~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/google.golang.org/api/googleapi/googleapi.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2011 Google Inc. All rights reserved.
 
2
// Use of this source code is governed by a BSD-style
 
3
// license that can be found in the LICENSE file.
 
4
 
 
5
// Package googleapi contains the common code shared by all Google API
 
6
// libraries.
 
7
package googleapi
 
8
 
 
9
import (
 
10
        "bytes"
 
11
        "encoding/json"
 
12
        "fmt"
 
13
        "io"
 
14
        "io/ioutil"
 
15
        "mime/multipart"
 
16
        "net/http"
 
17
        "net/textproto"
 
18
        "net/url"
 
19
        "os"
 
20
        "strings"
 
21
 
 
22
        "google.golang.org/api/googleapi/internal/uritemplates"
 
23
)
 
24
 
 
25
// ContentTyper is an interface for Readers which know (or would like
 
26
// to override) their Content-Type. If a media body doesn't implement
 
27
// ContentTyper, the type is sniffed from the content using
 
28
// http.DetectContentType.
 
29
type ContentTyper interface {
 
30
        ContentType() string
 
31
}
 
32
 
 
33
const Version = "0.5"
 
34
 
 
35
// Error contains an error response from the server.
 
36
type Error struct {
 
37
        // Code is the HTTP response status code and will always be populated.
 
38
        Code int `json:"code"`
 
39
        // Message is the server response message and is only populated when
 
40
        // explicitly referenced by the JSON server response.
 
41
        Message string `json:"message"`
 
42
        // Body is the raw response returned by the server.
 
43
        // It is often but not always JSON, depending on how the request fails.
 
44
        Body string
 
45
 
 
46
        Errors []ErrorItem
 
47
}
 
48
 
 
49
// ErrorItem is a detailed error code & message from the Google API frontend.
 
50
type ErrorItem struct {
 
51
        // Reason is the typed error code. For example: "some_example".
 
52
        Reason string `json:"reason"`
 
53
        // Message is the human-readable description of the error.
 
54
        Message string `json:"message"`
 
55
}
 
56
 
 
57
func (e *Error) Error() string {
 
58
        if len(e.Errors) == 0 && e.Message == "" {
 
59
                return fmt.Sprintf("googleapi: got HTTP response code %d with body: %v", e.Code, e.Body)
 
60
        }
 
61
        var buf bytes.Buffer
 
62
        fmt.Fprintf(&buf, "googleapi: Error %d: ", e.Code)
 
63
        if e.Message != "" {
 
64
                fmt.Fprintf(&buf, "%s", e.Message)
 
65
        }
 
66
        if len(e.Errors) == 0 {
 
67
                return strings.TrimSpace(buf.String())
 
68
        }
 
69
        if len(e.Errors) == 1 && e.Errors[0].Message == e.Message {
 
70
                fmt.Fprintf(&buf, ", %s", e.Errors[0].Reason)
 
71
                return buf.String()
 
72
        }
 
73
        fmt.Fprintln(&buf, "\nMore details:")
 
74
        for _, v := range e.Errors {
 
75
                fmt.Fprintf(&buf, "Reason: %s, Message: %s\n", v.Reason, v.Message)
 
76
        }
 
77
        return buf.String()
 
78
}
 
79
 
 
80
type errorReply struct {
 
81
        Error *Error `json:"error"`
 
82
}
 
83
 
 
84
// CheckResponse returns an error (of type *Error) if the response
 
85
// status code is not 2xx.
 
86
func CheckResponse(res *http.Response) error {
 
87
        if res.StatusCode >= 200 && res.StatusCode <= 299 {
 
88
                return nil
 
89
        }
 
90
        slurp, err := ioutil.ReadAll(res.Body)
 
91
        if err == nil {
 
92
                jerr := new(errorReply)
 
93
                err = json.Unmarshal(slurp, jerr)
 
94
                if err == nil && jerr.Error != nil {
 
95
                        if jerr.Error.Code == 0 {
 
96
                                jerr.Error.Code = res.StatusCode
 
97
                        }
 
98
                        jerr.Error.Body = string(slurp)
 
99
                        return jerr.Error
 
100
                }
 
101
        }
 
102
        return &Error{
 
103
                Code: res.StatusCode,
 
104
                Body: string(slurp),
 
105
        }
 
106
}
 
107
 
 
108
type MarshalStyle bool
 
109
 
 
110
var WithDataWrapper = MarshalStyle(true)
 
111
var WithoutDataWrapper = MarshalStyle(false)
 
112
 
 
113
func (wrap MarshalStyle) JSONReader(v interface{}) (io.Reader, error) {
 
114
        buf := new(bytes.Buffer)
 
115
        if wrap {
 
116
                buf.Write([]byte(`{"data": `))
 
117
        }
 
118
        err := json.NewEncoder(buf).Encode(v)
 
119
        if err != nil {
 
120
                return nil, err
 
121
        }
 
122
        if wrap {
 
123
                buf.Write([]byte(`}`))
 
124
        }
 
125
        return buf, nil
 
126
}
 
127
 
 
128
func getMediaType(media io.Reader) (io.Reader, string) {
 
129
        if typer, ok := media.(ContentTyper); ok {
 
130
                return media, typer.ContentType()
 
131
        }
 
132
 
 
133
        typ := "application/octet-stream"
 
134
        buf := make([]byte, 1024)
 
135
        n, err := media.Read(buf)
 
136
        buf = buf[:n]
 
137
        if err == nil {
 
138
                typ = http.DetectContentType(buf)
 
139
        }
 
140
        return io.MultiReader(bytes.NewBuffer(buf), media), typ
 
141
}
 
142
 
 
143
type Lengther interface {
 
144
        Len() int
 
145
}
 
146
 
 
147
// endingWithErrorReader from r until it returns an error.  If the
 
148
// final error from r is os.EOF and e is non-nil, e is used instead.
 
149
type endingWithErrorReader struct {
 
150
        r io.Reader
 
151
        e error
 
152
}
 
153
 
 
154
func (er endingWithErrorReader) Read(p []byte) (n int, err error) {
 
155
        n, err = er.r.Read(p)
 
156
        if err == io.EOF && er.e != nil {
 
157
                err = er.e
 
158
        }
 
159
        return
 
160
}
 
161
 
 
162
func getReaderSize(r io.Reader) (io.Reader, int64) {
 
163
        // Ideal case, the reader knows its own size.
 
164
        if lr, ok := r.(Lengther); ok {
 
165
                return r, int64(lr.Len())
 
166
        }
 
167
 
 
168
        // But maybe it's a seeker and we can seek to the end to find its size.
 
169
        if s, ok := r.(io.Seeker); ok {
 
170
                pos0, err := s.Seek(0, os.SEEK_CUR)
 
171
                if err == nil {
 
172
                        posend, err := s.Seek(0, os.SEEK_END)
 
173
                        if err == nil {
 
174
                                _, err = s.Seek(pos0, os.SEEK_SET)
 
175
                                if err == nil {
 
176
                                        return r, posend - pos0
 
177
                                } else {
 
178
                                        // We moved it forward but can't restore it.
 
179
                                        // Seems unlikely, but can't really restore now.
 
180
                                        return endingWithErrorReader{strings.NewReader(""), err}, posend - pos0
 
181
                                }
 
182
                        }
 
183
                }
 
184
        }
 
185
 
 
186
        // Otherwise we have to make a copy to calculate how big the reader is.
 
187
        buf := new(bytes.Buffer)
 
188
        // TODO(bradfitz): put a cap on this copy? spill to disk after
 
189
        // a certain point?
 
190
        _, err := io.Copy(buf, r)
 
191
        return endingWithErrorReader{buf, err}, int64(buf.Len())
 
192
}
 
193
 
 
194
func typeHeader(contentType string) textproto.MIMEHeader {
 
195
        h := make(textproto.MIMEHeader)
 
196
        h.Set("Content-Type", contentType)
 
197
        return h
 
198
}
 
199
 
 
200
// countingWriter counts the number of bytes it receives to write, but
 
201
// discards them.
 
202
type countingWriter struct {
 
203
        n *int64
 
204
}
 
205
 
 
206
func (w countingWriter) Write(p []byte) (int, error) {
 
207
        *w.n += int64(len(p))
 
208
        return len(p), nil
 
209
}
 
210
 
 
211
// ConditionallyIncludeMedia does nothing if media is nil.
 
212
//
 
213
// bodyp is an in/out parameter.  It should initially point to the
 
214
// reader of the application/json (or whatever) payload to send in the
 
215
// API request.  It's updated to point to the multipart body reader.
 
216
//
 
217
// ctypep is an in/out parameter.  It should initially point to the
 
218
// content type of the bodyp, usually "application/json".  It's updated
 
219
// to the "multipart/related" content type, with random boundary.
 
220
//
 
221
// The return value is the content-length of the entire multpart body.
 
222
func ConditionallyIncludeMedia(media io.Reader, bodyp *io.Reader, ctypep *string) (totalContentLength int64, ok bool) {
 
223
        if media == nil {
 
224
                return
 
225
        }
 
226
        // Get the media type and size. The type check might return a
 
227
        // different reader instance, so do the size check first,
 
228
        // which looks at the specific type of the io.Reader.
 
229
        var mediaType string
 
230
        if typer, ok := media.(ContentTyper); ok {
 
231
                mediaType = typer.ContentType()
 
232
        }
 
233
        media, mediaSize := getReaderSize(media)
 
234
        if mediaType == "" {
 
235
                media, mediaType = getMediaType(media)
 
236
        }
 
237
        body, bodyType := *bodyp, *ctypep
 
238
        body, bodySize := getReaderSize(body)
 
239
 
 
240
        // Calculate how big the the multipart will be.
 
241
        {
 
242
                totalContentLength = bodySize + mediaSize
 
243
                mpw := multipart.NewWriter(countingWriter{&totalContentLength})
 
244
                mpw.CreatePart(typeHeader(bodyType))
 
245
                mpw.CreatePart(typeHeader(mediaType))
 
246
                mpw.Close()
 
247
        }
 
248
 
 
249
        pr, pw := io.Pipe()
 
250
        mpw := multipart.NewWriter(pw)
 
251
        *bodyp = pr
 
252
        *ctypep = "multipart/related; boundary=" + mpw.Boundary()
 
253
        go func() {
 
254
                defer pw.Close()
 
255
                defer mpw.Close()
 
256
 
 
257
                w, err := mpw.CreatePart(typeHeader(bodyType))
 
258
                if err != nil {
 
259
                        return
 
260
                }
 
261
                _, err = io.Copy(w, body)
 
262
                if err != nil {
 
263
                        return
 
264
                }
 
265
 
 
266
                w, err = mpw.CreatePart(typeHeader(mediaType))
 
267
                if err != nil {
 
268
                        return
 
269
                }
 
270
                _, err = io.Copy(w, media)
 
271
                if err != nil {
 
272
                        return
 
273
                }
 
274
        }()
 
275
        return totalContentLength, true
 
276
}
 
277
 
 
278
func ResolveRelative(basestr, relstr string) string {
 
279
        u, _ := url.Parse(basestr)
 
280
        rel, _ := url.Parse(relstr)
 
281
        u = u.ResolveReference(rel)
 
282
        us := u.String()
 
283
        us = strings.Replace(us, "%7B", "{", -1)
 
284
        us = strings.Replace(us, "%7D", "}", -1)
 
285
        return us
 
286
}
 
287
 
 
288
// has4860Fix is whether this Go environment contains the fix for
 
289
// http://golang.org/issue/4860
 
290
var has4860Fix bool
 
291
 
 
292
// init initializes has4860Fix by checking the behavior of the net/http package.
 
293
func init() {
 
294
        r := http.Request{
 
295
                URL: &url.URL{
 
296
                        Scheme: "http",
 
297
                        Opaque: "//opaque",
 
298
                },
 
299
        }
 
300
        b := &bytes.Buffer{}
 
301
        r.Write(b)
 
302
        has4860Fix = bytes.HasPrefix(b.Bytes(), []byte("GET http"))
 
303
}
 
304
 
 
305
// SetOpaque sets u.Opaque from u.Path such that HTTP requests to it
 
306
// don't alter any hex-escaped characters in u.Path.
 
307
func SetOpaque(u *url.URL) {
 
308
        u.Opaque = "//" + u.Host + u.Path
 
309
        if !has4860Fix {
 
310
                u.Opaque = u.Scheme + ":" + u.Opaque
 
311
        }
 
312
}
 
313
 
 
314
// Expand subsitutes any {encoded} strings in the URL passed in using
 
315
// the map supplied.
 
316
//
 
317
// This calls SetOpaque to avoid encoding of the parameters in the URL path.
 
318
func Expand(u *url.URL, expansions map[string]string) {
 
319
        expanded, err := uritemplates.Expand(u.Path, expansions)
 
320
        if err == nil {
 
321
                u.Path = expanded
 
322
                SetOpaque(u)
 
323
        }
 
324
}
 
325
 
 
326
// CloseBody is used to close res.Body.
 
327
// Prior to calling Close, it also tries to Read a small amount to see an EOF.
 
328
// Not seeing an EOF can prevent HTTP Transports from reusing connections.
 
329
func CloseBody(res *http.Response) {
 
330
        if res == nil || res.Body == nil {
 
331
                return
 
332
        }
 
333
        // Justification for 3 byte reads: two for up to "\r\n" after
 
334
        // a JSON/XML document, and then 1 to see EOF if we haven't yet.
 
335
        // TODO(bradfitz): detect Go 1.3+ and skip these reads.
 
336
        // See https://codereview.appspot.com/58240043
 
337
        // and https://codereview.appspot.com/49570044
 
338
        buf := make([]byte, 1)
 
339
        for i := 0; i < 3; i++ {
 
340
                _, err := res.Body.Read(buf)
 
341
                if err != nil {
 
342
                        break
 
343
                }
 
344
        }
 
345
        res.Body.Close()
 
346
 
 
347
}
 
348
 
 
349
// VariantType returns the type name of the given variant.
 
350
// If the map doesn't contain the named key or the value is not a []interface{}, "" is returned.
 
351
// This is used to support "variant" APIs that can return one of a number of different types.
 
352
func VariantType(t map[string]interface{}) string {
 
353
        s, _ := t["type"].(string)
 
354
        return s
 
355
}
 
356
 
 
357
// ConvertVariant uses the JSON encoder/decoder to fill in the struct 'dst' with the fields found in variant 'v'.
 
358
// This is used to support "variant" APIs that can return one of a number of different types.
 
359
// It reports whether the conversion was successful.
 
360
func ConvertVariant(v map[string]interface{}, dst interface{}) bool {
 
361
        var buf bytes.Buffer
 
362
        err := json.NewEncoder(&buf).Encode(v)
 
363
        if err != nil {
 
364
                return false
 
365
        }
 
366
        return json.Unmarshal(buf.Bytes(), dst) == nil
 
367
}
 
368
 
 
369
// A Field names a field to be retrieved with a partial response.
 
370
// See https://developers.google.com/gdata/docs/2.0/basics#PartialResponse
 
371
//
 
372
// Partial responses can dramatically reduce the amount of data that must be sent to your application.
 
373
// In order to request partial responses, you can specify the full list of fields
 
374
// that your application needs by adding the Fields option to your request.
 
375
//
 
376
// Field strings use camelCase with leading lower-case characters to identify fields within the response.
 
377
//
 
378
// For example, if your response has a "NextPageToken" and a slice of "Items" with "Id" fields,
 
379
// you could request just those fields like this:
 
380
//
 
381
//     svc.Events.List().Fields("nextPageToken", "items/id").Do()
 
382
//
 
383
// or if you were also interested in each Item's "Updated" field, you can combine them like this:
 
384
//
 
385
//     svc.Events.List().Fields("nextPageToken", "items(id,updated)").Do()
 
386
//
 
387
// More information about field formatting can be found here:
 
388
// https://developers.google.com/+/api/#fields-syntax
 
389
//
 
390
// Another way to find field names is through the Google API explorer:
 
391
// https://developers.google.com/apis-explorer/#p/
 
392
type Field string
 
393
 
 
394
// CombineFields combines fields into a single string.
 
395
func CombineFields(s []Field) string {
 
396
        r := make([]string, len(s))
 
397
        for i, v := range s {
 
398
                r[i] = string(v)
 
399
        }
 
400
        return strings.Join(r, ",")
 
401
}