googleapi.go 15 KB

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