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