storage.go 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382
  1. // Copyright 2014 Google LLC
  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
  15. import (
  16. "bytes"
  17. "context"
  18. "crypto"
  19. "crypto/rand"
  20. "crypto/rsa"
  21. "crypto/sha256"
  22. "crypto/x509"
  23. "encoding/base64"
  24. "encoding/hex"
  25. "encoding/pem"
  26. "errors"
  27. "fmt"
  28. "net/http"
  29. "net/url"
  30. "os"
  31. "reflect"
  32. "regexp"
  33. "sort"
  34. "strconv"
  35. "strings"
  36. "time"
  37. "unicode/utf8"
  38. "cloud.google.com/go/internal/optional"
  39. "cloud.google.com/go/internal/trace"
  40. "cloud.google.com/go/storage/internal"
  41. "cloud.google.com/go/storage/internal/apiv2/storagepb"
  42. "github.com/googleapis/gax-go/v2"
  43. "golang.org/x/oauth2/google"
  44. "google.golang.org/api/googleapi"
  45. "google.golang.org/api/option"
  46. "google.golang.org/api/option/internaloption"
  47. raw "google.golang.org/api/storage/v1"
  48. "google.golang.org/api/transport"
  49. htransport "google.golang.org/api/transport/http"
  50. "google.golang.org/protobuf/proto"
  51. "google.golang.org/protobuf/reflect/protoreflect"
  52. "google.golang.org/protobuf/types/known/fieldmaskpb"
  53. "google.golang.org/protobuf/types/known/timestamppb"
  54. )
  55. // Methods which can be used in signed URLs.
  56. var signedURLMethods = map[string]bool{"DELETE": true, "GET": true, "HEAD": true, "POST": true, "PUT": true}
  57. var (
  58. // ErrBucketNotExist indicates that the bucket does not exist.
  59. ErrBucketNotExist = errors.New("storage: bucket doesn't exist")
  60. // ErrObjectNotExist indicates that the object does not exist.
  61. ErrObjectNotExist = errors.New("storage: object doesn't exist")
  62. // errMethodNotSupported indicates that the method called is not currently supported by the client.
  63. // TODO: Export this error when launching the transport-agnostic client.
  64. errMethodNotSupported = errors.New("storage: method is not currently supported")
  65. // errMethodNotValid indicates that given HTTP method is not valid.
  66. errMethodNotValid = fmt.Errorf("storage: HTTP method should be one of %v", reflect.ValueOf(signedURLMethods).MapKeys())
  67. )
  68. var userAgent = fmt.Sprintf("gcloud-golang-storage/%s", internal.Version)
  69. const (
  70. // ScopeFullControl grants permissions to manage your
  71. // data and permissions in Google Cloud Storage.
  72. ScopeFullControl = raw.DevstorageFullControlScope
  73. // ScopeReadOnly grants permissions to
  74. // view your data in Google Cloud Storage.
  75. ScopeReadOnly = raw.DevstorageReadOnlyScope
  76. // ScopeReadWrite grants permissions to manage your
  77. // data in Google Cloud Storage.
  78. ScopeReadWrite = raw.DevstorageReadWriteScope
  79. // aes256Algorithm is the AES256 encryption algorithm used with the
  80. // Customer-Supplied Encryption Keys feature.
  81. aes256Algorithm = "AES256"
  82. // defaultGen indicates the latest object generation by default,
  83. // using a negative value.
  84. defaultGen = int64(-1)
  85. )
  86. // TODO: remove this once header with invocation ID is applied to all methods.
  87. func setClientHeader(headers http.Header) {
  88. headers.Set("x-goog-api-client", xGoogDefaultHeader)
  89. }
  90. // Client is a client for interacting with Google Cloud Storage.
  91. //
  92. // Clients should be reused instead of created as needed.
  93. // The methods of Client are safe for concurrent use by multiple goroutines.
  94. type Client struct {
  95. hc *http.Client
  96. raw *raw.Service
  97. // Scheme describes the scheme under the current host.
  98. scheme string
  99. // xmlHost is the default host used for XML requests.
  100. xmlHost string
  101. // May be nil.
  102. creds *google.Credentials
  103. retry *retryConfig
  104. // tc is the transport-agnostic client implemented with either gRPC or HTTP.
  105. tc storageClient
  106. // useGRPC flags whether the client uses gRPC. This is needed while the
  107. // integration piece is only partially complete.
  108. // TODO: remove before merging to main.
  109. useGRPC bool
  110. }
  111. // NewClient creates a new Google Cloud Storage client using the HTTP transport.
  112. // The default scope is ScopeFullControl. To use a different scope, like
  113. // ScopeReadOnly, use option.WithScopes.
  114. //
  115. // Clients should be reused instead of created as needed. The methods of Client
  116. // are safe for concurrent use by multiple goroutines.
  117. //
  118. // You may configure the client by passing in options from the [google.golang.org/api/option]
  119. // package. You may also use options defined in this package, such as [WithJSONReads].
  120. func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
  121. var creds *google.Credentials
  122. // In general, it is recommended to use raw.NewService instead of htransport.NewClient
  123. // since raw.NewService configures the correct default endpoints when initializing the
  124. // internal http client. However, in our case, "NewRangeReader" in reader.go needs to
  125. // access the http client directly to make requests, so we create the client manually
  126. // here so it can be re-used by both reader.go and raw.NewService. This means we need to
  127. // manually configure the default endpoint options on the http client. Furthermore, we
  128. // need to account for STORAGE_EMULATOR_HOST override when setting the default endpoints.
  129. if host := os.Getenv("STORAGE_EMULATOR_HOST"); host == "" {
  130. // Prepend default options to avoid overriding options passed by the user.
  131. opts = append([]option.ClientOption{option.WithScopes(ScopeFullControl, "https://www.googleapis.com/auth/cloud-platform"), option.WithUserAgent(userAgent)}, opts...)
  132. opts = append(opts, internaloption.WithDefaultEndpointTemplate("https://storage.UNIVERSE_DOMAIN/storage/v1/"),
  133. internaloption.WithDefaultMTLSEndpoint("https://storage.mtls.googleapis.com/storage/v1/"),
  134. internaloption.WithDefaultUniverseDomain("googleapis.com"),
  135. )
  136. // Don't error out here. The user may have passed in their own HTTP
  137. // client which does not auth with ADC or other common conventions.
  138. c, err := transport.Creds(ctx, opts...)
  139. if err == nil {
  140. creds = c
  141. opts = append(opts, internaloption.WithCredentials(creds))
  142. }
  143. } else {
  144. var hostURL *url.URL
  145. if strings.Contains(host, "://") {
  146. h, err := url.Parse(host)
  147. if err != nil {
  148. return nil, err
  149. }
  150. hostURL = h
  151. } else {
  152. // Add scheme for user if not supplied in STORAGE_EMULATOR_HOST
  153. // URL is only parsed correctly if it has a scheme, so we build it ourselves
  154. hostURL = &url.URL{Scheme: "http", Host: host}
  155. }
  156. hostURL.Path = "storage/v1/"
  157. endpoint := hostURL.String()
  158. // Append the emulator host as default endpoint for the user
  159. opts = append([]option.ClientOption{
  160. option.WithoutAuthentication(),
  161. internaloption.SkipDialSettingsValidation(),
  162. internaloption.WithDefaultEndpoint(endpoint),
  163. internaloption.WithDefaultMTLSEndpoint(endpoint),
  164. }, opts...)
  165. }
  166. // htransport selects the correct endpoint among WithEndpoint (user override), WithDefaultEndpoint, and WithDefaultMTLSEndpoint.
  167. hc, ep, err := htransport.NewClient(ctx, opts...)
  168. if err != nil {
  169. return nil, fmt.Errorf("dialing: %w", err)
  170. }
  171. // RawService should be created with the chosen endpoint to take account of user override.
  172. rawService, err := raw.NewService(ctx, option.WithEndpoint(ep), option.WithHTTPClient(hc))
  173. if err != nil {
  174. return nil, fmt.Errorf("storage client: %w", err)
  175. }
  176. // Update xmlHost and scheme with the chosen endpoint.
  177. u, err := url.Parse(ep)
  178. if err != nil {
  179. return nil, fmt.Errorf("supplied endpoint %q is not valid: %w", ep, err)
  180. }
  181. tc, err := newHTTPStorageClient(ctx, withClientOptions(opts...))
  182. if err != nil {
  183. return nil, fmt.Errorf("storage: %w", err)
  184. }
  185. return &Client{
  186. hc: hc,
  187. raw: rawService,
  188. scheme: u.Scheme,
  189. xmlHost: u.Host,
  190. creds: creds,
  191. tc: tc,
  192. }, nil
  193. }
  194. // NewGRPCClient creates a new Storage client using the gRPC transport and API.
  195. // Client methods which have not been implemented in gRPC will return an error.
  196. // In particular, methods for Cloud Pub/Sub notifications are not supported.
  197. // Using a non-default universe domain is also not supported with the Storage
  198. // gRPC client.
  199. //
  200. // The storage gRPC API is still in preview and not yet publicly available.
  201. // If you would like to use the API, please first contact your GCP account rep to
  202. // request access. The API may be subject to breaking changes.
  203. //
  204. // Clients should be reused instead of created as needed. The methods of Client
  205. // are safe for concurrent use by multiple goroutines.
  206. //
  207. // You may configure the client by passing in options from the [google.golang.org/api/option]
  208. // package.
  209. func NewGRPCClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
  210. opts = append(defaultGRPCOptions(), opts...)
  211. tc, err := newGRPCStorageClient(ctx, withClientOptions(opts...))
  212. if err != nil {
  213. return nil, err
  214. }
  215. return &Client{tc: tc, useGRPC: true}, nil
  216. }
  217. // Close closes the Client.
  218. //
  219. // Close need not be called at program exit.
  220. func (c *Client) Close() error {
  221. // Set fields to nil so that subsequent uses will panic.
  222. c.hc = nil
  223. c.raw = nil
  224. c.creds = nil
  225. if c.tc != nil {
  226. return c.tc.Close()
  227. }
  228. return nil
  229. }
  230. // SigningScheme determines the API version to use when signing URLs.
  231. type SigningScheme int
  232. const (
  233. // SigningSchemeDefault is presently V2 and will change to V4 in the future.
  234. SigningSchemeDefault SigningScheme = iota
  235. // SigningSchemeV2 uses the V2 scheme to sign URLs.
  236. SigningSchemeV2
  237. // SigningSchemeV4 uses the V4 scheme to sign URLs.
  238. SigningSchemeV4
  239. )
  240. // URLStyle determines the style to use for the signed URL. PathStyle is the
  241. // default. All non-default options work with V4 scheme only. See
  242. // https://cloud.google.com/storage/docs/request-endpoints for details.
  243. type URLStyle interface {
  244. // host should return the host portion of the signed URL, not including
  245. // the scheme (e.g. storage.googleapis.com).
  246. host(hostname, bucket string) string
  247. // path should return the path portion of the signed URL, which may include
  248. // both the bucket and object name or only the object name depending on the
  249. // style.
  250. path(bucket, object string) string
  251. }
  252. type pathStyle struct{}
  253. type virtualHostedStyle struct{}
  254. type bucketBoundHostname struct {
  255. hostname string
  256. }
  257. func (s pathStyle) host(hostname, bucket string) string {
  258. if hostname != "" {
  259. return stripScheme(hostname)
  260. }
  261. if host := os.Getenv("STORAGE_EMULATOR_HOST"); host != "" {
  262. return stripScheme(host)
  263. }
  264. return "storage.googleapis.com"
  265. }
  266. func (s virtualHostedStyle) host(hostname, bucket string) string {
  267. if hostname != "" {
  268. return bucket + "." + stripScheme(hostname)
  269. }
  270. if host := os.Getenv("STORAGE_EMULATOR_HOST"); host != "" {
  271. return bucket + "." + stripScheme(host)
  272. }
  273. return bucket + ".storage.googleapis.com"
  274. }
  275. func (s bucketBoundHostname) host(_, bucket string) string {
  276. return s.hostname
  277. }
  278. func (s pathStyle) path(bucket, object string) string {
  279. p := bucket
  280. if object != "" {
  281. p += "/" + object
  282. }
  283. return p
  284. }
  285. func (s virtualHostedStyle) path(bucket, object string) string {
  286. return object
  287. }
  288. func (s bucketBoundHostname) path(bucket, object string) string {
  289. return object
  290. }
  291. // PathStyle is the default style, and will generate a URL of the form
  292. // "<host-name>/<bucket-name>/<object-name>". By default, <host-name> is
  293. // storage.googleapis.com, but setting an endpoint on the storage Client or
  294. // through STORAGE_EMULATOR_HOST overrides this. Setting Hostname on
  295. // SignedURLOptions or PostPolicyV4Options overrides everything else.
  296. func PathStyle() URLStyle {
  297. return pathStyle{}
  298. }
  299. // VirtualHostedStyle generates a URL relative to the bucket's virtual
  300. // hostname, e.g. "<bucket-name>.storage.googleapis.com/<object-name>".
  301. func VirtualHostedStyle() URLStyle {
  302. return virtualHostedStyle{}
  303. }
  304. // BucketBoundHostname generates a URL with a custom hostname tied to a
  305. // specific GCS bucket. The desired hostname should be passed in using the
  306. // hostname argument. Generated urls will be of the form
  307. // "<bucket-bound-hostname>/<object-name>". See
  308. // https://cloud.google.com/storage/docs/request-endpoints#cname and
  309. // https://cloud.google.com/load-balancing/docs/https/adding-backend-buckets-to-load-balancers
  310. // for details. Note that for CNAMEs, only HTTP is supported, so Insecure must
  311. // be set to true.
  312. func BucketBoundHostname(hostname string) URLStyle {
  313. return bucketBoundHostname{hostname: hostname}
  314. }
  315. // Strips the scheme from a host if it contains it
  316. func stripScheme(host string) string {
  317. if strings.Contains(host, "://") {
  318. host = strings.SplitN(host, "://", 2)[1]
  319. }
  320. return host
  321. }
  322. // SignedURLOptions allows you to restrict the access to the signed URL.
  323. type SignedURLOptions struct {
  324. // GoogleAccessID represents the authorizer of the signed URL generation.
  325. // It is typically the Google service account client email address from
  326. // the Google Developers Console in the form of "xxx@developer.gserviceaccount.com".
  327. // Required.
  328. GoogleAccessID string
  329. // PrivateKey is the Google service account private key. It is obtainable
  330. // from the Google Developers Console.
  331. // At https://console.developers.google.com/project/<your-project-id>/apiui/credential,
  332. // create a service account client ID or reuse one of your existing service account
  333. // credentials. Click on the "Generate new P12 key" to generate and download
  334. // a new private key. Once you download the P12 file, use the following command
  335. // to convert it into a PEM file.
  336. //
  337. // $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes
  338. //
  339. // Provide the contents of the PEM file as a byte slice.
  340. // Exactly one of PrivateKey or SignBytes must be non-nil.
  341. PrivateKey []byte
  342. // SignBytes is a function for implementing custom signing. For example, if
  343. // your application is running on Google App Engine, you can use
  344. // appengine's internal signing function:
  345. // ctx := appengine.NewContext(request)
  346. // acc, _ := appengine.ServiceAccount(ctx)
  347. // url, err := SignedURL("bucket", "object", &SignedURLOptions{
  348. // GoogleAccessID: acc,
  349. // SignBytes: func(b []byte) ([]byte, error) {
  350. // _, signedBytes, err := appengine.SignBytes(ctx, b)
  351. // return signedBytes, err
  352. // },
  353. // // etc.
  354. // })
  355. //
  356. // Exactly one of PrivateKey or SignBytes must be non-nil.
  357. SignBytes func([]byte) ([]byte, error)
  358. // Method is the HTTP method to be used with the signed URL.
  359. // Signed URLs can be used with GET, HEAD, PUT, and DELETE requests.
  360. // Required.
  361. Method string
  362. // Expires is the expiration time on the signed URL. It must be
  363. // a datetime in the future. For SigningSchemeV4, the expiration may be no
  364. // more than seven days in the future.
  365. // Required.
  366. Expires time.Time
  367. // ContentType is the content type header the client must provide
  368. // to use the generated signed URL.
  369. // Optional.
  370. ContentType string
  371. // Headers is a list of extension headers the client must provide
  372. // in order to use the generated signed URL. Each must be a string of the
  373. // form "key:values", with multiple values separated by a semicolon.
  374. // Optional.
  375. Headers []string
  376. // QueryParameters is a map of additional query parameters. When
  377. // SigningScheme is V4, this is used in computing the signature, and the
  378. // client must use the same query parameters when using the generated signed
  379. // URL.
  380. // Optional.
  381. QueryParameters url.Values
  382. // MD5 is the base64 encoded MD5 checksum of the file.
  383. // If provided, the client should provide the exact value on the request
  384. // header in order to use the signed URL.
  385. // Optional.
  386. MD5 string
  387. // Style provides options for the type of URL to use. Options are
  388. // PathStyle (default), BucketBoundHostname, and VirtualHostedStyle. See
  389. // https://cloud.google.com/storage/docs/request-endpoints for details.
  390. // Only supported for V4 signing.
  391. // Optional.
  392. Style URLStyle
  393. // Insecure determines whether the signed URL should use HTTPS (default) or
  394. // HTTP.
  395. // Only supported for V4 signing.
  396. // Optional.
  397. Insecure bool
  398. // Scheme determines the version of URL signing to use. Default is
  399. // SigningSchemeV2.
  400. Scheme SigningScheme
  401. // Hostname sets the host of the signed URL. This field overrides any
  402. // endpoint set on a storage Client or through STORAGE_EMULATOR_HOST.
  403. // Only compatible with PathStyle and VirtualHostedStyle URLStyles.
  404. // Optional.
  405. Hostname string
  406. }
  407. func (opts *SignedURLOptions) clone() *SignedURLOptions {
  408. return &SignedURLOptions{
  409. GoogleAccessID: opts.GoogleAccessID,
  410. SignBytes: opts.SignBytes,
  411. PrivateKey: opts.PrivateKey,
  412. Method: opts.Method,
  413. Expires: opts.Expires,
  414. ContentType: opts.ContentType,
  415. Headers: opts.Headers,
  416. QueryParameters: opts.QueryParameters,
  417. MD5: opts.MD5,
  418. Style: opts.Style,
  419. Insecure: opts.Insecure,
  420. Scheme: opts.Scheme,
  421. Hostname: opts.Hostname,
  422. }
  423. }
  424. var (
  425. tabRegex = regexp.MustCompile(`[\t]+`)
  426. // I was tempted to call this spacex. :)
  427. spaceRegex = regexp.MustCompile(` +`)
  428. canonicalHeaderRegexp = regexp.MustCompile(`(?i)^(x-goog-[^:]+):(.*)?$`)
  429. excludedCanonicalHeaders = map[string]bool{
  430. "x-goog-encryption-key": true,
  431. "x-goog-encryption-key-sha256": true,
  432. }
  433. )
  434. // v2SanitizeHeaders applies the specifications for canonical extension headers at
  435. // https://cloud.google.com/storage/docs/access-control/signed-urls-v2#about-canonical-extension-headers
  436. func v2SanitizeHeaders(hdrs []string) []string {
  437. headerMap := map[string][]string{}
  438. for _, hdr := range hdrs {
  439. // No leading or trailing whitespaces.
  440. sanitizedHeader := strings.TrimSpace(hdr)
  441. var header, value string
  442. // Only keep canonical headers, discard any others.
  443. headerMatches := canonicalHeaderRegexp.FindStringSubmatch(sanitizedHeader)
  444. if len(headerMatches) == 0 {
  445. continue
  446. }
  447. header = headerMatches[1]
  448. value = headerMatches[2]
  449. header = strings.ToLower(strings.TrimSpace(header))
  450. value = strings.TrimSpace(value)
  451. if excludedCanonicalHeaders[header] {
  452. // Do not keep any deliberately excluded canonical headers when signing.
  453. continue
  454. }
  455. if len(value) > 0 {
  456. // Remove duplicate headers by appending the values of duplicates
  457. // in their order of appearance.
  458. headerMap[header] = append(headerMap[header], value)
  459. }
  460. }
  461. var sanitizedHeaders []string
  462. for header, values := range headerMap {
  463. // There should be no spaces around the colon separating the header name
  464. // from the header value or around the values themselves. The values
  465. // should be separated by commas.
  466. //
  467. // NOTE: The semantics for headers without a value are not clear.
  468. // However from specifications these should be edge-cases anyway and we
  469. // should assume that there will be no canonical headers using empty
  470. // values. Any such headers are discarded at the regexp stage above.
  471. sanitizedHeaders = append(sanitizedHeaders, fmt.Sprintf("%s:%s", header, strings.Join(values, ",")))
  472. }
  473. sort.Strings(sanitizedHeaders)
  474. return sanitizedHeaders
  475. }
  476. // v4SanitizeHeaders applies the specifications for canonical extension headers
  477. // at https://cloud.google.com/storage/docs/authentication/canonical-requests#about-headers.
  478. //
  479. // V4 does a couple things differently from V2:
  480. // - Headers get sorted by key, instead of by key:value. We do this in
  481. // signedURLV4.
  482. // - There's no canonical regexp: we simply split headers on :.
  483. // - We don't exclude canonical headers.
  484. // - We replace leading and trailing spaces in header values, like v2, but also
  485. // all intermediate space duplicates get stripped. That is, there's only ever
  486. // a single consecutive space.
  487. func v4SanitizeHeaders(hdrs []string) []string {
  488. headerMap := map[string][]string{}
  489. for _, hdr := range hdrs {
  490. // No leading or trailing whitespaces.
  491. sanitizedHeader := strings.TrimSpace(hdr)
  492. var key, value string
  493. headerMatches := strings.SplitN(sanitizedHeader, ":", 2)
  494. if len(headerMatches) < 2 {
  495. continue
  496. }
  497. key = headerMatches[0]
  498. value = headerMatches[1]
  499. key = strings.ToLower(strings.TrimSpace(key))
  500. value = strings.TrimSpace(value)
  501. value = string(spaceRegex.ReplaceAll([]byte(value), []byte(" ")))
  502. value = string(tabRegex.ReplaceAll([]byte(value), []byte("\t")))
  503. if len(value) > 0 {
  504. // Remove duplicate headers by appending the values of duplicates
  505. // in their order of appearance.
  506. headerMap[key] = append(headerMap[key], value)
  507. }
  508. }
  509. var sanitizedHeaders []string
  510. for header, values := range headerMap {
  511. // There should be no spaces around the colon separating the header name
  512. // from the header value or around the values themselves. The values
  513. // should be separated by commas.
  514. //
  515. // NOTE: The semantics for headers without a value are not clear.
  516. // However from specifications these should be edge-cases anyway and we
  517. // should assume that there will be no canonical headers using empty
  518. // values. Any such headers are discarded at the regexp stage above.
  519. sanitizedHeaders = append(sanitizedHeaders, fmt.Sprintf("%s:%s", header, strings.Join(values, ",")))
  520. }
  521. return sanitizedHeaders
  522. }
  523. // SignedURL returns a URL for the specified object. Signed URLs allow anyone
  524. // access to a restricted resource for a limited time without needing a
  525. // Google account or signing in. For more information about signed URLs, see
  526. // https://cloud.google.com/storage/docs/accesscontrol#signed_urls_query_string_authentication
  527. // If initializing a Storage Client, instead use the Bucket.SignedURL method
  528. // which uses the Client's credentials to handle authentication.
  529. func SignedURL(bucket, object string, opts *SignedURLOptions) (string, error) {
  530. now := utcNow()
  531. if err := validateOptions(opts, now); err != nil {
  532. return "", err
  533. }
  534. switch opts.Scheme {
  535. case SigningSchemeV2:
  536. opts.Headers = v2SanitizeHeaders(opts.Headers)
  537. return signedURLV2(bucket, object, opts)
  538. case SigningSchemeV4:
  539. opts.Headers = v4SanitizeHeaders(opts.Headers)
  540. return signedURLV4(bucket, object, opts, now)
  541. default: // SigningSchemeDefault
  542. opts.Headers = v2SanitizeHeaders(opts.Headers)
  543. return signedURLV2(bucket, object, opts)
  544. }
  545. }
  546. func validateOptions(opts *SignedURLOptions, now time.Time) error {
  547. if opts == nil {
  548. return errors.New("storage: missing required SignedURLOptions")
  549. }
  550. if opts.GoogleAccessID == "" {
  551. return errors.New("storage: missing required GoogleAccessID")
  552. }
  553. if (opts.PrivateKey == nil) == (opts.SignBytes == nil) {
  554. return errors.New("storage: exactly one of PrivateKey or SignedBytes must be set")
  555. }
  556. opts.Method = strings.ToUpper(opts.Method)
  557. if _, ok := signedURLMethods[opts.Method]; !ok {
  558. return errMethodNotValid
  559. }
  560. if opts.Expires.IsZero() {
  561. return errors.New("storage: missing required expires option")
  562. }
  563. if opts.MD5 != "" {
  564. md5, err := base64.StdEncoding.DecodeString(opts.MD5)
  565. if err != nil || len(md5) != 16 {
  566. return errors.New("storage: invalid MD5 checksum")
  567. }
  568. }
  569. if opts.Style == nil {
  570. opts.Style = PathStyle()
  571. }
  572. if _, ok := opts.Style.(pathStyle); !ok && opts.Scheme == SigningSchemeV2 {
  573. return errors.New("storage: only path-style URLs are permitted with SigningSchemeV2")
  574. }
  575. if opts.Scheme == SigningSchemeV4 {
  576. cutoff := now.Add(604801 * time.Second) // 7 days + 1 second
  577. if !opts.Expires.Before(cutoff) {
  578. return errors.New("storage: expires must be within seven days from now")
  579. }
  580. }
  581. return nil
  582. }
  583. const (
  584. iso8601 = "20060102T150405Z"
  585. yearMonthDay = "20060102"
  586. )
  587. // utcNow returns the current time in UTC and is a variable to allow for
  588. // reassignment in tests to provide deterministic signed URL values.
  589. var utcNow = func() time.Time {
  590. return time.Now().UTC()
  591. }
  592. // extractHeaderNames takes in a series of key:value headers and returns the
  593. // header names only.
  594. func extractHeaderNames(kvs []string) []string {
  595. var res []string
  596. for _, header := range kvs {
  597. nameValue := strings.SplitN(header, ":", 2)
  598. res = append(res, nameValue[0])
  599. }
  600. return res
  601. }
  602. // pathEncodeV4 creates an encoded string that matches the v4 signature spec.
  603. // Following the spec precisely is necessary in order to ensure that the URL
  604. // and signing string are correctly formed, and Go's url.PathEncode and
  605. // url.QueryEncode don't generate an exact match without some additional logic.
  606. func pathEncodeV4(path string) string {
  607. segments := strings.Split(path, "/")
  608. var encodedSegments []string
  609. for _, s := range segments {
  610. encodedSegments = append(encodedSegments, url.QueryEscape(s))
  611. }
  612. encodedStr := strings.Join(encodedSegments, "/")
  613. encodedStr = strings.Replace(encodedStr, "+", "%20", -1)
  614. return encodedStr
  615. }
  616. // signedURLV4 creates a signed URL using the sigV4 algorithm.
  617. func signedURLV4(bucket, name string, opts *SignedURLOptions, now time.Time) (string, error) {
  618. buf := &bytes.Buffer{}
  619. fmt.Fprintf(buf, "%s\n", opts.Method)
  620. u := &url.URL{Path: opts.Style.path(bucket, name)}
  621. u.RawPath = pathEncodeV4(u.Path)
  622. // Note: we have to add a / here because GCS does so auto-magically, despite
  623. // our encoding not doing so (and we have to exactly match their
  624. // canonical query).
  625. fmt.Fprintf(buf, "/%s\n", u.RawPath)
  626. headerNames := append(extractHeaderNames(opts.Headers), "host")
  627. if opts.ContentType != "" {
  628. headerNames = append(headerNames, "content-type")
  629. }
  630. if opts.MD5 != "" {
  631. headerNames = append(headerNames, "content-md5")
  632. }
  633. sort.Strings(headerNames)
  634. signedHeaders := strings.Join(headerNames, ";")
  635. timestamp := now.Format(iso8601)
  636. credentialScope := fmt.Sprintf("%s/auto/storage/goog4_request", now.Format(yearMonthDay))
  637. canonicalQueryString := url.Values{
  638. "X-Goog-Algorithm": {"GOOG4-RSA-SHA256"},
  639. "X-Goog-Credential": {fmt.Sprintf("%s/%s", opts.GoogleAccessID, credentialScope)},
  640. "X-Goog-Date": {timestamp},
  641. "X-Goog-Expires": {fmt.Sprintf("%d", int(opts.Expires.Sub(now).Seconds()))},
  642. "X-Goog-SignedHeaders": {signedHeaders},
  643. }
  644. // Add user-supplied query parameters to the canonical query string. For V4,
  645. // it's necessary to include these.
  646. for k, v := range opts.QueryParameters {
  647. canonicalQueryString[k] = append(canonicalQueryString[k], v...)
  648. }
  649. // url.Values.Encode escaping is correct, except that a space must be replaced
  650. // by `%20` rather than `+`.
  651. escapedQuery := strings.Replace(canonicalQueryString.Encode(), "+", "%20", -1)
  652. fmt.Fprintf(buf, "%s\n", escapedQuery)
  653. // Fill in the hostname based on the desired URL style.
  654. u.Host = opts.Style.host(opts.Hostname, bucket)
  655. // Fill in the URL scheme.
  656. if opts.Insecure {
  657. u.Scheme = "http"
  658. } else {
  659. u.Scheme = "https"
  660. }
  661. var headersWithValue []string
  662. headersWithValue = append(headersWithValue, "host:"+u.Hostname())
  663. headersWithValue = append(headersWithValue, opts.Headers...)
  664. if opts.ContentType != "" {
  665. headersWithValue = append(headersWithValue, "content-type:"+opts.ContentType)
  666. }
  667. if opts.MD5 != "" {
  668. headersWithValue = append(headersWithValue, "content-md5:"+opts.MD5)
  669. }
  670. // Trim extra whitespace from headers and replace with a single space.
  671. var trimmedHeaders []string
  672. for _, h := range headersWithValue {
  673. trimmedHeaders = append(trimmedHeaders, strings.Join(strings.Fields(h), " "))
  674. }
  675. canonicalHeaders := strings.Join(sortHeadersByKey(trimmedHeaders), "\n")
  676. fmt.Fprintf(buf, "%s\n\n", canonicalHeaders)
  677. fmt.Fprintf(buf, "%s\n", signedHeaders)
  678. // If the user provides a value for X-Goog-Content-SHA256, we must use
  679. // that value in the request string. If not, we use UNSIGNED-PAYLOAD.
  680. sha256Header := false
  681. for _, h := range trimmedHeaders {
  682. if strings.HasPrefix(strings.ToLower(h), "x-goog-content-sha256") && strings.Contains(h, ":") {
  683. sha256Header = true
  684. fmt.Fprintf(buf, "%s", strings.SplitN(h, ":", 2)[1])
  685. break
  686. }
  687. }
  688. if !sha256Header {
  689. fmt.Fprint(buf, "UNSIGNED-PAYLOAD")
  690. }
  691. sum := sha256.Sum256(buf.Bytes())
  692. hexDigest := hex.EncodeToString(sum[:])
  693. signBuf := &bytes.Buffer{}
  694. fmt.Fprint(signBuf, "GOOG4-RSA-SHA256\n")
  695. fmt.Fprintf(signBuf, "%s\n", timestamp)
  696. fmt.Fprintf(signBuf, "%s\n", credentialScope)
  697. fmt.Fprintf(signBuf, "%s", hexDigest)
  698. signBytes := opts.SignBytes
  699. if opts.PrivateKey != nil {
  700. key, err := parseKey(opts.PrivateKey)
  701. if err != nil {
  702. return "", err
  703. }
  704. signBytes = func(b []byte) ([]byte, error) {
  705. sum := sha256.Sum256(b)
  706. return rsa.SignPKCS1v15(
  707. rand.Reader,
  708. key,
  709. crypto.SHA256,
  710. sum[:],
  711. )
  712. }
  713. }
  714. b, err := signBytes(signBuf.Bytes())
  715. if err != nil {
  716. return "", err
  717. }
  718. signature := hex.EncodeToString(b)
  719. canonicalQueryString.Set("X-Goog-Signature", string(signature))
  720. u.RawQuery = canonicalQueryString.Encode()
  721. return u.String(), nil
  722. }
  723. // takes a list of headerKey:headervalue1,headervalue2,etc and sorts by header
  724. // key.
  725. func sortHeadersByKey(hdrs []string) []string {
  726. headersMap := map[string]string{}
  727. var headersKeys []string
  728. for _, h := range hdrs {
  729. parts := strings.SplitN(h, ":", 2)
  730. k := parts[0]
  731. v := parts[1]
  732. headersMap[k] = v
  733. headersKeys = append(headersKeys, k)
  734. }
  735. sort.Strings(headersKeys)
  736. var sorted []string
  737. for _, k := range headersKeys {
  738. v := headersMap[k]
  739. sorted = append(sorted, fmt.Sprintf("%s:%s", k, v))
  740. }
  741. return sorted
  742. }
  743. func signedURLV2(bucket, name string, opts *SignedURLOptions) (string, error) {
  744. signBytes := opts.SignBytes
  745. if opts.PrivateKey != nil {
  746. key, err := parseKey(opts.PrivateKey)
  747. if err != nil {
  748. return "", err
  749. }
  750. signBytes = func(b []byte) ([]byte, error) {
  751. sum := sha256.Sum256(b)
  752. return rsa.SignPKCS1v15(
  753. rand.Reader,
  754. key,
  755. crypto.SHA256,
  756. sum[:],
  757. )
  758. }
  759. }
  760. u := &url.URL{
  761. Path: fmt.Sprintf("/%s/%s", bucket, name),
  762. }
  763. buf := &bytes.Buffer{}
  764. fmt.Fprintf(buf, "%s\n", opts.Method)
  765. fmt.Fprintf(buf, "%s\n", opts.MD5)
  766. fmt.Fprintf(buf, "%s\n", opts.ContentType)
  767. fmt.Fprintf(buf, "%d\n", opts.Expires.Unix())
  768. if len(opts.Headers) > 0 {
  769. fmt.Fprintf(buf, "%s\n", strings.Join(opts.Headers, "\n"))
  770. }
  771. fmt.Fprintf(buf, "%s", u.String())
  772. b, err := signBytes(buf.Bytes())
  773. if err != nil {
  774. return "", err
  775. }
  776. encoded := base64.StdEncoding.EncodeToString(b)
  777. u.Scheme = "https"
  778. u.Host = PathStyle().host(opts.Hostname, bucket)
  779. q := u.Query()
  780. q.Set("GoogleAccessId", opts.GoogleAccessID)
  781. q.Set("Expires", fmt.Sprintf("%d", opts.Expires.Unix()))
  782. q.Set("Signature", string(encoded))
  783. u.RawQuery = q.Encode()
  784. return u.String(), nil
  785. }
  786. // ObjectHandle provides operations on an object in a Google Cloud Storage bucket.
  787. // Use BucketHandle.Object to get a handle.
  788. type ObjectHandle struct {
  789. c *Client
  790. bucket string
  791. object string
  792. acl ACLHandle
  793. gen int64 // a negative value indicates latest
  794. conds *Conditions
  795. encryptionKey []byte // AES-256 key
  796. userProject string // for requester-pays buckets
  797. readCompressed bool // Accept-Encoding: gzip
  798. retry *retryConfig
  799. overrideRetention *bool
  800. }
  801. // ACL provides access to the object's access control list.
  802. // This controls who can read and write this object.
  803. // This call does not perform any network operations.
  804. func (o *ObjectHandle) ACL() *ACLHandle {
  805. return &o.acl
  806. }
  807. // Generation returns a new ObjectHandle that operates on a specific generation
  808. // of the object.
  809. // By default, the handle operates on the latest generation. Not
  810. // all operations work when given a specific generation; check the API
  811. // endpoints at https://cloud.google.com/storage/docs/json_api/ for details.
  812. func (o *ObjectHandle) Generation(gen int64) *ObjectHandle {
  813. o2 := *o
  814. o2.gen = gen
  815. return &o2
  816. }
  817. // If returns a new ObjectHandle that applies a set of preconditions.
  818. // Preconditions already set on the ObjectHandle are ignored. The supplied
  819. // Conditions must have at least one field set to a non-default value;
  820. // otherwise an error will be returned from any operation on the ObjectHandle.
  821. // Operations on the new handle will return an error if the preconditions are not
  822. // satisfied. See https://cloud.google.com/storage/docs/generations-preconditions
  823. // for more details.
  824. func (o *ObjectHandle) If(conds Conditions) *ObjectHandle {
  825. o2 := *o
  826. o2.conds = &conds
  827. return &o2
  828. }
  829. // Key returns a new ObjectHandle that uses the supplied encryption
  830. // key to encrypt and decrypt the object's contents.
  831. //
  832. // Encryption key must be a 32-byte AES-256 key.
  833. // See https://cloud.google.com/storage/docs/encryption for details.
  834. func (o *ObjectHandle) Key(encryptionKey []byte) *ObjectHandle {
  835. o2 := *o
  836. o2.encryptionKey = encryptionKey
  837. return &o2
  838. }
  839. // Attrs returns meta information about the object.
  840. // ErrObjectNotExist will be returned if the object is not found.
  841. func (o *ObjectHandle) Attrs(ctx context.Context) (attrs *ObjectAttrs, err error) {
  842. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Attrs")
  843. defer func() { trace.EndSpan(ctx, err) }()
  844. if err := o.validate(); err != nil {
  845. return nil, err
  846. }
  847. opts := makeStorageOpts(true, o.retry, o.userProject)
  848. return o.c.tc.GetObject(ctx, o.bucket, o.object, o.gen, o.encryptionKey, o.conds, opts...)
  849. }
  850. // Update updates an object with the provided attributes. See
  851. // ObjectAttrsToUpdate docs for details on treatment of zero values.
  852. // ErrObjectNotExist will be returned if the object is not found.
  853. func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (oa *ObjectAttrs, err error) {
  854. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Update")
  855. defer func() { trace.EndSpan(ctx, err) }()
  856. if err := o.validate(); err != nil {
  857. return nil, err
  858. }
  859. isIdempotent := o.conds != nil && o.conds.MetagenerationMatch != 0
  860. opts := makeStorageOpts(isIdempotent, o.retry, o.userProject)
  861. return o.c.tc.UpdateObject(ctx,
  862. &updateObjectParams{
  863. bucket: o.bucket,
  864. object: o.object,
  865. uattrs: &uattrs,
  866. gen: o.gen,
  867. encryptionKey: o.encryptionKey,
  868. conds: o.conds,
  869. overrideRetention: o.overrideRetention}, opts...)
  870. }
  871. // BucketName returns the name of the bucket.
  872. func (o *ObjectHandle) BucketName() string {
  873. return o.bucket
  874. }
  875. // ObjectName returns the name of the object.
  876. func (o *ObjectHandle) ObjectName() string {
  877. return o.object
  878. }
  879. // ObjectAttrsToUpdate is used to update the attributes of an object.
  880. // Only fields set to non-nil values will be updated.
  881. // For all fields except CustomTime and Retention, set the field to its zero
  882. // value to delete it. CustomTime cannot be deleted or changed to an earlier
  883. // time once set. Retention can be deleted (only if the Mode is Unlocked) by
  884. // setting it to an empty value (not nil).
  885. //
  886. // For example, to change ContentType and delete ContentEncoding, Metadata and
  887. // Retention, use:
  888. //
  889. // ObjectAttrsToUpdate{
  890. // ContentType: "text/html",
  891. // ContentEncoding: "",
  892. // Metadata: map[string]string{},
  893. // Retention: &ObjectRetention{},
  894. // }
  895. type ObjectAttrsToUpdate struct {
  896. EventBasedHold optional.Bool
  897. TemporaryHold optional.Bool
  898. ContentType optional.String
  899. ContentLanguage optional.String
  900. ContentEncoding optional.String
  901. ContentDisposition optional.String
  902. CacheControl optional.String
  903. CustomTime time.Time // Cannot be deleted or backdated from its current value.
  904. Metadata map[string]string // Set to map[string]string{} to delete.
  905. ACL []ACLRule
  906. // If not empty, applies a predefined set of access controls. ACL must be nil.
  907. // See https://cloud.google.com/storage/docs/json_api/v1/objects/patch.
  908. PredefinedACL string
  909. // Retention contains the retention configuration for this object.
  910. // Operations other than setting the retention for the first time or
  911. // extending the RetainUntil time on the object retention must be done
  912. // on an ObjectHandle with OverrideUnlockedRetention set to true.
  913. Retention *ObjectRetention
  914. }
  915. // Delete deletes the single specified object.
  916. func (o *ObjectHandle) Delete(ctx context.Context) error {
  917. if err := o.validate(); err != nil {
  918. return err
  919. }
  920. // Delete is idempotent if GenerationMatch or Generation have been passed in.
  921. // The default generation is negative to get the latest version of the object.
  922. isIdempotent := (o.conds != nil && o.conds.GenerationMatch != 0) || o.gen >= 0
  923. opts := makeStorageOpts(isIdempotent, o.retry, o.userProject)
  924. return o.c.tc.DeleteObject(ctx, o.bucket, o.object, o.gen, o.conds, opts...)
  925. }
  926. // ReadCompressed when true causes the read to happen without decompressing.
  927. func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle {
  928. o2 := *o
  929. o2.readCompressed = compressed
  930. return &o2
  931. }
  932. // OverrideUnlockedRetention provides an option for overriding an Unlocked
  933. // Retention policy. This must be set to true in order to change a policy
  934. // from Unlocked to Locked, to set it to null, or to reduce its
  935. // RetainUntil attribute. It is not required for setting the ObjectRetention for
  936. // the first time nor for extending the RetainUntil time.
  937. func (o *ObjectHandle) OverrideUnlockedRetention(override bool) *ObjectHandle {
  938. o2 := *o
  939. o2.overrideRetention = &override
  940. return &o2
  941. }
  942. // NewWriter returns a storage Writer that writes to the GCS object
  943. // associated with this ObjectHandle.
  944. //
  945. // A new object will be created unless an object with this name already exists.
  946. // Otherwise any previous object with the same name will be replaced.
  947. // The object will not be available (and any previous object will remain)
  948. // until Close has been called.
  949. //
  950. // Attributes can be set on the object by modifying the returned Writer's
  951. // ObjectAttrs field before the first call to Write. If no ContentType
  952. // attribute is specified, the content type will be automatically sniffed
  953. // using net/http.DetectContentType.
  954. //
  955. // Note that each Writer allocates an internal buffer of size Writer.ChunkSize.
  956. // See the ChunkSize docs for more information.
  957. //
  958. // It is the caller's responsibility to call Close when writing is done. To
  959. // stop writing without saving the data, cancel the context.
  960. func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer {
  961. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Writer")
  962. return &Writer{
  963. ctx: ctx,
  964. o: o,
  965. donec: make(chan struct{}),
  966. ObjectAttrs: ObjectAttrs{Name: o.object},
  967. ChunkSize: googleapi.DefaultUploadChunkSize,
  968. }
  969. }
  970. func (o *ObjectHandle) validate() error {
  971. if o.bucket == "" {
  972. return errors.New("storage: bucket name is empty")
  973. }
  974. if o.object == "" {
  975. return errors.New("storage: object name is empty")
  976. }
  977. if !utf8.ValidString(o.object) {
  978. return fmt.Errorf("storage: object name %q is not valid UTF-8", o.object)
  979. }
  980. // Names . and .. are not valid; see https://cloud.google.com/storage/docs/objects#naming
  981. if o.object == "." || o.object == ".." {
  982. return fmt.Errorf("storage: object name %q is not valid", o.object)
  983. }
  984. return nil
  985. }
  986. // parseKey converts the binary contents of a private key file to an
  987. // *rsa.PrivateKey. It detects whether the private key is in a PEM container or
  988. // not. If so, it extracts the private key from PEM container before
  989. // conversion. It only supports PEM containers with no passphrase.
  990. func parseKey(key []byte) (*rsa.PrivateKey, error) {
  991. if block, _ := pem.Decode(key); block != nil {
  992. key = block.Bytes
  993. }
  994. parsedKey, err := x509.ParsePKCS8PrivateKey(key)
  995. if err != nil {
  996. parsedKey, err = x509.ParsePKCS1PrivateKey(key)
  997. if err != nil {
  998. return nil, err
  999. }
  1000. }
  1001. parsed, ok := parsedKey.(*rsa.PrivateKey)
  1002. if !ok {
  1003. return nil, errors.New("oauth2: private key is invalid")
  1004. }
  1005. return parsed, nil
  1006. }
  1007. // toRawObject copies the editable attributes from o to the raw library's Object type.
  1008. func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object {
  1009. var ret string
  1010. if !o.RetentionExpirationTime.IsZero() {
  1011. ret = o.RetentionExpirationTime.Format(time.RFC3339)
  1012. }
  1013. var ct string
  1014. if !o.CustomTime.IsZero() {
  1015. ct = o.CustomTime.Format(time.RFC3339)
  1016. }
  1017. return &raw.Object{
  1018. Bucket: bucket,
  1019. Name: o.Name,
  1020. EventBasedHold: o.EventBasedHold,
  1021. TemporaryHold: o.TemporaryHold,
  1022. RetentionExpirationTime: ret,
  1023. ContentType: o.ContentType,
  1024. ContentEncoding: o.ContentEncoding,
  1025. ContentLanguage: o.ContentLanguage,
  1026. CacheControl: o.CacheControl,
  1027. ContentDisposition: o.ContentDisposition,
  1028. StorageClass: o.StorageClass,
  1029. Acl: toRawObjectACL(o.ACL),
  1030. Metadata: o.Metadata,
  1031. CustomTime: ct,
  1032. Retention: o.Retention.toRawObjectRetention(),
  1033. }
  1034. }
  1035. // toProtoObject copies the editable attributes from o to the proto library's Object type.
  1036. func (o *ObjectAttrs) toProtoObject(b string) *storagepb.Object {
  1037. // For now, there are only globally unique buckets, and "_" is the alias
  1038. // project ID for such buckets. If the bucket is not provided, like in the
  1039. // destination ObjectAttrs of a Copy, do not attempt to format it.
  1040. if b != "" {
  1041. b = bucketResourceName(globalProjectAlias, b)
  1042. }
  1043. return &storagepb.Object{
  1044. Bucket: b,
  1045. Name: o.Name,
  1046. EventBasedHold: proto.Bool(o.EventBasedHold),
  1047. TemporaryHold: o.TemporaryHold,
  1048. ContentType: o.ContentType,
  1049. ContentEncoding: o.ContentEncoding,
  1050. ContentLanguage: o.ContentLanguage,
  1051. CacheControl: o.CacheControl,
  1052. ContentDisposition: o.ContentDisposition,
  1053. StorageClass: o.StorageClass,
  1054. Acl: toProtoObjectACL(o.ACL),
  1055. Metadata: o.Metadata,
  1056. CreateTime: toProtoTimestamp(o.Created),
  1057. CustomTime: toProtoTimestamp(o.CustomTime),
  1058. DeleteTime: toProtoTimestamp(o.Deleted),
  1059. RetentionExpireTime: toProtoTimestamp(o.RetentionExpirationTime),
  1060. UpdateTime: toProtoTimestamp(o.Updated),
  1061. KmsKey: o.KMSKeyName,
  1062. Generation: o.Generation,
  1063. Size: o.Size,
  1064. }
  1065. }
  1066. // toProtoObject copies the attributes to update from uattrs to the proto library's Object type.
  1067. func (uattrs *ObjectAttrsToUpdate) toProtoObject(bucket, object string) *storagepb.Object {
  1068. o := &storagepb.Object{
  1069. Name: object,
  1070. Bucket: bucket,
  1071. }
  1072. if uattrs == nil {
  1073. return o
  1074. }
  1075. if uattrs.EventBasedHold != nil {
  1076. o.EventBasedHold = proto.Bool(optional.ToBool(uattrs.EventBasedHold))
  1077. }
  1078. if uattrs.TemporaryHold != nil {
  1079. o.TemporaryHold = optional.ToBool(uattrs.TemporaryHold)
  1080. }
  1081. if uattrs.ContentType != nil {
  1082. o.ContentType = optional.ToString(uattrs.ContentType)
  1083. }
  1084. if uattrs.ContentLanguage != nil {
  1085. o.ContentLanguage = optional.ToString(uattrs.ContentLanguage)
  1086. }
  1087. if uattrs.ContentEncoding != nil {
  1088. o.ContentEncoding = optional.ToString(uattrs.ContentEncoding)
  1089. }
  1090. if uattrs.ContentDisposition != nil {
  1091. o.ContentDisposition = optional.ToString(uattrs.ContentDisposition)
  1092. }
  1093. if uattrs.CacheControl != nil {
  1094. o.CacheControl = optional.ToString(uattrs.CacheControl)
  1095. }
  1096. if !uattrs.CustomTime.IsZero() {
  1097. o.CustomTime = toProtoTimestamp(uattrs.CustomTime)
  1098. }
  1099. if uattrs.ACL != nil {
  1100. o.Acl = toProtoObjectACL(uattrs.ACL)
  1101. }
  1102. o.Metadata = uattrs.Metadata
  1103. return o
  1104. }
  1105. // ObjectAttrs represents the metadata for a Google Cloud Storage (GCS) object.
  1106. type ObjectAttrs struct {
  1107. // Bucket is the name of the bucket containing this GCS object.
  1108. // This field is read-only.
  1109. Bucket string
  1110. // Name is the name of the object within the bucket.
  1111. // This field is read-only.
  1112. Name string
  1113. // ContentType is the MIME type of the object's content.
  1114. ContentType string
  1115. // ContentLanguage is the content language of the object's content.
  1116. ContentLanguage string
  1117. // CacheControl is the Cache-Control header to be sent in the response
  1118. // headers when serving the object data.
  1119. CacheControl string
  1120. // EventBasedHold specifies whether an object is under event-based hold. New
  1121. // objects created in a bucket whose DefaultEventBasedHold is set will
  1122. // default to that value.
  1123. EventBasedHold bool
  1124. // TemporaryHold specifies whether an object is under temporary hold. While
  1125. // this flag is set to true, the object is protected against deletion and
  1126. // overwrites.
  1127. TemporaryHold bool
  1128. // RetentionExpirationTime is a server-determined value that specifies the
  1129. // earliest time that the object's retention period expires.
  1130. // This is a read-only field.
  1131. RetentionExpirationTime time.Time
  1132. // ACL is the list of access control rules for the object.
  1133. ACL []ACLRule
  1134. // If not empty, applies a predefined set of access controls. It should be set
  1135. // only when writing, copying or composing an object. When copying or composing,
  1136. // it acts as the destinationPredefinedAcl parameter.
  1137. // PredefinedACL is always empty for ObjectAttrs returned from the service.
  1138. // See https://cloud.google.com/storage/docs/json_api/v1/objects/insert
  1139. // for valid values.
  1140. PredefinedACL string
  1141. // Owner is the owner of the object. This field is read-only.
  1142. //
  1143. // If non-zero, it is in the form of "user-<userId>".
  1144. Owner string
  1145. // Size is the length of the object's content. This field is read-only.
  1146. Size int64
  1147. // ContentEncoding is the encoding of the object's content.
  1148. ContentEncoding string
  1149. // ContentDisposition is the optional Content-Disposition header of the object
  1150. // sent in the response headers.
  1151. ContentDisposition string
  1152. // MD5 is the MD5 hash of the object's content. This field is read-only,
  1153. // except when used from a Writer. If set on a Writer, the uploaded
  1154. // data is rejected if its MD5 hash does not match this field.
  1155. MD5 []byte
  1156. // CRC32C is the CRC32 checksum of the object's content using the Castagnoli93
  1157. // polynomial. This field is read-only, except when used from a Writer or
  1158. // Composer. In those cases, if the SendCRC32C field in the Writer or Composer
  1159. // is set to is true, the uploaded data is rejected if its CRC32C hash does
  1160. // not match this field.
  1161. //
  1162. // Note: For a Writer, SendCRC32C must be set to true BEFORE the first call to
  1163. // Writer.Write() in order to send the checksum.
  1164. CRC32C uint32
  1165. // MediaLink is an URL to the object's content. This field is read-only.
  1166. MediaLink string
  1167. // Metadata represents user-provided metadata, in key/value pairs.
  1168. // It can be nil if no metadata is provided.
  1169. //
  1170. // For object downloads using Reader, metadata keys are sent as headers.
  1171. // Therefore, avoid setting metadata keys using characters that are not valid
  1172. // for headers. See https://www.rfc-editor.org/rfc/rfc7230#section-3.2.6.
  1173. Metadata map[string]string
  1174. // Generation is the generation number of the object's content.
  1175. // This field is read-only.
  1176. Generation int64
  1177. // Metageneration is the version of the metadata for this
  1178. // object at this generation. This field is used for preconditions
  1179. // and for detecting changes in metadata. A metageneration number
  1180. // is only meaningful in the context of a particular generation
  1181. // of a particular object. This field is read-only.
  1182. Metageneration int64
  1183. // StorageClass is the storage class of the object. This defines
  1184. // how objects are stored and determines the SLA and the cost of storage.
  1185. // Typical values are "STANDARD", "NEARLINE", "COLDLINE" and "ARCHIVE".
  1186. // Defaults to "STANDARD".
  1187. // See https://cloud.google.com/storage/docs/storage-classes for all
  1188. // valid values.
  1189. StorageClass string
  1190. // Created is the time the object was created. This field is read-only.
  1191. Created time.Time
  1192. // Deleted is the time the object was deleted.
  1193. // If not deleted, it is the zero value. This field is read-only.
  1194. Deleted time.Time
  1195. // Updated is the creation or modification time of the object.
  1196. // For buckets with versioning enabled, changing an object's
  1197. // metadata does not change this property. This field is read-only.
  1198. Updated time.Time
  1199. // CustomerKeySHA256 is the base64-encoded SHA-256 hash of the
  1200. // customer-supplied encryption key for the object. It is empty if there is
  1201. // no customer-supplied encryption key.
  1202. // See // https://cloud.google.com/storage/docs/encryption for more about
  1203. // encryption in Google Cloud Storage.
  1204. CustomerKeySHA256 string
  1205. // Cloud KMS key name, in the form
  1206. // projects/P/locations/L/keyRings/R/cryptoKeys/K, used to encrypt this object,
  1207. // if the object is encrypted by such a key.
  1208. //
  1209. // Providing both a KMSKeyName and a customer-supplied encryption key (via
  1210. // ObjectHandle.Key) will result in an error when writing an object.
  1211. KMSKeyName string
  1212. // Prefix is set only for ObjectAttrs which represent synthetic "directory
  1213. // entries" when iterating over buckets using Query.Delimiter. See
  1214. // ObjectIterator.Next. When set, no other fields in ObjectAttrs will be
  1215. // populated.
  1216. Prefix string
  1217. // Etag is the HTTP/1.1 Entity tag for the object.
  1218. // This field is read-only.
  1219. Etag string
  1220. // A user-specified timestamp which can be applied to an object. This is
  1221. // typically set in order to use the CustomTimeBefore and DaysSinceCustomTime
  1222. // LifecycleConditions to manage object lifecycles.
  1223. //
  1224. // CustomTime cannot be removed once set on an object. It can be updated to a
  1225. // later value but not to an earlier one. For more information see
  1226. // https://cloud.google.com/storage/docs/metadata#custom-time .
  1227. CustomTime time.Time
  1228. // ComponentCount is the number of objects contained within a composite object.
  1229. // For non-composite objects, the value will be zero.
  1230. // This field is read-only.
  1231. ComponentCount int64
  1232. // Retention contains the retention configuration for this object.
  1233. // ObjectRetention cannot be configured or reported through the gRPC API.
  1234. Retention *ObjectRetention
  1235. }
  1236. // ObjectRetention contains the retention configuration for this object.
  1237. type ObjectRetention struct {
  1238. // Mode is the retention policy's mode on this object. Valid values are
  1239. // "Locked" and "Unlocked".
  1240. // Locked retention policies cannot be changed. Unlocked policies require an
  1241. // override to change.
  1242. Mode string
  1243. // RetainUntil is the time this object will be retained until.
  1244. RetainUntil time.Time
  1245. }
  1246. func (r *ObjectRetention) toRawObjectRetention() *raw.ObjectRetention {
  1247. if r == nil {
  1248. return nil
  1249. }
  1250. return &raw.ObjectRetention{
  1251. Mode: r.Mode,
  1252. RetainUntilTime: r.RetainUntil.Format(time.RFC3339),
  1253. }
  1254. }
  1255. func toObjectRetention(r *raw.ObjectRetention) *ObjectRetention {
  1256. if r == nil {
  1257. return nil
  1258. }
  1259. return &ObjectRetention{
  1260. Mode: r.Mode,
  1261. RetainUntil: convertTime(r.RetainUntilTime),
  1262. }
  1263. }
  1264. // convertTime converts a time in RFC3339 format to time.Time.
  1265. // If any error occurs in parsing, the zero-value time.Time is silently returned.
  1266. func convertTime(t string) time.Time {
  1267. var r time.Time
  1268. if t != "" {
  1269. r, _ = time.Parse(time.RFC3339, t)
  1270. }
  1271. return r
  1272. }
  1273. func convertProtoTime(t *timestamppb.Timestamp) time.Time {
  1274. var r time.Time
  1275. if t != nil {
  1276. r = t.AsTime()
  1277. }
  1278. return r
  1279. }
  1280. func toProtoTimestamp(t time.Time) *timestamppb.Timestamp {
  1281. if t.IsZero() {
  1282. return nil
  1283. }
  1284. return timestamppb.New(t)
  1285. }
  1286. func newObject(o *raw.Object) *ObjectAttrs {
  1287. if o == nil {
  1288. return nil
  1289. }
  1290. owner := ""
  1291. if o.Owner != nil {
  1292. owner = o.Owner.Entity
  1293. }
  1294. md5, _ := base64.StdEncoding.DecodeString(o.Md5Hash)
  1295. crc32c, _ := decodeUint32(o.Crc32c)
  1296. var sha256 string
  1297. if o.CustomerEncryption != nil {
  1298. sha256 = o.CustomerEncryption.KeySha256
  1299. }
  1300. return &ObjectAttrs{
  1301. Bucket: o.Bucket,
  1302. Name: o.Name,
  1303. ContentType: o.ContentType,
  1304. ContentLanguage: o.ContentLanguage,
  1305. CacheControl: o.CacheControl,
  1306. EventBasedHold: o.EventBasedHold,
  1307. TemporaryHold: o.TemporaryHold,
  1308. RetentionExpirationTime: convertTime(o.RetentionExpirationTime),
  1309. ACL: toObjectACLRules(o.Acl),
  1310. Owner: owner,
  1311. ContentEncoding: o.ContentEncoding,
  1312. ContentDisposition: o.ContentDisposition,
  1313. Size: int64(o.Size),
  1314. MD5: md5,
  1315. CRC32C: crc32c,
  1316. MediaLink: o.MediaLink,
  1317. Metadata: o.Metadata,
  1318. Generation: o.Generation,
  1319. Metageneration: o.Metageneration,
  1320. StorageClass: o.StorageClass,
  1321. CustomerKeySHA256: sha256,
  1322. KMSKeyName: o.KmsKeyName,
  1323. Created: convertTime(o.TimeCreated),
  1324. Deleted: convertTime(o.TimeDeleted),
  1325. Updated: convertTime(o.Updated),
  1326. Etag: o.Etag,
  1327. CustomTime: convertTime(o.CustomTime),
  1328. ComponentCount: o.ComponentCount,
  1329. Retention: toObjectRetention(o.Retention),
  1330. }
  1331. }
  1332. func newObjectFromProto(o *storagepb.Object) *ObjectAttrs {
  1333. if o == nil {
  1334. return nil
  1335. }
  1336. return &ObjectAttrs{
  1337. Bucket: parseBucketName(o.Bucket),
  1338. Name: o.Name,
  1339. ContentType: o.ContentType,
  1340. ContentLanguage: o.ContentLanguage,
  1341. CacheControl: o.CacheControl,
  1342. EventBasedHold: o.GetEventBasedHold(),
  1343. TemporaryHold: o.TemporaryHold,
  1344. RetentionExpirationTime: convertProtoTime(o.GetRetentionExpireTime()),
  1345. ACL: toObjectACLRulesFromProto(o.GetAcl()),
  1346. Owner: o.GetOwner().GetEntity(),
  1347. ContentEncoding: o.ContentEncoding,
  1348. ContentDisposition: o.ContentDisposition,
  1349. Size: int64(o.Size),
  1350. MD5: o.GetChecksums().GetMd5Hash(),
  1351. CRC32C: o.GetChecksums().GetCrc32C(),
  1352. Metadata: o.Metadata,
  1353. Generation: o.Generation,
  1354. Metageneration: o.Metageneration,
  1355. StorageClass: o.StorageClass,
  1356. // CustomerKeySHA256 needs to be presented as base64 encoded, but the response from gRPC is not.
  1357. CustomerKeySHA256: base64.StdEncoding.EncodeToString(o.GetCustomerEncryption().GetKeySha256Bytes()),
  1358. KMSKeyName: o.GetKmsKey(),
  1359. Created: convertProtoTime(o.GetCreateTime()),
  1360. Deleted: convertProtoTime(o.GetDeleteTime()),
  1361. Updated: convertProtoTime(o.GetUpdateTime()),
  1362. CustomTime: convertProtoTime(o.GetCustomTime()),
  1363. ComponentCount: int64(o.ComponentCount),
  1364. }
  1365. }
  1366. // Decode a uint32 encoded in Base64 in big-endian byte order.
  1367. func decodeUint32(b64 string) (uint32, error) {
  1368. d, err := base64.StdEncoding.DecodeString(b64)
  1369. if err != nil {
  1370. return 0, err
  1371. }
  1372. if len(d) != 4 {
  1373. return 0, fmt.Errorf("storage: %q does not encode a 32-bit value", d)
  1374. }
  1375. return uint32(d[0])<<24 + uint32(d[1])<<16 + uint32(d[2])<<8 + uint32(d[3]), nil
  1376. }
  1377. // Encode a uint32 as Base64 in big-endian byte order.
  1378. func encodeUint32(u uint32) string {
  1379. b := []byte{byte(u >> 24), byte(u >> 16), byte(u >> 8), byte(u)}
  1380. return base64.StdEncoding.EncodeToString(b)
  1381. }
  1382. // Projection is enumerated type for Query.Projection.
  1383. type Projection int
  1384. const (
  1385. // ProjectionDefault returns all fields of objects.
  1386. ProjectionDefault Projection = iota
  1387. // ProjectionFull returns all fields of objects.
  1388. ProjectionFull
  1389. // ProjectionNoACL returns all fields of objects except for Owner and ACL.
  1390. ProjectionNoACL
  1391. )
  1392. func (p Projection) String() string {
  1393. switch p {
  1394. case ProjectionFull:
  1395. return "full"
  1396. case ProjectionNoACL:
  1397. return "noAcl"
  1398. default:
  1399. return ""
  1400. }
  1401. }
  1402. // Query represents a query to filter objects from a bucket.
  1403. type Query struct {
  1404. // Delimiter returns results in a directory-like fashion.
  1405. // Results will contain only objects whose names, aside from the
  1406. // prefix, do not contain delimiter. Objects whose names,
  1407. // aside from the prefix, contain delimiter will have their name,
  1408. // truncated after the delimiter, returned in prefixes.
  1409. // Duplicate prefixes are omitted.
  1410. // Must be set to / when used with the MatchGlob parameter to filter results
  1411. // in a directory-like mode.
  1412. // Optional.
  1413. Delimiter string
  1414. // Prefix is the prefix filter to query objects
  1415. // whose names begin with this prefix.
  1416. // Optional.
  1417. Prefix string
  1418. // Versions indicates whether multiple versions of the same
  1419. // object will be included in the results.
  1420. Versions bool
  1421. // attrSelection is used to select only specific fields to be returned by
  1422. // the query. It is set by the user calling SetAttrSelection. These
  1423. // are used by toFieldMask and toFieldSelection for gRPC and HTTP/JSON
  1424. // clients respectively.
  1425. attrSelection []string
  1426. // StartOffset is used to filter results to objects whose names are
  1427. // lexicographically equal to or after startOffset. If endOffset is also set,
  1428. // the objects listed will have names between startOffset (inclusive) and
  1429. // endOffset (exclusive).
  1430. StartOffset string
  1431. // EndOffset is used to filter results to objects whose names are
  1432. // lexicographically before endOffset. If startOffset is also set, the objects
  1433. // listed will have names between startOffset (inclusive) and endOffset (exclusive).
  1434. EndOffset string
  1435. // Projection defines the set of properties to return. It will default to ProjectionFull,
  1436. // which returns all properties. Passing ProjectionNoACL will omit Owner and ACL,
  1437. // which may improve performance when listing many objects.
  1438. Projection Projection
  1439. // IncludeTrailingDelimiter controls how objects which end in a single
  1440. // instance of Delimiter (for example, if Query.Delimiter = "/" and the
  1441. // object name is "foo/bar/") are included in the results. By default, these
  1442. // objects only show up as prefixes. If IncludeTrailingDelimiter is set to
  1443. // true, they will also be included as objects and their metadata will be
  1444. // populated in the returned ObjectAttrs.
  1445. IncludeTrailingDelimiter bool
  1446. // MatchGlob is a glob pattern used to filter results (for example, foo*bar). See
  1447. // https://cloud.google.com/storage/docs/json_api/v1/objects/list#list-object-glob
  1448. // for syntax details. When Delimiter is set in conjunction with MatchGlob,
  1449. // it must be set to /.
  1450. MatchGlob string
  1451. // IncludeFoldersAsPrefixes includes Folders and Managed Folders in the set of
  1452. // prefixes returned by the query. Only applicable if Delimiter is set to /.
  1453. // IncludeFoldersAsPrefixes is not yet implemented in the gRPC API.
  1454. IncludeFoldersAsPrefixes bool
  1455. }
  1456. // attrToFieldMap maps the field names of ObjectAttrs to the underlying field
  1457. // names in the API call. Only the ObjectAttrs field names are visible to users
  1458. // because they are already part of the public API of the package.
  1459. var attrToFieldMap = map[string]string{
  1460. "Bucket": "bucket",
  1461. "Name": "name",
  1462. "ContentType": "contentType",
  1463. "ContentLanguage": "contentLanguage",
  1464. "CacheControl": "cacheControl",
  1465. "EventBasedHold": "eventBasedHold",
  1466. "TemporaryHold": "temporaryHold",
  1467. "RetentionExpirationTime": "retentionExpirationTime",
  1468. "ACL": "acl",
  1469. "Owner": "owner",
  1470. "ContentEncoding": "contentEncoding",
  1471. "ContentDisposition": "contentDisposition",
  1472. "Size": "size",
  1473. "MD5": "md5Hash",
  1474. "CRC32C": "crc32c",
  1475. "MediaLink": "mediaLink",
  1476. "Metadata": "metadata",
  1477. "Generation": "generation",
  1478. "Metageneration": "metageneration",
  1479. "StorageClass": "storageClass",
  1480. "CustomerKeySHA256": "customerEncryption",
  1481. "KMSKeyName": "kmsKeyName",
  1482. "Created": "timeCreated",
  1483. "Deleted": "timeDeleted",
  1484. "Updated": "updated",
  1485. "Etag": "etag",
  1486. "CustomTime": "customTime",
  1487. "ComponentCount": "componentCount",
  1488. "Retention": "retention",
  1489. }
  1490. // attrToProtoFieldMap maps the field names of ObjectAttrs to the underlying field
  1491. // names in the protobuf Object message.
  1492. var attrToProtoFieldMap = map[string]string{
  1493. "Name": "name",
  1494. "Bucket": "bucket",
  1495. "Etag": "etag",
  1496. "Generation": "generation",
  1497. "Metageneration": "metageneration",
  1498. "StorageClass": "storage_class",
  1499. "Size": "size",
  1500. "ContentEncoding": "content_encoding",
  1501. "ContentDisposition": "content_disposition",
  1502. "CacheControl": "cache_control",
  1503. "ACL": "acl",
  1504. "ContentLanguage": "content_language",
  1505. "Deleted": "delete_time",
  1506. "ContentType": "content_type",
  1507. "Created": "create_time",
  1508. "CRC32C": "checksums.crc32c",
  1509. "MD5": "checksums.md5_hash",
  1510. "Updated": "update_time",
  1511. "KMSKeyName": "kms_key",
  1512. "TemporaryHold": "temporary_hold",
  1513. "RetentionExpirationTime": "retention_expire_time",
  1514. "Metadata": "metadata",
  1515. "EventBasedHold": "event_based_hold",
  1516. "Owner": "owner",
  1517. "CustomerKeySHA256": "customer_encryption",
  1518. "CustomTime": "custom_time",
  1519. "ComponentCount": "component_count",
  1520. // MediaLink was explicitly excluded from the proto as it is an HTTP-ism.
  1521. // "MediaLink": "mediaLink",
  1522. // TODO: add object retention - b/308194853
  1523. }
  1524. // SetAttrSelection makes the query populate only specific attributes of
  1525. // objects. When iterating over objects, if you only need each object's name
  1526. // and size, pass []string{"Name", "Size"} to this method. Only these fields
  1527. // will be fetched for each object across the network; the other fields of
  1528. // ObjectAttr will remain at their default values. This is a performance
  1529. // optimization; for more information, see
  1530. // https://cloud.google.com/storage/docs/json_api/v1/how-tos/performance
  1531. func (q *Query) SetAttrSelection(attrs []string) error {
  1532. // Validate selections.
  1533. for _, attr := range attrs {
  1534. // If the attr is acceptable for one of the two sets, then it is OK.
  1535. // If it is not acceptable for either, then return an error.
  1536. // The respective masking implementations ignore unknown attrs which
  1537. // makes switching between transports a little easier.
  1538. _, okJSON := attrToFieldMap[attr]
  1539. _, okGRPC := attrToProtoFieldMap[attr]
  1540. if !okJSON && !okGRPC {
  1541. return fmt.Errorf("storage: attr %v is not valid", attr)
  1542. }
  1543. }
  1544. q.attrSelection = attrs
  1545. return nil
  1546. }
  1547. func (q *Query) toFieldSelection() string {
  1548. if q == nil || len(q.attrSelection) == 0 {
  1549. return ""
  1550. }
  1551. fieldSet := make(map[string]bool)
  1552. for _, attr := range q.attrSelection {
  1553. field, ok := attrToFieldMap[attr]
  1554. if !ok {
  1555. // Future proofing, skip unknown fields, let SetAttrSelection handle
  1556. // error modes.
  1557. continue
  1558. }
  1559. fieldSet[field] = true
  1560. }
  1561. var s string
  1562. if len(fieldSet) > 0 {
  1563. var b bytes.Buffer
  1564. b.WriteString("prefixes,items(")
  1565. first := true
  1566. for field := range fieldSet {
  1567. if !first {
  1568. b.WriteString(",")
  1569. }
  1570. first = false
  1571. b.WriteString(field)
  1572. }
  1573. b.WriteString(")")
  1574. s = b.String()
  1575. }
  1576. return s
  1577. }
  1578. func (q *Query) toFieldMask() *fieldmaskpb.FieldMask {
  1579. // The default behavior with no Query is ProjectionDefault (i.e. ProjectionFull).
  1580. if q == nil {
  1581. return &fieldmaskpb.FieldMask{Paths: []string{"*"}}
  1582. }
  1583. // User selected attributes via q.SetAttrSeleciton. This takes precedence
  1584. // over the Projection.
  1585. if numSelected := len(q.attrSelection); numSelected > 0 {
  1586. protoFieldPaths := make([]string, 0, numSelected)
  1587. for _, attr := range q.attrSelection {
  1588. pf, ok := attrToProtoFieldMap[attr]
  1589. if !ok {
  1590. // Future proofing, skip unknown fields, let SetAttrSelection
  1591. // handle error modes.
  1592. continue
  1593. }
  1594. protoFieldPaths = append(protoFieldPaths, pf)
  1595. }
  1596. return &fieldmaskpb.FieldMask{Paths: protoFieldPaths}
  1597. }
  1598. // ProjectDefault == ProjectionFull which means all fields.
  1599. fm := &fieldmaskpb.FieldMask{Paths: []string{"*"}}
  1600. if q.Projection == ProjectionNoACL {
  1601. paths := make([]string, 0, len(attrToProtoFieldMap)-2) // omitting two fields
  1602. for _, f := range attrToProtoFieldMap {
  1603. // Skip the acl and owner fields for "NoACL".
  1604. if f == "acl" || f == "owner" {
  1605. continue
  1606. }
  1607. paths = append(paths, f)
  1608. }
  1609. fm.Paths = paths
  1610. }
  1611. return fm
  1612. }
  1613. // Conditions constrain methods to act on specific generations of
  1614. // objects.
  1615. //
  1616. // The zero value is an empty set of constraints. Not all conditions or
  1617. // combinations of conditions are applicable to all methods.
  1618. // See https://cloud.google.com/storage/docs/generations-preconditions
  1619. // for details on how these operate.
  1620. type Conditions struct {
  1621. // Generation constraints.
  1622. // At most one of the following can be set to a non-zero value.
  1623. // GenerationMatch specifies that the object must have the given generation
  1624. // for the operation to occur.
  1625. // If GenerationMatch is zero, it has no effect.
  1626. // Use DoesNotExist to specify that the object does not exist in the bucket.
  1627. GenerationMatch int64
  1628. // GenerationNotMatch specifies that the object must not have the given
  1629. // generation for the operation to occur.
  1630. // If GenerationNotMatch is zero, it has no effect.
  1631. // This condition only works for object reads if the WithJSONReads client
  1632. // option is set.
  1633. GenerationNotMatch int64
  1634. // DoesNotExist specifies that the object must not exist in the bucket for
  1635. // the operation to occur.
  1636. // If DoesNotExist is false, it has no effect.
  1637. DoesNotExist bool
  1638. // Metadata generation constraints.
  1639. // At most one of the following can be set to a non-zero value.
  1640. // MetagenerationMatch specifies that the object must have the given
  1641. // metageneration for the operation to occur.
  1642. // If MetagenerationMatch is zero, it has no effect.
  1643. MetagenerationMatch int64
  1644. // MetagenerationNotMatch specifies that the object must not have the given
  1645. // metageneration for the operation to occur.
  1646. // If MetagenerationNotMatch is zero, it has no effect.
  1647. // This condition only works for object reads if the WithJSONReads client
  1648. // option is set.
  1649. MetagenerationNotMatch int64
  1650. }
  1651. func (c *Conditions) validate(method string) error {
  1652. if *c == (Conditions{}) {
  1653. return fmt.Errorf("storage: %s: empty conditions", method)
  1654. }
  1655. if !c.isGenerationValid() {
  1656. return fmt.Errorf("storage: %s: multiple conditions specified for generation", method)
  1657. }
  1658. if !c.isMetagenerationValid() {
  1659. return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method)
  1660. }
  1661. return nil
  1662. }
  1663. func (c *Conditions) isGenerationValid() bool {
  1664. n := 0
  1665. if c.GenerationMatch != 0 {
  1666. n++
  1667. }
  1668. if c.GenerationNotMatch != 0 {
  1669. n++
  1670. }
  1671. if c.DoesNotExist {
  1672. n++
  1673. }
  1674. return n <= 1
  1675. }
  1676. func (c *Conditions) isMetagenerationValid() bool {
  1677. return c.MetagenerationMatch == 0 || c.MetagenerationNotMatch == 0
  1678. }
  1679. // applyConds modifies the provided call using the conditions in conds.
  1680. // call is something that quacks like a *raw.WhateverCall.
  1681. func applyConds(method string, gen int64, conds *Conditions, call interface{}) error {
  1682. cval := reflect.ValueOf(call)
  1683. if gen >= 0 {
  1684. if !setGeneration(cval, gen) {
  1685. return fmt.Errorf("storage: %s: generation not supported", method)
  1686. }
  1687. }
  1688. if conds == nil {
  1689. return nil
  1690. }
  1691. if err := conds.validate(method); err != nil {
  1692. return err
  1693. }
  1694. switch {
  1695. case conds.GenerationMatch != 0:
  1696. if !setIfGenerationMatch(cval, conds.GenerationMatch) {
  1697. return fmt.Errorf("storage: %s: ifGenerationMatch not supported", method)
  1698. }
  1699. case conds.GenerationNotMatch != 0:
  1700. if !setIfGenerationNotMatch(cval, conds.GenerationNotMatch) {
  1701. return fmt.Errorf("storage: %s: ifGenerationNotMatch not supported", method)
  1702. }
  1703. case conds.DoesNotExist:
  1704. if !setIfGenerationMatch(cval, int64(0)) {
  1705. return fmt.Errorf("storage: %s: DoesNotExist not supported", method)
  1706. }
  1707. }
  1708. switch {
  1709. case conds.MetagenerationMatch != 0:
  1710. if !setIfMetagenerationMatch(cval, conds.MetagenerationMatch) {
  1711. return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
  1712. }
  1713. case conds.MetagenerationNotMatch != 0:
  1714. if !setIfMetagenerationNotMatch(cval, conds.MetagenerationNotMatch) {
  1715. return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
  1716. }
  1717. }
  1718. return nil
  1719. }
  1720. func applySourceConds(gen int64, conds *Conditions, call *raw.ObjectsRewriteCall) error {
  1721. if gen >= 0 {
  1722. call.SourceGeneration(gen)
  1723. }
  1724. if conds == nil {
  1725. return nil
  1726. }
  1727. if err := conds.validate("CopyTo source"); err != nil {
  1728. return err
  1729. }
  1730. switch {
  1731. case conds.GenerationMatch != 0:
  1732. call.IfSourceGenerationMatch(conds.GenerationMatch)
  1733. case conds.GenerationNotMatch != 0:
  1734. call.IfSourceGenerationNotMatch(conds.GenerationNotMatch)
  1735. case conds.DoesNotExist:
  1736. call.IfSourceGenerationMatch(0)
  1737. }
  1738. switch {
  1739. case conds.MetagenerationMatch != 0:
  1740. call.IfSourceMetagenerationMatch(conds.MetagenerationMatch)
  1741. case conds.MetagenerationNotMatch != 0:
  1742. call.IfSourceMetagenerationNotMatch(conds.MetagenerationNotMatch)
  1743. }
  1744. return nil
  1745. }
  1746. func applySourceCondsProto(gen int64, conds *Conditions, call *storagepb.RewriteObjectRequest) error {
  1747. if gen >= 0 {
  1748. call.SourceGeneration = gen
  1749. }
  1750. if conds == nil {
  1751. return nil
  1752. }
  1753. if err := conds.validate("CopyTo source"); err != nil {
  1754. return err
  1755. }
  1756. switch {
  1757. case conds.GenerationMatch != 0:
  1758. call.IfSourceGenerationMatch = proto.Int64(conds.GenerationMatch)
  1759. case conds.GenerationNotMatch != 0:
  1760. call.IfSourceGenerationNotMatch = proto.Int64(conds.GenerationNotMatch)
  1761. case conds.DoesNotExist:
  1762. call.IfSourceGenerationMatch = proto.Int64(0)
  1763. }
  1764. switch {
  1765. case conds.MetagenerationMatch != 0:
  1766. call.IfSourceMetagenerationMatch = proto.Int64(conds.MetagenerationMatch)
  1767. case conds.MetagenerationNotMatch != 0:
  1768. call.IfSourceMetagenerationNotMatch = proto.Int64(conds.MetagenerationNotMatch)
  1769. }
  1770. return nil
  1771. }
  1772. // setGeneration sets Generation on a *raw.WhateverCall.
  1773. // We can't use anonymous interfaces because the return type is
  1774. // different, since the field setters are builders.
  1775. // We also make sure to supply a compile-time constant to MethodByName;
  1776. // otherwise, the Go Linker will disable dead code elimination, leading
  1777. // to larger binaries for all packages that import storage.
  1778. func setGeneration(cval reflect.Value, value interface{}) bool {
  1779. return setCondition(cval.MethodByName("Generation"), value)
  1780. }
  1781. // setIfGenerationMatch sets IfGenerationMatch on a *raw.WhateverCall.
  1782. // See also setGeneration.
  1783. func setIfGenerationMatch(cval reflect.Value, value interface{}) bool {
  1784. return setCondition(cval.MethodByName("IfGenerationMatch"), value)
  1785. }
  1786. // setIfGenerationNotMatch sets IfGenerationNotMatch on a *raw.WhateverCall.
  1787. // See also setGeneration.
  1788. func setIfGenerationNotMatch(cval reflect.Value, value interface{}) bool {
  1789. return setCondition(cval.MethodByName("IfGenerationNotMatch"), value)
  1790. }
  1791. // setIfMetagenerationMatch sets IfMetagenerationMatch on a *raw.WhateverCall.
  1792. // See also setGeneration.
  1793. func setIfMetagenerationMatch(cval reflect.Value, value interface{}) bool {
  1794. return setCondition(cval.MethodByName("IfMetagenerationMatch"), value)
  1795. }
  1796. // setIfMetagenerationNotMatch sets IfMetagenerationNotMatch on a *raw.WhateverCall.
  1797. // See also setGeneration.
  1798. func setIfMetagenerationNotMatch(cval reflect.Value, value interface{}) bool {
  1799. return setCondition(cval.MethodByName("IfMetagenerationNotMatch"), value)
  1800. }
  1801. func setCondition(setter reflect.Value, value interface{}) bool {
  1802. if setter.IsValid() {
  1803. setter.Call([]reflect.Value{reflect.ValueOf(value)})
  1804. }
  1805. return setter.IsValid()
  1806. }
  1807. // Retryer returns an object handle that is configured with custom retry
  1808. // behavior as specified by the options that are passed to it. All operations
  1809. // on the new handle will use the customized retry configuration.
  1810. // These retry options will merge with the bucket's retryer (if set) for the
  1811. // returned handle. Options passed into this method will take precedence over
  1812. // retry options on the bucket and client. Note that you must explicitly pass in
  1813. // each option you want to override.
  1814. func (o *ObjectHandle) Retryer(opts ...RetryOption) *ObjectHandle {
  1815. o2 := *o
  1816. var retry *retryConfig
  1817. if o.retry != nil {
  1818. // merge the options with the existing retry
  1819. retry = o.retry
  1820. } else {
  1821. retry = &retryConfig{}
  1822. }
  1823. for _, opt := range opts {
  1824. opt.apply(retry)
  1825. }
  1826. o2.retry = retry
  1827. o2.acl.retry = retry
  1828. return &o2
  1829. }
  1830. // SetRetry configures the client with custom retry behavior as specified by the
  1831. // options that are passed to it. All operations using this client will use the
  1832. // customized retry configuration.
  1833. // This should be called once before using the client for network operations, as
  1834. // there could be indeterminate behaviour with operations in progress.
  1835. // Retry options set on a bucket or object handle will take precedence over
  1836. // these options.
  1837. func (c *Client) SetRetry(opts ...RetryOption) {
  1838. var retry *retryConfig
  1839. if c.retry != nil {
  1840. // merge the options with the existing retry
  1841. retry = c.retry
  1842. } else {
  1843. retry = &retryConfig{}
  1844. }
  1845. for _, opt := range opts {
  1846. opt.apply(retry)
  1847. }
  1848. c.retry = retry
  1849. }
  1850. // RetryOption allows users to configure non-default retry behavior for API
  1851. // calls made to GCS.
  1852. type RetryOption interface {
  1853. apply(config *retryConfig)
  1854. }
  1855. // WithBackoff allows configuration of the backoff timing used for retries.
  1856. // Available configuration options (Initial, Max and Multiplier) are described
  1857. // at https://pkg.go.dev/github.com/googleapis/gax-go/v2#Backoff. If any fields
  1858. // are not supplied by the user, gax default values will be used.
  1859. func WithBackoff(backoff gax.Backoff) RetryOption {
  1860. return &withBackoff{
  1861. backoff: backoff,
  1862. }
  1863. }
  1864. type withBackoff struct {
  1865. backoff gax.Backoff
  1866. }
  1867. func (wb *withBackoff) apply(config *retryConfig) {
  1868. config.backoff = &wb.backoff
  1869. }
  1870. // WithMaxAttempts configures the maximum number of times an API call can be made
  1871. // in the case of retryable errors.
  1872. // For example, if you set WithMaxAttempts(5), the operation will be attempted up to 5
  1873. // times total (initial call plus 4 retries).
  1874. // Without this setting, operations will continue retrying indefinitely
  1875. // until either the context is canceled or a deadline is reached.
  1876. func WithMaxAttempts(maxAttempts int) RetryOption {
  1877. return &withMaxAttempts{
  1878. maxAttempts: maxAttempts,
  1879. }
  1880. }
  1881. type withMaxAttempts struct {
  1882. maxAttempts int
  1883. }
  1884. func (wb *withMaxAttempts) apply(config *retryConfig) {
  1885. config.maxAttempts = &wb.maxAttempts
  1886. }
  1887. // RetryPolicy describes the available policies for which operations should be
  1888. // retried. The default is `RetryIdempotent`.
  1889. type RetryPolicy int
  1890. const (
  1891. // RetryIdempotent causes only idempotent operations to be retried when the
  1892. // service returns a transient error. Using this policy, fully idempotent
  1893. // operations (such as `ObjectHandle.Attrs()`) will always be retried.
  1894. // Conditionally idempotent operations (for example `ObjectHandle.Update()`)
  1895. // will be retried only if the necessary conditions have been supplied (in
  1896. // the case of `ObjectHandle.Update()` this would mean supplying a
  1897. // `Conditions.MetagenerationMatch` condition is required).
  1898. RetryIdempotent RetryPolicy = iota
  1899. // RetryAlways causes all operations to be retried when the service returns a
  1900. // transient error, regardless of idempotency considerations.
  1901. RetryAlways
  1902. // RetryNever causes the client to not perform retries on failed operations.
  1903. RetryNever
  1904. )
  1905. // WithPolicy allows the configuration of which operations should be performed
  1906. // with retries for transient errors.
  1907. func WithPolicy(policy RetryPolicy) RetryOption {
  1908. return &withPolicy{
  1909. policy: policy,
  1910. }
  1911. }
  1912. type withPolicy struct {
  1913. policy RetryPolicy
  1914. }
  1915. func (ws *withPolicy) apply(config *retryConfig) {
  1916. config.policy = ws.policy
  1917. }
  1918. // WithErrorFunc allows users to pass a custom function to the retryer. Errors
  1919. // will be retried if and only if `shouldRetry(err)` returns true.
  1920. // By default, the following errors are retried (see ShouldRetry for the default
  1921. // function):
  1922. //
  1923. // - HTTP responses with codes 408, 429, 502, 503, and 504.
  1924. //
  1925. // - Transient network errors such as connection reset and io.ErrUnexpectedEOF.
  1926. //
  1927. // - Errors which are considered transient using the Temporary() interface.
  1928. //
  1929. // - Wrapped versions of these errors.
  1930. //
  1931. // This option can be used to retry on a different set of errors than the
  1932. // default. Users can use the default ShouldRetry function inside their custom
  1933. // function if they only want to make minor modifications to default behavior.
  1934. func WithErrorFunc(shouldRetry func(err error) bool) RetryOption {
  1935. return &withErrorFunc{
  1936. shouldRetry: shouldRetry,
  1937. }
  1938. }
  1939. type withErrorFunc struct {
  1940. shouldRetry func(err error) bool
  1941. }
  1942. func (wef *withErrorFunc) apply(config *retryConfig) {
  1943. config.shouldRetry = wef.shouldRetry
  1944. }
  1945. type retryConfig struct {
  1946. backoff *gax.Backoff
  1947. policy RetryPolicy
  1948. shouldRetry func(err error) bool
  1949. maxAttempts *int
  1950. }
  1951. func (r *retryConfig) clone() *retryConfig {
  1952. if r == nil {
  1953. return nil
  1954. }
  1955. var bo *gax.Backoff
  1956. if r.backoff != nil {
  1957. bo = &gax.Backoff{
  1958. Initial: r.backoff.Initial,
  1959. Max: r.backoff.Max,
  1960. Multiplier: r.backoff.Multiplier,
  1961. }
  1962. }
  1963. return &retryConfig{
  1964. backoff: bo,
  1965. policy: r.policy,
  1966. shouldRetry: r.shouldRetry,
  1967. maxAttempts: r.maxAttempts,
  1968. }
  1969. }
  1970. // composeSourceObj wraps a *raw.ComposeRequestSourceObjects, but adds the methods
  1971. // that modifyCall searches for by name.
  1972. type composeSourceObj struct {
  1973. src *raw.ComposeRequestSourceObjects
  1974. }
  1975. func (c composeSourceObj) Generation(gen int64) {
  1976. c.src.Generation = gen
  1977. }
  1978. func (c composeSourceObj) IfGenerationMatch(gen int64) {
  1979. // It's safe to overwrite ObjectPreconditions, since its only field is
  1980. // IfGenerationMatch.
  1981. c.src.ObjectPreconditions = &raw.ComposeRequestSourceObjectsObjectPreconditions{
  1982. IfGenerationMatch: gen,
  1983. }
  1984. }
  1985. func setEncryptionHeaders(headers http.Header, key []byte, copySource bool) error {
  1986. if key == nil {
  1987. return nil
  1988. }
  1989. // TODO(jbd): Ask the API team to return a more user-friendly error
  1990. // and avoid doing this check at the client level.
  1991. if len(key) != 32 {
  1992. return errors.New("storage: not a 32-byte AES-256 key")
  1993. }
  1994. var cs string
  1995. if copySource {
  1996. cs = "copy-source-"
  1997. }
  1998. headers.Set("x-goog-"+cs+"encryption-algorithm", aes256Algorithm)
  1999. headers.Set("x-goog-"+cs+"encryption-key", base64.StdEncoding.EncodeToString(key))
  2000. keyHash := sha256.Sum256(key)
  2001. headers.Set("x-goog-"+cs+"encryption-key-sha256", base64.StdEncoding.EncodeToString(keyHash[:]))
  2002. return nil
  2003. }
  2004. // toProtoCommonObjectRequestParams sets customer-supplied encryption to the proto library's CommonObjectRequestParams.
  2005. func toProtoCommonObjectRequestParams(key []byte) *storagepb.CommonObjectRequestParams {
  2006. if key == nil {
  2007. return nil
  2008. }
  2009. keyHash := sha256.Sum256(key)
  2010. return &storagepb.CommonObjectRequestParams{
  2011. EncryptionAlgorithm: aes256Algorithm,
  2012. EncryptionKeyBytes: key,
  2013. EncryptionKeySha256Bytes: keyHash[:],
  2014. }
  2015. }
  2016. func toProtoChecksums(sendCRC32C bool, attrs *ObjectAttrs) *storagepb.ObjectChecksums {
  2017. var checksums *storagepb.ObjectChecksums
  2018. if sendCRC32C {
  2019. checksums = &storagepb.ObjectChecksums{
  2020. Crc32C: proto.Uint32(attrs.CRC32C),
  2021. }
  2022. }
  2023. if len(attrs.MD5) != 0 {
  2024. if checksums == nil {
  2025. checksums = &storagepb.ObjectChecksums{
  2026. Md5Hash: attrs.MD5,
  2027. }
  2028. } else {
  2029. checksums.Md5Hash = attrs.MD5
  2030. }
  2031. }
  2032. return checksums
  2033. }
  2034. // ServiceAccount fetches the email address of the given project's Google Cloud Storage service account.
  2035. func (c *Client) ServiceAccount(ctx context.Context, projectID string) (string, error) {
  2036. o := makeStorageOpts(true, c.retry, "")
  2037. return c.tc.GetServiceAccount(ctx, projectID, o...)
  2038. }
  2039. // bucketResourceName formats the given project ID and bucketResourceName ID
  2040. // into a Bucket resource name. This is the format necessary for the gRPC API as
  2041. // it conforms to the Resource-oriented design practices in https://google.aip.dev/121.
  2042. func bucketResourceName(p, b string) string {
  2043. return fmt.Sprintf("projects/%s/buckets/%s", p, b)
  2044. }
  2045. // parseBucketName strips the leading resource path segment and returns the
  2046. // bucket ID, which is the simple Bucket name typical of the v1 API.
  2047. func parseBucketName(b string) string {
  2048. sep := strings.LastIndex(b, "/")
  2049. return b[sep+1:]
  2050. }
  2051. // parseProjectNumber consume the given resource name and parses out the project
  2052. // number if one is present i.e. it is not a project ID.
  2053. func parseProjectNumber(r string) uint64 {
  2054. projectID := regexp.MustCompile(`projects\/([0-9]+)\/?`)
  2055. if matches := projectID.FindStringSubmatch(r); len(matches) > 0 {
  2056. // Capture group follows the matched segment. For example:
  2057. // input: projects/123/bars/456
  2058. // output: [projects/123/, 123]
  2059. number, err := strconv.ParseUint(matches[1], 10, 64)
  2060. if err != nil {
  2061. return 0
  2062. }
  2063. return number
  2064. }
  2065. return 0
  2066. }
  2067. // toProjectResource accepts a project ID and formats it as a Project resource
  2068. // name.
  2069. func toProjectResource(project string) string {
  2070. return fmt.Sprintf("projects/%s", project)
  2071. }
  2072. // setConditionProtoField uses protobuf reflection to set named condition field
  2073. // to the given condition value if supported on the protobuf message.
  2074. func setConditionProtoField(m protoreflect.Message, f string, v int64) bool {
  2075. fields := m.Descriptor().Fields()
  2076. if rf := fields.ByName(protoreflect.Name(f)); rf != nil {
  2077. m.Set(rf, protoreflect.ValueOfInt64(v))
  2078. return true
  2079. }
  2080. return false
  2081. }
  2082. // applyCondsProto validates and attempts to set the conditions on a protobuf
  2083. // message using protobuf reflection.
  2084. func applyCondsProto(method string, gen int64, conds *Conditions, msg proto.Message) error {
  2085. rmsg := msg.ProtoReflect()
  2086. if gen >= 0 {
  2087. if !setConditionProtoField(rmsg, "generation", gen) {
  2088. return fmt.Errorf("storage: %s: generation not supported", method)
  2089. }
  2090. }
  2091. if conds == nil {
  2092. return nil
  2093. }
  2094. if err := conds.validate(method); err != nil {
  2095. return err
  2096. }
  2097. switch {
  2098. case conds.GenerationMatch != 0:
  2099. if !setConditionProtoField(rmsg, "if_generation_match", conds.GenerationMatch) {
  2100. return fmt.Errorf("storage: %s: ifGenerationMatch not supported", method)
  2101. }
  2102. case conds.GenerationNotMatch != 0:
  2103. if !setConditionProtoField(rmsg, "if_generation_not_match", conds.GenerationNotMatch) {
  2104. return fmt.Errorf("storage: %s: ifGenerationNotMatch not supported", method)
  2105. }
  2106. case conds.DoesNotExist:
  2107. if !setConditionProtoField(rmsg, "if_generation_match", int64(0)) {
  2108. return fmt.Errorf("storage: %s: DoesNotExist not supported", method)
  2109. }
  2110. }
  2111. switch {
  2112. case conds.MetagenerationMatch != 0:
  2113. if !setConditionProtoField(rmsg, "if_metageneration_match", conds.MetagenerationMatch) {
  2114. return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
  2115. }
  2116. case conds.MetagenerationNotMatch != 0:
  2117. if !setConditionProtoField(rmsg, "if_metageneration_not_match", conds.MetagenerationNotMatch) {
  2118. return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
  2119. }
  2120. }
  2121. return nil
  2122. }