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  }