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 }