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