github.com/rochacon/deis@v1.0.2-0.20150903015341-6839b592a1ff/Godeps/_workspace/src/code.google.com/p/google-api-go-client/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  	"fmt"
    13  	"io"
    14  	"io/ioutil"
    15  	"mime/multipart"
    16  	"net/http"
    17  	"net/textproto"
    18  	"net/url"
    19  	"os"
    20  	"strings"
    21  
    22  	"code.google.com/p/google-api-go-client/googleapi/internal/uritemplates"
    23  )
    24  
    25  // ContentTyper is an interface for Readers which know (or would like
    26  // to override) their Content-Type. If a media body doesn't implement
    27  // ContentTyper, the type is sniffed from the content using
    28  // http.DetectContentType.
    29  type ContentTyper interface {
    30  	ContentType() string
    31  }
    32  
    33  const Version = "0.5"
    34  
    35  // Error contains an error response from the server.
    36  type Error struct {
    37  	// Code is the HTTP response status code and will always be populated.
    38  	Code int `json:"code"`
    39  	// Message is the server response message and is only populated when
    40  	// explicitly referenced by the JSON server response.
    41  	Message string `json:"message"`
    42  	// Body is the raw response returned by the server.
    43  	// It is often but not always JSON, depending on how the request fails.
    44  	Body string
    45  
    46  	Errors []ErrorItem
    47  }
    48  
    49  // ErrorItem is a detailed error code & message from the Google API frontend.
    50  type ErrorItem struct {
    51  	// Reason is the typed error code. For example: "some_example".
    52  	Reason string `json:"reason"`
    53  	// Message is the human-readable description of the error.
    54  	Message string `json:"message"`
    55  }
    56  
    57  func (e *Error) Error() string {
    58  	if len(e.Errors) == 0 && e.Message == "" {
    59  		return fmt.Sprintf("googleapi: got HTTP response code %d with body: %v", e.Code, e.Body)
    60  	}
    61  	var buf bytes.Buffer
    62  	fmt.Fprintf(&buf, "googleapi: Error %d: ", e.Code)
    63  	if e.Message != "" {
    64  		fmt.Fprintf(&buf, "%s", e.Message)
    65  	}
    66  	if len(e.Errors) == 0 {
    67  		return strings.TrimSpace(buf.String())
    68  	}
    69  	if len(e.Errors) == 1 && e.Errors[0].Message == e.Message {
    70  		fmt.Fprintf(&buf, ", %s", e.Errors[0].Reason)
    71  		return buf.String()
    72  	}
    73  	fmt.Fprintln(&buf, "\nMore details:")
    74  	for _, v := range e.Errors {
    75  		fmt.Fprintf(&buf, "Reason: %s, Message: %s\n", v.Reason, v.Message)
    76  	}
    77  	return buf.String()
    78  }
    79  
    80  type errorReply struct {
    81  	Error *Error `json:"error"`
    82  }
    83  
    84  // CheckResponse returns an error (of type *Error) if the response
    85  // status code is not 2xx.
    86  func CheckResponse(res *http.Response) error {
    87  	if res.StatusCode >= 200 && res.StatusCode <= 299 {
    88  		return nil
    89  	}
    90  	slurp, err := ioutil.ReadAll(res.Body)
    91  	if err == nil {
    92  		jerr := new(errorReply)
    93  		err = json.Unmarshal(slurp, jerr)
    94  		if err == nil && jerr.Error != nil {
    95  			if jerr.Error.Code == 0 {
    96  				jerr.Error.Code = res.StatusCode
    97  			}
    98  			jerr.Error.Body = string(slurp)
    99  			return jerr.Error
   100  		}
   101  	}
   102  	return &Error{
   103  		Code: res.StatusCode,
   104  		Body: string(slurp),
   105  	}
   106  }
   107  
   108  type MarshalStyle bool
   109  
   110  var WithDataWrapper = MarshalStyle(true)
   111  var WithoutDataWrapper = MarshalStyle(false)
   112  
   113  func (wrap MarshalStyle) JSONReader(v interface{}) (io.Reader, error) {
   114  	buf := new(bytes.Buffer)
   115  	if wrap {
   116  		buf.Write([]byte(`{"data": `))
   117  	}
   118  	err := json.NewEncoder(buf).Encode(v)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	if wrap {
   123  		buf.Write([]byte(`}`))
   124  	}
   125  	return buf, nil
   126  }
   127  
   128  func getMediaType(media io.Reader) (io.Reader, string) {
   129  	if typer, ok := media.(ContentTyper); ok {
   130  		return media, typer.ContentType()
   131  	}
   132  
   133  	typ := "application/octet-stream"
   134  	buf := make([]byte, 1024)
   135  	n, err := media.Read(buf)
   136  	buf = buf[:n]
   137  	if err == nil {
   138  		typ = http.DetectContentType(buf)
   139  	}
   140  	return io.MultiReader(bytes.NewBuffer(buf), media), typ
   141  }
   142  
   143  type Lengther interface {
   144  	Len() int
   145  }
   146  
   147  // endingWithErrorReader from r until it returns an error.  If the
   148  // final error from r is os.EOF and e is non-nil, e is used instead.
   149  type endingWithErrorReader struct {
   150  	r io.Reader
   151  	e error
   152  }
   153  
   154  func (er endingWithErrorReader) Read(p []byte) (n int, err error) {
   155  	n, err = er.r.Read(p)
   156  	if err == io.EOF && er.e != nil {
   157  		err = er.e
   158  	}
   159  	return
   160  }
   161  
   162  func getReaderSize(r io.Reader) (io.Reader, int64) {
   163  	// Ideal case, the reader knows its own size.
   164  	if lr, ok := r.(Lengther); ok {
   165  		return r, int64(lr.Len())
   166  	}
   167  
   168  	// But maybe it's a seeker and we can seek to the end to find its size.
   169  	if s, ok := r.(io.Seeker); ok {
   170  		pos0, err := s.Seek(0, os.SEEK_CUR)
   171  		if err == nil {
   172  			posend, err := s.Seek(0, os.SEEK_END)
   173  			if err == nil {
   174  				_, err = s.Seek(pos0, os.SEEK_SET)
   175  				if err == nil {
   176  					return r, posend - pos0
   177  				} else {
   178  					// We moved it forward but can't restore it.
   179  					// Seems unlikely, but can't really restore now.
   180  					return endingWithErrorReader{strings.NewReader(""), err}, posend - pos0
   181  				}
   182  			}
   183  		}
   184  	}
   185  
   186  	// Otherwise we have to make a copy to calculate how big the reader is.
   187  	buf := new(bytes.Buffer)
   188  	// TODO(bradfitz): put a cap on this copy? spill to disk after
   189  	// a certain point?
   190  	_, err := io.Copy(buf, r)
   191  	return endingWithErrorReader{buf, err}, int64(buf.Len())
   192  }
   193  
   194  func typeHeader(contentType string) textproto.MIMEHeader {
   195  	h := make(textproto.MIMEHeader)
   196  	h.Set("Content-Type", contentType)
   197  	return h
   198  }
   199  
   200  // countingWriter counts the number of bytes it receives to write, but
   201  // discards them.
   202  type countingWriter struct {
   203  	n *int64
   204  }
   205  
   206  func (w countingWriter) Write(p []byte) (int, error) {
   207  	*w.n += int64(len(p))
   208  	return len(p), nil
   209  }
   210  
   211  // ConditionallyIncludeMedia does nothing if media is nil.
   212  //
   213  // bodyp is an in/out parameter.  It should initially point to the
   214  // reader of the application/json (or whatever) payload to send in the
   215  // API request.  It's updated to point to the multipart body reader.
   216  //
   217  // ctypep is an in/out parameter.  It should initially point to the
   218  // content type of the bodyp, usually "application/json".  It's updated
   219  // to the "multipart/related" content type, with random boundary.
   220  //
   221  // The return value is the content-length of the entire multpart body.
   222  func ConditionallyIncludeMedia(media io.Reader, bodyp *io.Reader, ctypep *string) (totalContentLength int64, ok bool) {
   223  	if media == nil {
   224  		return
   225  	}
   226  	// Get the media type and size. The type check might return a
   227  	// different reader instance, so do the size check first,
   228  	// which looks at the specific type of the io.Reader.
   229  	var mediaType string
   230  	if typer, ok := media.(ContentTyper); ok {
   231  		mediaType = typer.ContentType()
   232  	}
   233  	media, mediaSize := getReaderSize(media)
   234  	if mediaType == "" {
   235  		media, mediaType = getMediaType(media)
   236  	}
   237  	body, bodyType := *bodyp, *ctypep
   238  	body, bodySize := getReaderSize(body)
   239  
   240  	// Calculate how big the the multipart will be.
   241  	{
   242  		totalContentLength = bodySize + mediaSize
   243  		mpw := multipart.NewWriter(countingWriter{&totalContentLength})
   244  		mpw.CreatePart(typeHeader(bodyType))
   245  		mpw.CreatePart(typeHeader(mediaType))
   246  		mpw.Close()
   247  	}
   248  
   249  	pr, pw := io.Pipe()
   250  	mpw := multipart.NewWriter(pw)
   251  	*bodyp = pr
   252  	*ctypep = "multipart/related; boundary=" + mpw.Boundary()
   253  	go func() {
   254  		defer pw.Close()
   255  		defer mpw.Close()
   256  
   257  		w, err := mpw.CreatePart(typeHeader(bodyType))
   258  		if err != nil {
   259  			return
   260  		}
   261  		_, err = io.Copy(w, body)
   262  		if err != nil {
   263  			return
   264  		}
   265  
   266  		w, err = mpw.CreatePart(typeHeader(mediaType))
   267  		if err != nil {
   268  			return
   269  		}
   270  		_, err = io.Copy(w, media)
   271  		if err != nil {
   272  			return
   273  		}
   274  	}()
   275  	return totalContentLength, true
   276  }
   277  
   278  func ResolveRelative(basestr, relstr string) string {
   279  	u, _ := url.Parse(basestr)
   280  	rel, _ := url.Parse(relstr)
   281  	u = u.ResolveReference(rel)
   282  	us := u.String()
   283  	us = strings.Replace(us, "%7B", "{", -1)
   284  	us = strings.Replace(us, "%7D", "}", -1)
   285  	return us
   286  }
   287  
   288  // has4860Fix is whether this Go environment contains the fix for
   289  // http://golang.org/issue/4860
   290  var has4860Fix bool
   291  
   292  // init initializes has4860Fix by checking the behavior of the net/http package.
   293  func init() {
   294  	r := http.Request{
   295  		URL: &url.URL{
   296  			Scheme: "http",
   297  			Opaque: "//opaque",
   298  		},
   299  	}
   300  	b := &bytes.Buffer{}
   301  	r.Write(b)
   302  	has4860Fix = bytes.HasPrefix(b.Bytes(), []byte("GET http"))
   303  }
   304  
   305  // SetOpaque sets u.Opaque from u.Path such that HTTP requests to it
   306  // don't alter any hex-escaped characters in u.Path.
   307  func SetOpaque(u *url.URL) {
   308  	u.Opaque = "//" + u.Host + u.Path
   309  	if !has4860Fix {
   310  		u.Opaque = u.Scheme + ":" + u.Opaque
   311  	}
   312  }
   313  
   314  // Expand subsitutes any {encoded} strings in the URL passed in using
   315  // the map supplied.
   316  //
   317  // This calls SetOpaque to avoid encoding of the parameters in the URL path.
   318  func Expand(u *url.URL, expansions map[string]string) {
   319  	expanded, err := uritemplates.Expand(u.Path, expansions)
   320  	if err == nil {
   321  		u.Path = expanded
   322  		SetOpaque(u)
   323  	}
   324  }
   325  
   326  // CloseBody is used to close res.Body.
   327  // Prior to calling Close, it also tries to Read a small amount to see an EOF.
   328  // Not seeing an EOF can prevent HTTP Transports from reusing connections.
   329  func CloseBody(res *http.Response) {
   330  	if res == nil || res.Body == nil {
   331  		return
   332  	}
   333  	// Justification for 3 byte reads: two for up to "\r\n" after
   334  	// a JSON/XML document, and then 1 to see EOF if we haven't yet.
   335  	// TODO(bradfitz): detect Go 1.3+ and skip these reads.
   336  	// See https://codereview.appspot.com/58240043
   337  	// and https://codereview.appspot.com/49570044
   338  	buf := make([]byte, 1)
   339  	for i := 0; i < 3; i++ {
   340  		_, err := res.Body.Read(buf)
   341  		if err != nil {
   342  			break
   343  		}
   344  	}
   345  	res.Body.Close()
   346  
   347  }
   348  
   349  // VariantType returns the type name of the given variant.
   350  // If the map doesn't contain the named key or the value is not a []interface{}, "" is returned.
   351  // This is used to support "variant" APIs that can return one of a number of different types.
   352  func VariantType(t map[string]interface{}) string {
   353  	s, _ := t["type"].(string)
   354  	return s
   355  }
   356  
   357  // ConvertVariant uses the JSON encoder/decoder to fill in the struct 'dst' with the fields found in variant 'v'.
   358  // This is used to support "variant" APIs that can return one of a number of different types.
   359  // It reports whether the conversion was successful.
   360  func ConvertVariant(v map[string]interface{}, dst interface{}) bool {
   361  	var buf bytes.Buffer
   362  	err := json.NewEncoder(&buf).Encode(v)
   363  	if err != nil {
   364  		return false
   365  	}
   366  	return json.Unmarshal(buf.Bytes(), dst) == nil
   367  }