• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
7package googleapi
8
9import (
10	"bytes"
11	"encoding/json"
12	"fmt"
13	"io"
14	"io/ioutil"
15	"net/http"
16	"net/url"
17	"strings"
18
19	"google.golang.org/api/googleapi/internal/uritemplates"
20)
21
22// ContentTyper is an interface for Readers which know (or would like
23// to override) their Content-Type. If a media body doesn't implement
24// ContentTyper, the type is sniffed from the content using
25// http.DetectContentType.
26type ContentTyper interface {
27	ContentType() string
28}
29
30// A SizeReaderAt is a ReaderAt with a Size method.
31// An io.SectionReader implements SizeReaderAt.
32type SizeReaderAt interface {
33	io.ReaderAt
34	Size() int64
35}
36
37// ServerResponse is embedded in each Do response and
38// provides the HTTP status code and header sent by the server.
39type ServerResponse struct {
40	// HTTPStatusCode is the server's response status code.
41	// When using a resource method's Do call, this will always be in the 2xx range.
42	HTTPStatusCode int
43	// Header contains the response header fields from the server.
44	Header http.Header
45}
46
47const (
48	Version = "0.5"
49
50	// UserAgent is the header string used to identify this package.
51	UserAgent = "google-api-go-client/" + Version
52
53	// The default chunk size to use for resumable uploads if not specified by the user.
54	DefaultUploadChunkSize = 8 * 1024 * 1024
55
56	// The minimum chunk size that can be used for resumable uploads.  All
57	// user-specified chunk sizes must be multiple of this value.
58	MinUploadChunkSize = 256 * 1024
59)
60
61// Error contains an error response from the server.
62type Error struct {
63	// Code is the HTTP response status code and will always be populated.
64	Code int `json:"code"`
65	// Message is the server response message and is only populated when
66	// explicitly referenced by the JSON server response.
67	Message string `json:"message"`
68	// Body is the raw response returned by the server.
69	// It is often but not always JSON, depending on how the request fails.
70	Body string
71	// Header contains the response header fields from the server.
72	Header http.Header
73
74	Errors []ErrorItem
75}
76
77// ErrorItem is a detailed error code & message from the Google API frontend.
78type ErrorItem struct {
79	// Reason is the typed error code. For example: "some_example".
80	Reason string `json:"reason"`
81	// Message is the human-readable description of the error.
82	Message string `json:"message"`
83}
84
85func (e *Error) Error() string {
86	if len(e.Errors) == 0 && e.Message == "" {
87		return fmt.Sprintf("googleapi: got HTTP response code %d with body: %v", e.Code, e.Body)
88	}
89	var buf bytes.Buffer
90	fmt.Fprintf(&buf, "googleapi: Error %d: ", e.Code)
91	if e.Message != "" {
92		fmt.Fprintf(&buf, "%s", e.Message)
93	}
94	if len(e.Errors) == 0 {
95		return strings.TrimSpace(buf.String())
96	}
97	if len(e.Errors) == 1 && e.Errors[0].Message == e.Message {
98		fmt.Fprintf(&buf, ", %s", e.Errors[0].Reason)
99		return buf.String()
100	}
101	fmt.Fprintln(&buf, "\nMore details:")
102	for _, v := range e.Errors {
103		fmt.Fprintf(&buf, "Reason: %s, Message: %s\n", v.Reason, v.Message)
104	}
105	return buf.String()
106}
107
108type errorReply struct {
109	Error *Error `json:"error"`
110}
111
112// CheckResponse returns an error (of type *Error) if the response
113// status code is not 2xx.
114func CheckResponse(res *http.Response) error {
115	if res.StatusCode >= 200 && res.StatusCode <= 299 {
116		return nil
117	}
118	slurp, err := ioutil.ReadAll(res.Body)
119	if err == nil {
120		jerr := new(errorReply)
121		err = json.Unmarshal(slurp, jerr)
122		if err == nil && jerr.Error != nil {
123			if jerr.Error.Code == 0 {
124				jerr.Error.Code = res.StatusCode
125			}
126			jerr.Error.Body = string(slurp)
127			return jerr.Error
128		}
129	}
130	return &Error{
131		Code:   res.StatusCode,
132		Body:   string(slurp),
133		Header: res.Header,
134	}
135}
136
137// IsNotModified reports whether err is the result of the
138// server replying with http.StatusNotModified.
139// Such error values are sometimes returned by "Do" methods
140// on calls when If-None-Match is used.
141func IsNotModified(err error) bool {
142	if err == nil {
143		return false
144	}
145	ae, ok := err.(*Error)
146	return ok && ae.Code == http.StatusNotModified
147}
148
149// CheckMediaResponse returns an error (of type *Error) if the response
150// status code is not 2xx. Unlike CheckResponse it does not assume the
151// body is a JSON error document.
152// It is the caller's responsibility to close res.Body.
153func CheckMediaResponse(res *http.Response) error {
154	if res.StatusCode >= 200 && res.StatusCode <= 299 {
155		return nil
156	}
157	slurp, _ := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20))
158	return &Error{
159		Code: res.StatusCode,
160		Body: string(slurp),
161	}
162}
163
164type MarshalStyle bool
165
166var WithDataWrapper = MarshalStyle(true)
167var WithoutDataWrapper = MarshalStyle(false)
168
169func (wrap MarshalStyle) JSONReader(v interface{}) (io.Reader, error) {
170	buf := new(bytes.Buffer)
171	if wrap {
172		buf.Write([]byte(`{"data": `))
173	}
174	err := json.NewEncoder(buf).Encode(v)
175	if err != nil {
176		return nil, err
177	}
178	if wrap {
179		buf.Write([]byte(`}`))
180	}
181	return buf, nil
182}
183
184// endingWithErrorReader from r until it returns an error.  If the
185// final error from r is io.EOF and e is non-nil, e is used instead.
186type endingWithErrorReader struct {
187	r io.Reader
188	e error
189}
190
191func (er endingWithErrorReader) Read(p []byte) (n int, err error) {
192	n, err = er.r.Read(p)
193	if err == io.EOF && er.e != nil {
194		err = er.e
195	}
196	return
197}
198
199// countingWriter counts the number of bytes it receives to write, but
200// discards them.
201type countingWriter struct {
202	n *int64
203}
204
205func (w countingWriter) Write(p []byte) (int, error) {
206	*w.n += int64(len(p))
207	return len(p), nil
208}
209
210// ProgressUpdater is a function that is called upon every progress update of a resumable upload.
211// This is the only part of a resumable upload (from googleapi) that is usable by the developer.
212// The remaining usable pieces of resumable uploads is exposed in each auto-generated API.
213type ProgressUpdater func(current, total int64)
214
215type MediaOption interface {
216	setOptions(o *MediaOptions)
217}
218
219type contentTypeOption string
220
221func (ct contentTypeOption) setOptions(o *MediaOptions) {
222	o.ContentType = string(ct)
223	if o.ContentType == "" {
224		o.ForceEmptyContentType = true
225	}
226}
227
228// ContentType returns a MediaOption which sets the Content-Type header for media uploads.
229// If ctype is empty, the Content-Type header will be omitted.
230func ContentType(ctype string) MediaOption {
231	return contentTypeOption(ctype)
232}
233
234type chunkSizeOption int
235
236func (cs chunkSizeOption) setOptions(o *MediaOptions) {
237	size := int(cs)
238	if size%MinUploadChunkSize != 0 {
239		size += MinUploadChunkSize - (size % MinUploadChunkSize)
240	}
241	o.ChunkSize = size
242}
243
244// ChunkSize returns a MediaOption which sets the chunk size for media uploads.
245// size will be rounded up to the nearest multiple of 256K.
246// Media which contains fewer than size bytes will be uploaded in a single request.
247// Media which contains size bytes or more will be uploaded in separate chunks.
248// If size is zero, media will be uploaded in a single request.
249func ChunkSize(size int) MediaOption {
250	return chunkSizeOption(size)
251}
252
253// MediaOptions stores options for customizing media upload.  It is not used by developers directly.
254type MediaOptions struct {
255	ContentType           string
256	ForceEmptyContentType bool
257
258	ChunkSize int
259}
260
261// ProcessMediaOptions stores options from opts in a MediaOptions.
262// It is not used by developers directly.
263func ProcessMediaOptions(opts []MediaOption) *MediaOptions {
264	mo := &MediaOptions{ChunkSize: DefaultUploadChunkSize}
265	for _, o := range opts {
266		o.setOptions(mo)
267	}
268	return mo
269}
270
271func ResolveRelative(basestr, relstr string) string {
272	u, _ := url.Parse(basestr)
273	rel, _ := url.Parse(relstr)
274	u = u.ResolveReference(rel)
275	us := u.String()
276	us = strings.Replace(us, "%7B", "{", -1)
277	us = strings.Replace(us, "%7D", "}", -1)
278	return us
279}
280
281// Expand subsitutes any {encoded} strings in the URL passed in using
282// the map supplied.
283//
284// This calls SetOpaque to avoid encoding of the parameters in the URL path.
285func Expand(u *url.URL, expansions map[string]string) {
286	escaped, unescaped, err := uritemplates.Expand(u.Path, expansions)
287	if err == nil {
288		u.Path = unescaped
289		u.RawPath = escaped
290	}
291}
292
293// CloseBody is used to close res.Body.
294// Prior to calling Close, it also tries to Read a small amount to see an EOF.
295// Not seeing an EOF can prevent HTTP Transports from reusing connections.
296func CloseBody(res *http.Response) {
297	if res == nil || res.Body == nil {
298		return
299	}
300	// Justification for 3 byte reads: two for up to "\r\n" after
301	// a JSON/XML document, and then 1 to see EOF if we haven't yet.
302	// TODO(bradfitz): detect Go 1.3+ and skip these reads.
303	// See https://codereview.appspot.com/58240043
304	// and https://codereview.appspot.com/49570044
305	buf := make([]byte, 1)
306	for i := 0; i < 3; i++ {
307		_, err := res.Body.Read(buf)
308		if err != nil {
309			break
310		}
311	}
312	res.Body.Close()
313
314}
315
316// VariantType returns the type name of the given variant.
317// If the map doesn't contain the named key or the value is not a []interface{}, "" is returned.
318// This is used to support "variant" APIs that can return one of a number of different types.
319func VariantType(t map[string]interface{}) string {
320	s, _ := t["type"].(string)
321	return s
322}
323
324// ConvertVariant uses the JSON encoder/decoder to fill in the struct 'dst' with the fields found in variant 'v'.
325// This is used to support "variant" APIs that can return one of a number of different types.
326// It reports whether the conversion was successful.
327func ConvertVariant(v map[string]interface{}, dst interface{}) bool {
328	var buf bytes.Buffer
329	err := json.NewEncoder(&buf).Encode(v)
330	if err != nil {
331		return false
332	}
333	return json.Unmarshal(buf.Bytes(), dst) == nil
334}
335
336// A Field names a field to be retrieved with a partial response.
337// See https://developers.google.com/gdata/docs/2.0/basics#PartialResponse
338//
339// Partial responses can dramatically reduce the amount of data that must be sent to your application.
340// In order to request partial responses, you can specify the full list of fields
341// that your application needs by adding the Fields option to your request.
342//
343// Field strings use camelCase with leading lower-case characters to identify fields within the response.
344//
345// For example, if your response has a "NextPageToken" and a slice of "Items" with "Id" fields,
346// you could request just those fields like this:
347//
348//     svc.Events.List().Fields("nextPageToken", "items/id").Do()
349//
350// or if you were also interested in each Item's "Updated" field, you can combine them like this:
351//
352//     svc.Events.List().Fields("nextPageToken", "items(id,updated)").Do()
353//
354// More information about field formatting can be found here:
355// https://developers.google.com/+/api/#fields-syntax
356//
357// Another way to find field names is through the Google API explorer:
358// https://developers.google.com/apis-explorer/#p/
359type Field string
360
361// CombineFields combines fields into a single string.
362func CombineFields(s []Field) string {
363	r := make([]string, len(s))
364	for i, v := range s {
365		r[i] = string(v)
366	}
367	return strings.Join(r, ",")
368}
369
370// A CallOption is an optional argument to an API call.
371// It should be treated as an opaque value by users of Google APIs.
372//
373// A CallOption is something that configures an API call in a way that is
374// not specific to that API; for instance, controlling the quota user for
375// an API call is common across many APIs, and is thus a CallOption.
376type CallOption interface {
377	Get() (key, value string)
378}
379
380// QuotaUser returns a CallOption that will set the quota user for a call.
381// The quota user can be used by server-side applications to control accounting.
382// It can be an arbitrary string up to 40 characters, and will override UserIP
383// if both are provided.
384func QuotaUser(u string) CallOption { return quotaUser(u) }
385
386type quotaUser string
387
388func (q quotaUser) Get() (string, string) { return "quotaUser", string(q) }
389
390// UserIP returns a CallOption that will set the "userIp" parameter of a call.
391// This should be the IP address of the originating request.
392func UserIP(ip string) CallOption { return userIP(ip) }
393
394type userIP string
395
396func (i userIP) Get() (string, string) { return "userIp", string(i) }
397
398// Trace returns a CallOption that enables diagnostic tracing for a call.
399// traceToken is an ID supplied by Google support.
400func Trace(traceToken string) CallOption { return traceTok(traceToken) }
401
402type traceTok string
403
404func (t traceTok) Get() (string, string) { return "trace", "token:" + string(t) }
405
406// TODO: Fields too
407