storage.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Package storage contains a Google Cloud Storage client.
  15. //
  16. // This package is experimental and may make backwards-incompatible changes.
  17. package storage // import "google.golang.org/cloud/storage"
  18. import (
  19. "crypto"
  20. "crypto/rand"
  21. "crypto/rsa"
  22. "crypto/sha256"
  23. "crypto/x509"
  24. "encoding/base64"
  25. "encoding/pem"
  26. "errors"
  27. "fmt"
  28. "io"
  29. "io/ioutil"
  30. "net/http"
  31. "net/url"
  32. "reflect"
  33. "strconv"
  34. "strings"
  35. "time"
  36. "unicode/utf8"
  37. "google.golang.org/cloud"
  38. "google.golang.org/cloud/internal/transport"
  39. "golang.org/x/net/context"
  40. "google.golang.org/api/googleapi"
  41. raw "google.golang.org/api/storage/v1"
  42. )
  43. var (
  44. ErrBucketNotExist = errors.New("storage: bucket doesn't exist")
  45. ErrObjectNotExist = errors.New("storage: object doesn't exist")
  46. )
  47. const userAgent = "gcloud-golang-storage/20151204"
  48. const (
  49. // ScopeFullControl grants permissions to manage your
  50. // data and permissions in Google Cloud Storage.
  51. ScopeFullControl = raw.DevstorageFullControlScope
  52. // ScopeReadOnly grants permissions to
  53. // view your data in Google Cloud Storage.
  54. ScopeReadOnly = raw.DevstorageReadOnlyScope
  55. // ScopeReadWrite grants permissions to manage your
  56. // data in Google Cloud Storage.
  57. ScopeReadWrite = raw.DevstorageReadWriteScope
  58. )
  59. // AdminClient is a client type for performing admin operations on a project's
  60. // buckets.
  61. type AdminClient struct {
  62. hc *http.Client
  63. raw *raw.Service
  64. projectID string
  65. }
  66. // NewAdminClient creates a new AdminClient for a given project.
  67. func NewAdminClient(ctx context.Context, projectID string, opts ...cloud.ClientOption) (*AdminClient, error) {
  68. c, err := NewClient(ctx, opts...)
  69. if err != nil {
  70. return nil, err
  71. }
  72. return &AdminClient{
  73. hc: c.hc,
  74. raw: c.raw,
  75. projectID: projectID,
  76. }, nil
  77. }
  78. // Close closes the AdminClient.
  79. func (c *AdminClient) Close() error {
  80. c.hc = nil
  81. return nil
  82. }
  83. // Create creates a Bucket in the project.
  84. // If attrs is nil the API defaults will be used.
  85. func (c *AdminClient) CreateBucket(ctx context.Context, bucketName string, attrs *BucketAttrs) error {
  86. var bkt *raw.Bucket
  87. if attrs != nil {
  88. bkt = attrs.toRawBucket()
  89. } else {
  90. bkt = &raw.Bucket{}
  91. }
  92. bkt.Name = bucketName
  93. req := c.raw.Buckets.Insert(c.projectID, bkt)
  94. _, err := req.Context(ctx).Do()
  95. return err
  96. }
  97. // Delete deletes a Bucket in the project.
  98. func (c *AdminClient) DeleteBucket(ctx context.Context, bucketName string) error {
  99. req := c.raw.Buckets.Delete(bucketName)
  100. return req.Context(ctx).Do()
  101. }
  102. // Client is a client for interacting with Google Cloud Storage.
  103. type Client struct {
  104. hc *http.Client
  105. raw *raw.Service
  106. }
  107. // NewClient creates a new Google Cloud Storage client.
  108. // The default scope is ScopeFullControl. To use a different scope, like ScopeReadOnly, use cloud.WithScopes.
  109. func NewClient(ctx context.Context, opts ...cloud.ClientOption) (*Client, error) {
  110. o := []cloud.ClientOption{
  111. cloud.WithScopes(ScopeFullControl),
  112. cloud.WithUserAgent(userAgent),
  113. }
  114. opts = append(o, opts...)
  115. hc, _, err := transport.NewHTTPClient(ctx, opts...)
  116. if err != nil {
  117. return nil, fmt.Errorf("dialing: %v", err)
  118. }
  119. rawService, err := raw.New(hc)
  120. if err != nil {
  121. return nil, fmt.Errorf("storage client: %v", err)
  122. }
  123. return &Client{
  124. hc: hc,
  125. raw: rawService,
  126. }, nil
  127. }
  128. // Close closes the Client.
  129. func (c *Client) Close() error {
  130. c.hc = nil
  131. return nil
  132. }
  133. // BucketHandle provides operations on a Google Cloud Storage bucket.
  134. // Use Client.Bucket to get a handle.
  135. type BucketHandle struct {
  136. acl *ACLHandle
  137. defaultObjectACL *ACLHandle
  138. c *Client
  139. name string
  140. }
  141. // Bucket returns a BucketHandle, which provides operations on the named bucket.
  142. // This call does not perform any network operations.
  143. //
  144. // name must contain only lowercase letters, numbers, dashes, underscores, and
  145. // dots. The full specification for valid bucket names can be found at:
  146. // https://cloud.google.com/storage/docs/bucket-naming
  147. func (c *Client) Bucket(name string) *BucketHandle {
  148. return &BucketHandle{
  149. c: c,
  150. name: name,
  151. acl: &ACLHandle{
  152. c: c,
  153. bucket: name,
  154. },
  155. defaultObjectACL: &ACLHandle{
  156. c: c,
  157. bucket: name,
  158. isDefault: true,
  159. },
  160. }
  161. }
  162. // ACL returns an ACLHandle, which provides access to the bucket's access control list.
  163. // This controls who can list, create or overwrite the objects in a bucket.
  164. // This call does not perform any network operations.
  165. func (c *BucketHandle) ACL() *ACLHandle {
  166. return c.acl
  167. }
  168. // DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs.
  169. // These ACLs are applied to newly created objects in this bucket that do not have a defined ACL.
  170. // This call does not perform any network operations.
  171. func (c *BucketHandle) DefaultObjectACL() *ACLHandle {
  172. return c.defaultObjectACL
  173. }
  174. // Object returns an ObjectHandle, which provides operations on the named object.
  175. // This call does not perform any network operations.
  176. //
  177. // name must consist entirely of valid UTF-8-encoded runes. The full specification
  178. // for valid object names can be found at:
  179. // https://cloud.google.com/storage/docs/bucket-naming
  180. func (b *BucketHandle) Object(name string) *ObjectHandle {
  181. return &ObjectHandle{
  182. c: b.c,
  183. bucket: b.name,
  184. object: name,
  185. acl: &ACLHandle{
  186. c: b.c,
  187. bucket: b.name,
  188. object: name,
  189. },
  190. }
  191. }
  192. // TODO(jbd): Add storage.buckets.list.
  193. // TODO(jbd): Add storage.buckets.update.
  194. // TODO(jbd): Add storage.objects.watch.
  195. // Attrs returns the metadata for the bucket.
  196. func (b *BucketHandle) Attrs(ctx context.Context) (*BucketAttrs, error) {
  197. resp, err := b.c.raw.Buckets.Get(b.name).Projection("full").Context(ctx).Do()
  198. if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
  199. return nil, ErrBucketNotExist
  200. }
  201. if err != nil {
  202. return nil, err
  203. }
  204. return newBucket(resp), nil
  205. }
  206. // List lists objects from the bucket. You can specify a query
  207. // to filter the results. If q is nil, no filtering is applied.
  208. func (b *BucketHandle) List(ctx context.Context, q *Query) (*ObjectList, error) {
  209. req := b.c.raw.Objects.List(b.name)
  210. req.Projection("full")
  211. if q != nil {
  212. req.Delimiter(q.Delimiter)
  213. req.Prefix(q.Prefix)
  214. req.Versions(q.Versions)
  215. req.PageToken(q.Cursor)
  216. if q.MaxResults > 0 {
  217. req.MaxResults(int64(q.MaxResults))
  218. }
  219. }
  220. resp, err := req.Context(ctx).Do()
  221. if err != nil {
  222. return nil, err
  223. }
  224. objects := &ObjectList{
  225. Results: make([]*ObjectAttrs, len(resp.Items)),
  226. Prefixes: make([]string, len(resp.Prefixes)),
  227. }
  228. for i, item := range resp.Items {
  229. objects.Results[i] = newObject(item)
  230. }
  231. for i, prefix := range resp.Prefixes {
  232. objects.Prefixes[i] = prefix
  233. }
  234. if resp.NextPageToken != "" {
  235. next := Query{}
  236. if q != nil {
  237. // keep the other filtering
  238. // criteria if there is a query
  239. next = *q
  240. }
  241. next.Cursor = resp.NextPageToken
  242. objects.Next = &next
  243. }
  244. return objects, nil
  245. }
  246. // SignedURLOptions allows you to restrict the access to the signed URL.
  247. type SignedURLOptions struct {
  248. // GoogleAccessID represents the authorizer of the signed URL generation.
  249. // It is typically the Google service account client email address from
  250. // the Google Developers Console in the form of "xxx@developer.gserviceaccount.com".
  251. // Required.
  252. GoogleAccessID string
  253. // PrivateKey is the Google service account private key. It is obtainable
  254. // from the Google Developers Console.
  255. // At https://console.developers.google.com/project/<your-project-id>/apiui/credential,
  256. // create a service account client ID or reuse one of your existing service account
  257. // credentials. Click on the "Generate new P12 key" to generate and download
  258. // a new private key. Once you download the P12 file, use the following command
  259. // to convert it into a PEM file.
  260. //
  261. // $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes
  262. //
  263. // Provide the contents of the PEM file as a byte slice.
  264. // Required.
  265. PrivateKey []byte
  266. // Method is the HTTP method to be used with the signed URL.
  267. // Signed URLs can be used with GET, HEAD, PUT, and DELETE requests.
  268. // Required.
  269. Method string
  270. // Expires is the expiration time on the signed URL. It must be
  271. // a datetime in the future.
  272. // Required.
  273. Expires time.Time
  274. // ContentType is the content type header the client must provide
  275. // to use the generated signed URL.
  276. // Optional.
  277. ContentType string
  278. // Headers is a list of extention headers the client must provide
  279. // in order to use the generated signed URL.
  280. // Optional.
  281. Headers []string
  282. // MD5 is the base64 encoded MD5 checksum of the file.
  283. // If provided, the client should provide the exact value on the request
  284. // header in order to use the signed URL.
  285. // Optional.
  286. MD5 []byte
  287. }
  288. // SignedURL returns a URL for the specified object. Signed URLs allow
  289. // the users access to a restricted resource for a limited time without having a
  290. // Google account or signing in. For more information about the signed
  291. // URLs, see https://cloud.google.com/storage/docs/accesscontrol#Signed-URLs.
  292. func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) {
  293. if opts == nil {
  294. return "", errors.New("storage: missing required SignedURLOptions")
  295. }
  296. if opts.GoogleAccessID == "" || opts.PrivateKey == nil {
  297. return "", errors.New("storage: missing required credentials to generate a signed URL")
  298. }
  299. if opts.Method == "" {
  300. return "", errors.New("storage: missing required method option")
  301. }
  302. if opts.Expires.IsZero() {
  303. return "", errors.New("storage: missing required expires option")
  304. }
  305. key, err := parseKey(opts.PrivateKey)
  306. if err != nil {
  307. return "", err
  308. }
  309. u := &url.URL{
  310. Path: fmt.Sprintf("/%s/%s", bucket, name),
  311. }
  312. h := sha256.New()
  313. fmt.Fprintf(h, "%s\n", opts.Method)
  314. fmt.Fprintf(h, "%s\n", opts.MD5)
  315. fmt.Fprintf(h, "%s\n", opts.ContentType)
  316. fmt.Fprintf(h, "%d\n", opts.Expires.Unix())
  317. fmt.Fprintf(h, "%s", strings.Join(opts.Headers, "\n"))
  318. fmt.Fprintf(h, "%s", u.String())
  319. b, err := rsa.SignPKCS1v15(
  320. rand.Reader,
  321. key,
  322. crypto.SHA256,
  323. h.Sum(nil),
  324. )
  325. if err != nil {
  326. return "", err
  327. }
  328. encoded := base64.StdEncoding.EncodeToString(b)
  329. u.Scheme = "https"
  330. u.Host = "storage.googleapis.com"
  331. q := u.Query()
  332. q.Set("GoogleAccessId", opts.GoogleAccessID)
  333. q.Set("Expires", fmt.Sprintf("%d", opts.Expires.Unix()))
  334. q.Set("Signature", string(encoded))
  335. u.RawQuery = q.Encode()
  336. return u.String(), nil
  337. }
  338. // ObjectHandle provides operations on an object in a Google Cloud Storage bucket.
  339. // Use BucketHandle.Object to get a handle.
  340. type ObjectHandle struct {
  341. c *Client
  342. bucket string
  343. object string
  344. acl *ACLHandle
  345. conds []Condition
  346. }
  347. // ACL provides access to the object's access control list.
  348. // This controls who can read and write this object.
  349. // This call does not perform any network operations.
  350. func (o *ObjectHandle) ACL() *ACLHandle {
  351. return o.acl
  352. }
  353. // WithConditions returns a copy of o using the provided conditions.
  354. func (o *ObjectHandle) WithConditions(conds ...Condition) *ObjectHandle {
  355. o2 := *o
  356. o2.conds = conds
  357. return &o2
  358. }
  359. // Attrs returns meta information about the object.
  360. // ErrObjectNotExist will be returned if the object is not found.
  361. func (o *ObjectHandle) Attrs(ctx context.Context) (*ObjectAttrs, error) {
  362. if !utf8.ValidString(o.object) {
  363. return nil, fmt.Errorf("storage: object name %q is not valid UTF-8", o.object)
  364. }
  365. call := o.c.raw.Objects.Get(o.bucket, o.object).Projection("full").Context(ctx)
  366. if err := applyConds("Attrs", o.conds, call); err != nil {
  367. return nil, err
  368. }
  369. obj, err := call.Do()
  370. if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
  371. return nil, ErrObjectNotExist
  372. }
  373. if err != nil {
  374. return nil, err
  375. }
  376. return newObject(obj), nil
  377. }
  378. // Update updates an object with the provided attributes.
  379. // All zero-value attributes are ignored.
  380. // ErrObjectNotExist will be returned if the object is not found.
  381. func (o *ObjectHandle) Update(ctx context.Context, attrs ObjectAttrs) (*ObjectAttrs, error) {
  382. if !utf8.ValidString(o.object) {
  383. return nil, fmt.Errorf("storage: object name %q is not valid UTF-8", o.object)
  384. }
  385. call := o.c.raw.Objects.Patch(o.bucket, o.object, attrs.toRawObject(o.bucket)).Projection("full").Context(ctx)
  386. if err := applyConds("Update", o.conds, call); err != nil {
  387. return nil, err
  388. }
  389. obj, err := call.Do()
  390. if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
  391. return nil, ErrObjectNotExist
  392. }
  393. if err != nil {
  394. return nil, err
  395. }
  396. return newObject(obj), nil
  397. }
  398. // Delete deletes the single specified object.
  399. func (o *ObjectHandle) Delete(ctx context.Context) error {
  400. if !utf8.ValidString(o.object) {
  401. return fmt.Errorf("storage: object name %q is not valid UTF-8", o.object)
  402. }
  403. call := o.c.raw.Objects.Delete(o.bucket, o.object).Context(ctx)
  404. if err := applyConds("Delete", o.conds, call); err != nil {
  405. return err
  406. }
  407. return call.Do()
  408. }
  409. // CopyTo copies the object to the given dst.
  410. // The copied object's attributes are overwritten by attrs if non-nil.
  411. func (o *ObjectHandle) CopyTo(ctx context.Context, dst *ObjectHandle, attrs *ObjectAttrs) (*ObjectAttrs, error) {
  412. // TODO(djd): move bucket/object name validation to a single helper func.
  413. if o.bucket == "" || dst.bucket == "" {
  414. return nil, errors.New("storage: the source and destination bucket names must both be non-empty")
  415. }
  416. if o.object == "" || dst.object == "" {
  417. return nil, errors.New("storage: the source and destination object names must both be non-empty")
  418. }
  419. if !utf8.ValidString(o.object) {
  420. return nil, fmt.Errorf("storage: object name %q is not valid UTF-8", o.object)
  421. }
  422. if !utf8.ValidString(dst.object) {
  423. return nil, fmt.Errorf("storage: dst name %q is not valid UTF-8", dst.object)
  424. }
  425. var rawObject *raw.Object
  426. if attrs != nil {
  427. attrs.Name = dst.object
  428. if attrs.ContentType == "" {
  429. return nil, errors.New("storage: attrs.ContentType must be non-empty")
  430. }
  431. rawObject = attrs.toRawObject(dst.bucket)
  432. }
  433. call := o.c.raw.Objects.Copy(o.bucket, o.object, dst.bucket, dst.object, rawObject).Projection("full").Context(ctx)
  434. if err := applyConds("CopyTo destination", dst.conds, call); err != nil {
  435. return nil, err
  436. }
  437. if err := applyConds("CopyTo source", toSourceConds(o.conds), call); err != nil {
  438. return nil, err
  439. }
  440. obj, err := call.Do()
  441. if err != nil {
  442. return nil, err
  443. }
  444. return newObject(obj), nil
  445. }
  446. // NewReader creates a new Reader to read the contents of the
  447. // object.
  448. // ErrObjectNotExist will be returned if the object is not found.
  449. func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) {
  450. return o.NewRangeReader(ctx, 0, -1)
  451. }
  452. // NewRangeReader reads part of an object, reading at most length bytes
  453. // starting at the given offset. If length is negative, the object is read
  454. // until the end.
  455. func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (*Reader, error) {
  456. if !utf8.ValidString(o.object) {
  457. return nil, fmt.Errorf("storage: object name %q is not valid UTF-8", o.object)
  458. }
  459. if offset < 0 {
  460. return nil, fmt.Errorf("storage: invalid offset %d < 0", offset)
  461. }
  462. u := &url.URL{
  463. Scheme: "https",
  464. Host: "storage.googleapis.com",
  465. Path: fmt.Sprintf("/%s/%s", o.bucket, o.object),
  466. }
  467. verb := "GET"
  468. if length == 0 {
  469. verb = "HEAD"
  470. }
  471. req, err := http.NewRequest(verb, u.String(), nil)
  472. if err != nil {
  473. return nil, err
  474. }
  475. if err := applyConds("NewReader", o.conds, objectsGetCall{req}); err != nil {
  476. return nil, err
  477. }
  478. if length < 0 {
  479. req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
  480. } else if length > 0 {
  481. req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+length-1))
  482. }
  483. res, err := o.c.hc.Do(req)
  484. if err != nil {
  485. return nil, err
  486. }
  487. if res.StatusCode == http.StatusNotFound {
  488. res.Body.Close()
  489. return nil, ErrObjectNotExist
  490. }
  491. if res.StatusCode < 200 || res.StatusCode > 299 {
  492. res.Body.Close()
  493. return nil, fmt.Errorf("storage: can't read object %v/%v, status code: %v", o.bucket, o.object, res.Status)
  494. }
  495. if offset > 0 && length != 0 && res.StatusCode != http.StatusPartialContent {
  496. res.Body.Close()
  497. return nil, errors.New("storage: partial request not satisfied")
  498. }
  499. clHeader := res.Header.Get("X-Goog-Stored-Content-Length")
  500. cl, err := strconv.ParseInt(clHeader, 10, 64)
  501. if err != nil {
  502. return nil, fmt.Errorf("storage: can't parse content length %q: %v", clHeader, err)
  503. }
  504. remain := res.ContentLength
  505. if remain < 0 {
  506. return nil, errors.New("storage: unknown content length")
  507. }
  508. body := res.Body
  509. if length == 0 {
  510. remain = 0
  511. body.Close()
  512. body = emptyBody
  513. }
  514. return &Reader{
  515. body: body,
  516. size: cl,
  517. remain: remain,
  518. contentType: res.Header.Get("Content-Type"),
  519. }, nil
  520. }
  521. var emptyBody = ioutil.NopCloser(strings.NewReader(""))
  522. // NewWriter returns a storage Writer that writes to the GCS object
  523. // associated with this ObjectHandle.
  524. //
  525. // A new object will be created if an object with this name already exists.
  526. // Otherwise any previous object with the same name will be replaced.
  527. // The object will not be available (and any previous object will remain)
  528. // until Close has been called.
  529. //
  530. // Attributes can be set on the object by modifying the returned Writer's
  531. // ObjectAttrs field before the first call to Write. If no ContentType
  532. // attribute is specified, the content type will be automatically sniffed
  533. // using net/http.DetectContentType.
  534. //
  535. // It is the caller's responsibility to call Close when writing is done.
  536. func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer {
  537. return &Writer{
  538. ctx: ctx,
  539. o: o,
  540. donec: make(chan struct{}),
  541. ObjectAttrs: ObjectAttrs{Name: o.object},
  542. }
  543. }
  544. // parseKey converts the binary contents of a private key file
  545. // to an *rsa.PrivateKey. It detects whether the private key is in a
  546. // PEM container or not. If so, it extracts the the private key
  547. // from PEM container before conversion. It only supports PEM
  548. // containers with no passphrase.
  549. func parseKey(key []byte) (*rsa.PrivateKey, error) {
  550. if block, _ := pem.Decode(key); block != nil {
  551. key = block.Bytes
  552. }
  553. parsedKey, err := x509.ParsePKCS8PrivateKey(key)
  554. if err != nil {
  555. parsedKey, err = x509.ParsePKCS1PrivateKey(key)
  556. if err != nil {
  557. return nil, err
  558. }
  559. }
  560. parsed, ok := parsedKey.(*rsa.PrivateKey)
  561. if !ok {
  562. return nil, errors.New("oauth2: private key is invalid")
  563. }
  564. return parsed, nil
  565. }
  566. // BucketAttrs represents the metadata for a Google Cloud Storage bucket.
  567. type BucketAttrs struct {
  568. // Name is the name of the bucket.
  569. Name string
  570. // ACL is the list of access control rules on the bucket.
  571. ACL []ACLRule
  572. // DefaultObjectACL is the list of access controls to
  573. // apply to new objects when no object ACL is provided.
  574. DefaultObjectACL []ACLRule
  575. // Location is the location of the bucket. It defaults to "US".
  576. Location string
  577. // MetaGeneration is the metadata generation of the bucket.
  578. MetaGeneration int64
  579. // StorageClass is the storage class of the bucket. This defines
  580. // how objects in the bucket are stored and determines the SLA
  581. // and the cost of storage. Typical values are "STANDARD" and
  582. // "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD".
  583. StorageClass string
  584. // Created is the creation time of the bucket.
  585. Created time.Time
  586. }
  587. func newBucket(b *raw.Bucket) *BucketAttrs {
  588. if b == nil {
  589. return nil
  590. }
  591. bucket := &BucketAttrs{
  592. Name: b.Name,
  593. Location: b.Location,
  594. MetaGeneration: b.Metageneration,
  595. StorageClass: b.StorageClass,
  596. Created: convertTime(b.TimeCreated),
  597. }
  598. acl := make([]ACLRule, len(b.Acl))
  599. for i, rule := range b.Acl {
  600. acl[i] = ACLRule{
  601. Entity: ACLEntity(rule.Entity),
  602. Role: ACLRole(rule.Role),
  603. }
  604. }
  605. bucket.ACL = acl
  606. objACL := make([]ACLRule, len(b.DefaultObjectAcl))
  607. for i, rule := range b.DefaultObjectAcl {
  608. objACL[i] = ACLRule{
  609. Entity: ACLEntity(rule.Entity),
  610. Role: ACLRole(rule.Role),
  611. }
  612. }
  613. bucket.DefaultObjectACL = objACL
  614. return bucket
  615. }
  616. func toRawObjectACL(oldACL []ACLRule) []*raw.ObjectAccessControl {
  617. var acl []*raw.ObjectAccessControl
  618. if len(oldACL) > 0 {
  619. acl = make([]*raw.ObjectAccessControl, len(oldACL))
  620. for i, rule := range oldACL {
  621. acl[i] = &raw.ObjectAccessControl{
  622. Entity: string(rule.Entity),
  623. Role: string(rule.Role),
  624. }
  625. }
  626. }
  627. return acl
  628. }
  629. // toRawBucket copies the editable attribute from b to the raw library's Bucket type.
  630. func (b *BucketAttrs) toRawBucket() *raw.Bucket {
  631. var acl []*raw.BucketAccessControl
  632. if len(b.ACL) > 0 {
  633. acl = make([]*raw.BucketAccessControl, len(b.ACL))
  634. for i, rule := range b.ACL {
  635. acl[i] = &raw.BucketAccessControl{
  636. Entity: string(rule.Entity),
  637. Role: string(rule.Role),
  638. }
  639. }
  640. }
  641. dACL := toRawObjectACL(b.DefaultObjectACL)
  642. return &raw.Bucket{
  643. Name: b.Name,
  644. DefaultObjectAcl: dACL,
  645. Location: b.Location,
  646. StorageClass: b.StorageClass,
  647. Acl: acl,
  648. }
  649. }
  650. // toRawObject copies the editable attributes from o to the raw library's Object type.
  651. func (o ObjectAttrs) toRawObject(bucket string) *raw.Object {
  652. acl := toRawObjectACL(o.ACL)
  653. return &raw.Object{
  654. Bucket: bucket,
  655. Name: o.Name,
  656. ContentType: o.ContentType,
  657. ContentEncoding: o.ContentEncoding,
  658. ContentLanguage: o.ContentLanguage,
  659. CacheControl: o.CacheControl,
  660. ContentDisposition: o.ContentDisposition,
  661. Acl: acl,
  662. Metadata: o.Metadata,
  663. }
  664. }
  665. // ObjectAttrs represents the metadata for a Google Cloud Storage (GCS) object.
  666. type ObjectAttrs struct {
  667. // Bucket is the name of the bucket containing this GCS object.
  668. // This field is read-only.
  669. Bucket string
  670. // Name is the name of the object within the bucket.
  671. // This field is read-only.
  672. Name string
  673. // ContentType is the MIME type of the object's content.
  674. ContentType string
  675. // ContentLanguage is the content language of the object's content.
  676. ContentLanguage string
  677. // CacheControl is the Cache-Control header to be sent in the response
  678. // headers when serving the object data.
  679. CacheControl string
  680. // ACL is the list of access control rules for the object.
  681. ACL []ACLRule
  682. // Owner is the owner of the object. This field is read-only.
  683. //
  684. // If non-zero, it is in the form of "user-<userId>".
  685. Owner string
  686. // Size is the length of the object's content. This field is read-only.
  687. Size int64
  688. // ContentEncoding is the encoding of the object's content.
  689. ContentEncoding string
  690. // ContentDisposition is the optional Content-Disposition header of the object
  691. // sent in the response headers.
  692. ContentDisposition string
  693. // MD5 is the MD5 hash of the object's content. This field is read-only.
  694. MD5 []byte
  695. // CRC32C is the CRC32 checksum of the object's content using
  696. // the Castagnoli93 polynomial. This field is read-only.
  697. CRC32C uint32
  698. // MediaLink is an URL to the object's content. This field is read-only.
  699. MediaLink string
  700. // Metadata represents user-provided metadata, in key/value pairs.
  701. // It can be nil if no metadata is provided.
  702. Metadata map[string]string
  703. // Generation is the generation number of the object's content.
  704. // This field is read-only.
  705. Generation int64
  706. // MetaGeneration is the version of the metadata for this
  707. // object at this generation. This field is used for preconditions
  708. // and for detecting changes in metadata. A metageneration number
  709. // is only meaningful in the context of a particular generation
  710. // of a particular object. This field is read-only.
  711. MetaGeneration int64
  712. // StorageClass is the storage class of the bucket.
  713. // This value defines how objects in the bucket are stored and
  714. // determines the SLA and the cost of storage. Typical values are
  715. // "STANDARD" and "DURABLE_REDUCED_AVAILABILITY".
  716. // It defaults to "STANDARD". This field is read-only.
  717. StorageClass string
  718. // Created is the time the object was created. This field is read-only.
  719. Created time.Time
  720. // Deleted is the time the object was deleted.
  721. // If not deleted, it is the zero value. This field is read-only.
  722. Deleted time.Time
  723. // Updated is the creation or modification time of the object.
  724. // For buckets with versioning enabled, changing an object's
  725. // metadata does not change this property. This field is read-only.
  726. Updated time.Time
  727. }
  728. // convertTime converts a time in RFC3339 format to time.Time.
  729. // If any error occurs in parsing, the zero-value time.Time is silently returned.
  730. func convertTime(t string) time.Time {
  731. var r time.Time
  732. if t != "" {
  733. r, _ = time.Parse(time.RFC3339, t)
  734. }
  735. return r
  736. }
  737. func newObject(o *raw.Object) *ObjectAttrs {
  738. if o == nil {
  739. return nil
  740. }
  741. acl := make([]ACLRule, len(o.Acl))
  742. for i, rule := range o.Acl {
  743. acl[i] = ACLRule{
  744. Entity: ACLEntity(rule.Entity),
  745. Role: ACLRole(rule.Role),
  746. }
  747. }
  748. owner := ""
  749. if o.Owner != nil {
  750. owner = o.Owner.Entity
  751. }
  752. md5, _ := base64.StdEncoding.DecodeString(o.Md5Hash)
  753. var crc32c uint32
  754. d, err := base64.StdEncoding.DecodeString(o.Crc32c)
  755. if err == nil && len(d) == 4 {
  756. crc32c = uint32(d[0])<<24 + uint32(d[1])<<16 + uint32(d[2])<<8 + uint32(d[3])
  757. }
  758. return &ObjectAttrs{
  759. Bucket: o.Bucket,
  760. Name: o.Name,
  761. ContentType: o.ContentType,
  762. ContentLanguage: o.ContentLanguage,
  763. CacheControl: o.CacheControl,
  764. ACL: acl,
  765. Owner: owner,
  766. ContentEncoding: o.ContentEncoding,
  767. Size: int64(o.Size),
  768. MD5: md5,
  769. CRC32C: crc32c,
  770. MediaLink: o.MediaLink,
  771. Metadata: o.Metadata,
  772. Generation: o.Generation,
  773. MetaGeneration: o.Metageneration,
  774. StorageClass: o.StorageClass,
  775. Created: convertTime(o.TimeCreated),
  776. Deleted: convertTime(o.TimeDeleted),
  777. Updated: convertTime(o.Updated),
  778. }
  779. }
  780. // Query represents a query to filter objects from a bucket.
  781. type Query struct {
  782. // Delimiter returns results in a directory-like fashion.
  783. // Results will contain only objects whose names, aside from the
  784. // prefix, do not contain delimiter. Objects whose names,
  785. // aside from the prefix, contain delimiter will have their name,
  786. // truncated after the delimiter, returned in prefixes.
  787. // Duplicate prefixes are omitted.
  788. // Optional.
  789. Delimiter string
  790. // Prefix is the prefix filter to query objects
  791. // whose names begin with this prefix.
  792. // Optional.
  793. Prefix string
  794. // Versions indicates whether multiple versions of the same
  795. // object will be included in the results.
  796. Versions bool
  797. // Cursor is a previously-returned page token
  798. // representing part of the larger set of results to view.
  799. // Optional.
  800. Cursor string
  801. // MaxResults is the maximum number of items plus prefixes
  802. // to return. As duplicate prefixes are omitted,
  803. // fewer total results may be returned than requested.
  804. // The default page limit is used if it is negative or zero.
  805. MaxResults int
  806. }
  807. // ObjectList represents a list of objects returned from a bucket List call.
  808. type ObjectList struct {
  809. // Results represent a list of object results.
  810. Results []*ObjectAttrs
  811. // Next is the continuation query to retrieve more
  812. // results with the same filtering criteria. If there
  813. // are no more results to retrieve, it is nil.
  814. Next *Query
  815. // Prefixes represents prefixes of objects
  816. // matching-but-not-listed up to and including
  817. // the requested delimiter.
  818. Prefixes []string
  819. }
  820. // contentTyper implements ContentTyper to enable an
  821. // io.ReadCloser to specify its MIME type.
  822. type contentTyper struct {
  823. io.Reader
  824. t string
  825. }
  826. func (c *contentTyper) ContentType() string {
  827. return c.t
  828. }
  829. // A Condition constrains methods to act on specific generations of
  830. // resources.
  831. //
  832. // Not all conditions or combinations of conditions are applicable to
  833. // all methods.
  834. type Condition interface {
  835. // method is the high-level ObjectHandle method name, for
  836. // error messages. call is the call object to modify.
  837. modifyCall(method string, call interface{}) error
  838. }
  839. // applyConds modifies the provided call using the conditions in conds.
  840. // call is something that quacks like a *raw.WhateverCall.
  841. func applyConds(method string, conds []Condition, call interface{}) error {
  842. for _, cond := range conds {
  843. if err := cond.modifyCall(method, call); err != nil {
  844. return err
  845. }
  846. }
  847. return nil
  848. }
  849. // toSourceConds returns a slice of Conditions derived from Conds that instead
  850. // function on the equivalent Source methods of a call.
  851. func toSourceConds(conds []Condition) []Condition {
  852. out := make([]Condition, 0, len(conds))
  853. for _, c := range conds {
  854. switch c := c.(type) {
  855. case genCond:
  856. var m string
  857. if strings.HasPrefix(c.method, "If") {
  858. m = "IfSource" + c.method[2:]
  859. } else {
  860. m = "Source" + c.method
  861. }
  862. out = append(out, genCond{method: m, val: c.val})
  863. default:
  864. // NOTE(djd): If the message from unsupportedCond becomes
  865. // confusing, we'll need to find a way for Conditions to
  866. // identify themselves.
  867. out = append(out, unsupportedCond{})
  868. }
  869. }
  870. return out
  871. }
  872. func Generation(gen int64) Condition { return genCond{"Generation", gen} }
  873. func IfGenerationMatch(gen int64) Condition { return genCond{"IfGenerationMatch", gen} }
  874. func IfGenerationNotMatch(gen int64) Condition { return genCond{"IfGenerationNotMatch", gen} }
  875. func IfMetaGenerationMatch(gen int64) Condition { return genCond{"IfMetagenerationMatch", gen} }
  876. func IfMetaGenerationNotMatch(gen int64) Condition { return genCond{"IfMetagenerationNotMatch", gen} }
  877. type genCond struct {
  878. method string
  879. val int64
  880. }
  881. func (g genCond) modifyCall(srcMethod string, call interface{}) error {
  882. rv := reflect.ValueOf(call)
  883. meth := rv.MethodByName(g.method)
  884. if !meth.IsValid() {
  885. return fmt.Errorf("%s: condition %s not supported", srcMethod, g.method)
  886. }
  887. meth.Call([]reflect.Value{reflect.ValueOf(g.val)})
  888. return nil
  889. }
  890. type unsupportedCond struct{}
  891. func (unsupportedCond) modifyCall(srcMethod string, call interface{}) error {
  892. return fmt.Errorf("%s: condition not supported", srcMethod)
  893. }
  894. func appendParam(req *http.Request, k, v string) {
  895. sep := ""
  896. if req.URL.RawQuery != "" {
  897. sep = "&"
  898. }
  899. req.URL.RawQuery += sep + url.QueryEscape(k) + "=" + url.QueryEscape(v)
  900. }
  901. // objectsGetCall wraps an *http.Request for an object fetch call, but adds the methods
  902. // that modifyCall searches for by name. (the same names as the raw, auto-generated API)
  903. type objectsGetCall struct{ req *http.Request }
  904. func (c objectsGetCall) Generation(gen int64) {
  905. appendParam(c.req, "generation", fmt.Sprint(gen))
  906. }
  907. func (c objectsGetCall) IfGenerationMatch(gen int64) {
  908. appendParam(c.req, "ifGenerationMatch", fmt.Sprint(gen))
  909. }
  910. func (c objectsGetCall) IfGenerationNotMatch(gen int64) {
  911. appendParam(c.req, "ifGenerationNotMatch", fmt.Sprint(gen))
  912. }
  913. func (c objectsGetCall) IfMetagenerationMatch(gen int64) {
  914. appendParam(c.req, "ifMetagenerationMatch", fmt.Sprint(gen))
  915. }
  916. func (c objectsGetCall) IfMetagenerationNotMatch(gen int64) {
  917. appendParam(c.req, "ifMetagenerationNotMatch", fmt.Sprint(gen))
  918. }