github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/api/googleapi/googleapi.go (about) 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 "errors" 13 "fmt" 14 "io" 15 "io/ioutil" 16 "mime/multipart" 17 "net/http" 18 "net/textproto" 19 "net/url" 20 "regexp" 21 "strconv" 22 "strings" 23 "sync" 24 "time" 25 26 "golang.org/x/net/context" 27 "golang.org/x/net/context/ctxhttp" 28 "google.golang.org/api/googleapi/internal/uritemplates" 29 ) 30 31 // ContentTyper is an interface for Readers which know (or would like 32 // to override) their Content-Type. If a media body doesn't implement 33 // ContentTyper, the type is sniffed from the content using 34 // http.DetectContentType. 35 type ContentTyper interface { 36 ContentType() string 37 } 38 39 // A SizeReaderAt is a ReaderAt with a Size method. 40 // An io.SectionReader implements SizeReaderAt. 41 type SizeReaderAt interface { 42 io.ReaderAt 43 Size() int64 44 } 45 46 // ServerResponse is embedded in each Do response and 47 // provides the HTTP status code and header sent by the server. 48 type ServerResponse struct { 49 // HTTPStatusCode is the server's response status code. 50 // When using a resource method's Do call, this will always be in the 2xx range. 51 HTTPStatusCode int 52 // Header contains the response header fields from the server. 53 Header http.Header 54 } 55 56 const ( 57 Version = "0.5" 58 59 // statusResumeIncomplete is the code returned by the Google uploader when the transfer is not yet complete. 60 statusResumeIncomplete = 308 61 62 // UserAgent is the header string used to identify this package. 63 UserAgent = "google-api-go-client/" + Version 64 65 // uploadPause determines the delay between failed upload attempts 66 uploadPause = 1 * time.Second 67 ) 68 69 // Error contains an error response from the server. 70 type Error struct { 71 // Code is the HTTP response status code and will always be populated. 72 Code int `json:"code"` 73 // Message is the server response message and is only populated when 74 // explicitly referenced by the JSON server response. 75 Message string `json:"message"` 76 // Body is the raw response returned by the server. 77 // It is often but not always JSON, depending on how the request fails. 78 Body string 79 // Header contains the response header fields from the server. 80 Header http.Header 81 82 Errors []ErrorItem 83 } 84 85 // ErrorItem is a detailed error code & message from the Google API frontend. 86 type ErrorItem struct { 87 // Reason is the typed error code. For example: "some_example". 88 Reason string `json:"reason"` 89 // Message is the human-readable description of the error. 90 Message string `json:"message"` 91 } 92 93 func (e *Error) Error() string { 94 if len(e.Errors) == 0 && e.Message == "" { 95 return fmt.Sprintf("googleapi: got HTTP response code %d with body: %v", e.Code, e.Body) 96 } 97 var buf bytes.Buffer 98 fmt.Fprintf(&buf, "googleapi: Error %d: ", e.Code) 99 if e.Message != "" { 100 fmt.Fprintf(&buf, "%s", e.Message) 101 } 102 if len(e.Errors) == 0 { 103 return strings.TrimSpace(buf.String()) 104 } 105 if len(e.Errors) == 1 && e.Errors[0].Message == e.Message { 106 fmt.Fprintf(&buf, ", %s", e.Errors[0].Reason) 107 return buf.String() 108 } 109 fmt.Fprintln(&buf, "\nMore details:") 110 for _, v := range e.Errors { 111 fmt.Fprintf(&buf, "Reason: %s, Message: %s\n", v.Reason, v.Message) 112 } 113 return buf.String() 114 } 115 116 type errorReply struct { 117 Error *Error `json:"error"` 118 } 119 120 // CheckResponse returns an error (of type *Error) if the response 121 // status code is not 2xx. 122 func CheckResponse(res *http.Response) error { 123 if res.StatusCode >= 200 && res.StatusCode <= 299 { 124 return nil 125 } 126 slurp, err := ioutil.ReadAll(res.Body) 127 if err == nil { 128 jerr := new(errorReply) 129 err = json.Unmarshal(slurp, jerr) 130 if err == nil && jerr.Error != nil { 131 if jerr.Error.Code == 0 { 132 jerr.Error.Code = res.StatusCode 133 } 134 jerr.Error.Body = string(slurp) 135 return jerr.Error 136 } 137 } 138 return &Error{ 139 Code: res.StatusCode, 140 Body: string(slurp), 141 Header: res.Header, 142 } 143 } 144 145 // IsNotModified reports whether err is the result of the 146 // server replying with http.StatusNotModified. 147 // Such error values are sometimes returned by "Do" methods 148 // on calls when If-None-Match is used. 149 func IsNotModified(err error) bool { 150 if err == nil { 151 return false 152 } 153 ae, ok := err.(*Error) 154 return ok && ae.Code == http.StatusNotModified 155 } 156 157 // CheckMediaResponse returns an error (of type *Error) if the response 158 // status code is not 2xx. Unlike CheckResponse it does not assume the 159 // body is a JSON error document. 160 func CheckMediaResponse(res *http.Response) error { 161 if res.StatusCode >= 200 && res.StatusCode <= 299 { 162 return nil 163 } 164 slurp, _ := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20)) 165 res.Body.Close() 166 return &Error{ 167 Code: res.StatusCode, 168 Body: string(slurp), 169 } 170 } 171 172 type MarshalStyle bool 173 174 var WithDataWrapper = MarshalStyle(true) 175 var WithoutDataWrapper = MarshalStyle(false) 176 177 func (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 func getMediaType(media io.Reader) (io.Reader, string) { 193 if typer, ok := media.(ContentTyper); ok { 194 return media, typer.ContentType() 195 } 196 197 pr, pw := io.Pipe() 198 typ := "application/octet-stream" 199 buf, err := ioutil.ReadAll(io.LimitReader(media, 512)) 200 if err != nil { 201 pw.CloseWithError(fmt.Errorf("error reading media: %v", err)) 202 return pr, typ 203 } 204 typ = http.DetectContentType(buf) 205 mr := io.MultiReader(bytes.NewReader(buf), media) 206 go func() { 207 _, err = io.Copy(pw, mr) 208 if err != nil { 209 pw.CloseWithError(fmt.Errorf("error reading media: %v", err)) 210 return 211 } 212 pw.Close() 213 }() 214 return pr, typ 215 } 216 217 // DetectMediaType detects and returns the content type of the provided media. 218 // If the type can not be determined, "application/octet-stream" is returned. 219 func DetectMediaType(media io.ReaderAt) string { 220 if typer, ok := media.(ContentTyper); ok { 221 return typer.ContentType() 222 } 223 224 typ := "application/octet-stream" 225 buf := make([]byte, 1024) 226 n, err := media.ReadAt(buf, 0) 227 buf = buf[:n] 228 if err == nil || err == io.EOF { 229 typ = http.DetectContentType(buf) 230 } 231 return typ 232 } 233 234 type Lengther interface { 235 Len() int 236 } 237 238 // endingWithErrorReader from r until it returns an error. If the 239 // final error from r is io.EOF and e is non-nil, e is used instead. 240 type endingWithErrorReader struct { 241 r io.Reader 242 e error 243 } 244 245 func (er endingWithErrorReader) Read(p []byte) (n int, err error) { 246 n, err = er.r.Read(p) 247 if err == io.EOF && er.e != nil { 248 err = er.e 249 } 250 return 251 } 252 253 func typeHeader(contentType string) textproto.MIMEHeader { 254 h := make(textproto.MIMEHeader) 255 h.Set("Content-Type", contentType) 256 return h 257 } 258 259 // countingWriter counts the number of bytes it receives to write, but 260 // discards them. 261 type countingWriter struct { 262 n *int64 263 } 264 265 func (w countingWriter) Write(p []byte) (int, error) { 266 *w.n += int64(len(p)) 267 return len(p), nil 268 } 269 270 // ConditionallyIncludeMedia does nothing if media is nil. 271 // 272 // bodyp is an in/out parameter. It should initially point to the 273 // reader of the application/json (or whatever) payload to send in the 274 // API request. It's updated to point to the multipart body reader. 275 // 276 // ctypep is an in/out parameter. It should initially point to the 277 // content type of the bodyp, usually "application/json". It's updated 278 // to the "multipart/related" content type, with random boundary. 279 // 280 // The return value is the content-length of the entire multpart body. 281 func ConditionallyIncludeMedia(media io.Reader, bodyp *io.Reader, ctypep *string) (cancel func(), ok bool) { 282 if media == nil { 283 return 284 } 285 // Get the media type, which might return a different reader instance. 286 var mediaType string 287 media, mediaType = getMediaType(media) 288 289 body, bodyType := *bodyp, *ctypep 290 291 pr, pw := io.Pipe() 292 mpw := multipart.NewWriter(pw) 293 *bodyp = pr 294 *ctypep = "multipart/related; boundary=" + mpw.Boundary() 295 go func() { 296 w, err := mpw.CreatePart(typeHeader(bodyType)) 297 if err != nil { 298 mpw.Close() 299 pw.CloseWithError(fmt.Errorf("googleapi: body CreatePart failed: %v", err)) 300 return 301 } 302 _, err = io.Copy(w, body) 303 if err != nil { 304 mpw.Close() 305 pw.CloseWithError(fmt.Errorf("googleapi: body Copy failed: %v", err)) 306 return 307 } 308 309 w, err = mpw.CreatePart(typeHeader(mediaType)) 310 if err != nil { 311 mpw.Close() 312 pw.CloseWithError(fmt.Errorf("googleapi: media CreatePart failed: %v", err)) 313 return 314 } 315 _, err = io.Copy(w, media) 316 if err != nil { 317 mpw.Close() 318 pw.CloseWithError(fmt.Errorf("googleapi: media Copy failed: %v", err)) 319 return 320 } 321 mpw.Close() 322 pw.Close() 323 }() 324 cancel = func() { pw.CloseWithError(errAborted) } 325 return cancel, true 326 } 327 328 var errAborted = errors.New("googleapi: upload aborted") 329 330 // ProgressUpdater is a function that is called upon every progress update of a resumable upload. 331 // This is the only part of a resumable upload (from googleapi) that is usable by the developer. 332 // The remaining usable pieces of resumable uploads is exposed in each auto-generated API. 333 type ProgressUpdater func(current, total int64) 334 335 // ResumableUpload is used by the generated APIs to provide resumable uploads. 336 // It is not used by developers directly. 337 type ResumableUpload struct { 338 Client *http.Client 339 // URI is the resumable resource destination provided by the server after specifying "&uploadType=resumable". 340 URI string 341 UserAgent string // User-Agent for header of the request 342 // Media is the object being uploaded. 343 Media io.ReaderAt 344 // MediaType defines the media type, e.g. "image/jpeg". 345 MediaType string 346 // ContentLength is the full size of the object being uploaded. 347 ContentLength int64 348 349 mu sync.Mutex // guards progress 350 progress int64 // number of bytes uploaded so far 351 352 // Callback is an optional function that will be periodically called with the cumulative number of bytes uploaded. 353 Callback func(int64) 354 } 355 356 var ( 357 // rangeRE matches the transfer status response from the server. $1 is the last byte index uploaded. 358 rangeRE = regexp.MustCompile(`^bytes=0\-(\d+)$`) 359 // chunkSize is the size of the chunks created during a resumable upload and should be a power of two. 360 // 1<<18 is the minimum size supported by the Google uploader, and there is no maximum. 361 chunkSize int64 = 1 << 18 362 ) 363 364 // Progress returns the number of bytes uploaded at this point. 365 func (rx *ResumableUpload) Progress() int64 { 366 rx.mu.Lock() 367 defer rx.mu.Unlock() 368 return rx.progress 369 } 370 371 func (rx *ResumableUpload) transferStatus(ctx context.Context) (int64, *http.Response, error) { 372 req, _ := http.NewRequest("POST", rx.URI, nil) 373 req.ContentLength = 0 374 req.Header.Set("User-Agent", rx.UserAgent) 375 req.Header.Set("Content-Range", fmt.Sprintf("bytes */%v", rx.ContentLength)) 376 res, err := ctxhttp.Do(ctx, rx.Client, req) 377 if err != nil || res.StatusCode != statusResumeIncomplete { 378 return 0, res, err 379 } 380 var start int64 381 if m := rangeRE.FindStringSubmatch(res.Header.Get("Range")); len(m) == 2 { 382 start, err = strconv.ParseInt(m[1], 10, 64) 383 if err != nil { 384 return 0, nil, fmt.Errorf("unable to parse range size %v", m[1]) 385 } 386 start += 1 // Start at the next byte 387 } 388 return start, res, nil 389 } 390 391 type chunk struct { 392 body io.Reader 393 size int64 394 err error 395 } 396 397 func (rx *ResumableUpload) transferChunks(ctx context.Context) (*http.Response, error) { 398 start, res, err := rx.transferStatus(ctx) 399 if err != nil || res.StatusCode != statusResumeIncomplete { 400 if err == context.Canceled { 401 return &http.Response{StatusCode: http.StatusRequestTimeout}, err 402 } 403 return res, err 404 } 405 406 for { 407 select { // Check for cancellation 408 case <-ctx.Done(): 409 res.StatusCode = http.StatusRequestTimeout 410 return res, ctx.Err() 411 default: 412 } 413 reqSize := rx.ContentLength - start 414 if reqSize > chunkSize { 415 reqSize = chunkSize 416 } 417 r := io.NewSectionReader(rx.Media, start, reqSize) 418 req, _ := http.NewRequest("POST", rx.URI, r) 419 req.ContentLength = reqSize 420 req.Header.Set("Content-Range", fmt.Sprintf("bytes %v-%v/%v", start, start+reqSize-1, rx.ContentLength)) 421 req.Header.Set("Content-Type", rx.MediaType) 422 req.Header.Set("User-Agent", rx.UserAgent) 423 res, err = ctxhttp.Do(ctx, rx.Client, req) 424 start += reqSize 425 if err == nil && (res.StatusCode == statusResumeIncomplete || res.StatusCode == http.StatusOK) { 426 rx.mu.Lock() 427 rx.progress = start // keep track of number of bytes sent so far 428 rx.mu.Unlock() 429 if rx.Callback != nil { 430 rx.Callback(start) 431 } 432 } 433 if err != nil || res.StatusCode != statusResumeIncomplete { 434 break 435 } 436 } 437 return res, err 438 } 439 440 var sleep = time.Sleep // override in unit tests 441 442 // Upload starts the process of a resumable upload with a cancellable context. 443 // It retries indefinitely (with a pause of uploadPause between attempts) until cancelled. 444 // It is called from the auto-generated API code and is not visible to the user. 445 // rx is private to the auto-generated API code. 446 func (rx *ResumableUpload) Upload(ctx context.Context) (*http.Response, error) { 447 var res *http.Response 448 var err error 449 for { 450 res, err = rx.transferChunks(ctx) 451 if err != nil || res.StatusCode == http.StatusCreated || res.StatusCode == http.StatusOK { 452 return res, err 453 } 454 select { // Check for cancellation 455 case <-ctx.Done(): 456 res.StatusCode = http.StatusRequestTimeout 457 return res, ctx.Err() 458 default: 459 } 460 sleep(uploadPause) 461 } 462 return res, err 463 } 464 465 func ResolveRelative(basestr, relstr string) string { 466 u, _ := url.Parse(basestr) 467 rel, _ := url.Parse(relstr) 468 u = u.ResolveReference(rel) 469 us := u.String() 470 us = strings.Replace(us, "%7B", "{", -1) 471 us = strings.Replace(us, "%7D", "}", -1) 472 return us 473 } 474 475 // has4860Fix is whether this Go environment contains the fix for 476 // http://golang.org/issue/4860 477 var has4860Fix bool 478 479 // init initializes has4860Fix by checking the behavior of the net/http package. 480 func init() { 481 r := http.Request{ 482 URL: &url.URL{ 483 Scheme: "http", 484 Opaque: "//opaque", 485 }, 486 } 487 b := &bytes.Buffer{} 488 r.Write(b) 489 has4860Fix = bytes.HasPrefix(b.Bytes(), []byte("GET http")) 490 } 491 492 // SetOpaque sets u.Opaque from u.Path such that HTTP requests to it 493 // don't alter any hex-escaped characters in u.Path. 494 func SetOpaque(u *url.URL) { 495 u.Opaque = "//" + u.Host + u.Path 496 if !has4860Fix { 497 u.Opaque = u.Scheme + ":" + u.Opaque 498 } 499 } 500 501 // Expand subsitutes any {encoded} strings in the URL passed in using 502 // the map supplied. 503 // 504 // This calls SetOpaque to avoid encoding of the parameters in the URL path. 505 func Expand(u *url.URL, expansions map[string]string) { 506 expanded, err := uritemplates.Expand(u.Path, expansions) 507 if err == nil { 508 u.Path = expanded 509 SetOpaque(u) 510 } 511 } 512 513 // CloseBody is used to close res.Body. 514 // Prior to calling Close, it also tries to Read a small amount to see an EOF. 515 // Not seeing an EOF can prevent HTTP Transports from reusing connections. 516 func CloseBody(res *http.Response) { 517 if res == nil || res.Body == nil { 518 return 519 } 520 // Justification for 3 byte reads: two for up to "\r\n" after 521 // a JSON/XML document, and then 1 to see EOF if we haven't yet. 522 // TODO(bradfitz): detect Go 1.3+ and skip these reads. 523 // See https://codereview.appspot.com/58240043 524 // and https://codereview.appspot.com/49570044 525 buf := make([]byte, 1) 526 for i := 0; i < 3; i++ { 527 _, err := res.Body.Read(buf) 528 if err != nil { 529 break 530 } 531 } 532 res.Body.Close() 533 534 } 535 536 // VariantType returns the type name of the given variant. 537 // If the map doesn't contain the named key or the value is not a []interface{}, "" is returned. 538 // This is used to support "variant" APIs that can return one of a number of different types. 539 func VariantType(t map[string]interface{}) string { 540 s, _ := t["type"].(string) 541 return s 542 } 543 544 // ConvertVariant uses the JSON encoder/decoder to fill in the struct 'dst' with the fields found in variant 'v'. 545 // This is used to support "variant" APIs that can return one of a number of different types. 546 // It reports whether the conversion was successful. 547 func ConvertVariant(v map[string]interface{}, dst interface{}) bool { 548 var buf bytes.Buffer 549 err := json.NewEncoder(&buf).Encode(v) 550 if err != nil { 551 return false 552 } 553 return json.Unmarshal(buf.Bytes(), dst) == nil 554 } 555 556 // A Field names a field to be retrieved with a partial response. 557 // See https://developers.google.com/gdata/docs/2.0/basics#PartialResponse 558 // 559 // Partial responses can dramatically reduce the amount of data that must be sent to your application. 560 // In order to request partial responses, you can specify the full list of fields 561 // that your application needs by adding the Fields option to your request. 562 // 563 // Field strings use camelCase with leading lower-case characters to identify fields within the response. 564 // 565 // For example, if your response has a "NextPageToken" and a slice of "Items" with "Id" fields, 566 // you could request just those fields like this: 567 // 568 // svc.Events.List().Fields("nextPageToken", "items/id").Do() 569 // 570 // or if you were also interested in each Item's "Updated" field, you can combine them like this: 571 // 572 // svc.Events.List().Fields("nextPageToken", "items(id,updated)").Do() 573 // 574 // More information about field formatting can be found here: 575 // https://developers.google.com/+/api/#fields-syntax 576 // 577 // Another way to find field names is through the Google API explorer: 578 // https://developers.google.com/apis-explorer/#p/ 579 type Field string 580 581 // CombineFields combines fields into a single string. 582 func CombineFields(s []Field) string { 583 r := make([]string, len(s)) 584 for i, v := range s { 585 r[i] = string(v) 586 } 587 return strings.Join(r, ",") 588 }