api-get-options.go (5999B)
1 /* 2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2015-2020 MinIO, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package minio 19 20 import ( 21 "fmt" 22 "net/http" 23 "net/url" 24 "strconv" 25 "time" 26 27 "github.com/minio/minio-go/v7/pkg/encrypt" 28 ) 29 30 // AdvancedGetOptions for internal use by MinIO server - not intended for client use. 31 type AdvancedGetOptions struct { 32 ReplicationDeleteMarker bool 33 IsReplicationReadyForDeleteMarker bool 34 ReplicationProxyRequest string 35 } 36 37 // GetObjectOptions are used to specify additional headers or options 38 // during GET requests. 39 type GetObjectOptions struct { 40 headers map[string]string 41 reqParams url.Values 42 ServerSideEncryption encrypt.ServerSide 43 VersionID string 44 PartNumber int 45 46 // Include any checksums, if object was uploaded with checksum. 47 // For multipart objects this is a checksum of part checksums. 48 // https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html 49 Checksum bool 50 51 // To be not used by external applications 52 Internal AdvancedGetOptions 53 } 54 55 // StatObjectOptions are used to specify additional headers or options 56 // during GET info/stat requests. 57 type StatObjectOptions = GetObjectOptions 58 59 // Header returns the http.Header representation of the GET options. 60 func (o GetObjectOptions) Header() http.Header { 61 headers := make(http.Header, len(o.headers)) 62 for k, v := range o.headers { 63 headers.Set(k, v) 64 } 65 if o.ServerSideEncryption != nil && o.ServerSideEncryption.Type() == encrypt.SSEC { 66 o.ServerSideEncryption.Marshal(headers) 67 } 68 // this header is set for active-active replication scenario where GET/HEAD 69 // to site A is proxy'd to site B if object/version missing on site A. 70 if o.Internal.ReplicationProxyRequest != "" { 71 headers.Set(minIOBucketReplicationProxyRequest, o.Internal.ReplicationProxyRequest) 72 } 73 if o.Checksum { 74 headers.Set("x-amz-checksum-mode", "ENABLED") 75 } 76 return headers 77 } 78 79 // Set adds a key value pair to the options. The 80 // key-value pair will be part of the HTTP GET request 81 // headers. 82 func (o *GetObjectOptions) Set(key, value string) { 83 if o.headers == nil { 84 o.headers = make(map[string]string) 85 } 86 o.headers[http.CanonicalHeaderKey(key)] = value 87 } 88 89 // SetReqParam - set request query string parameter 90 // supported key: see supportedQueryValues. 91 // If an unsupported key is passed in, it will be ignored and nothing will be done. 92 func (o *GetObjectOptions) SetReqParam(key, value string) { 93 if !isStandardQueryValue(key) { 94 // do nothing 95 return 96 } 97 if o.reqParams == nil { 98 o.reqParams = make(url.Values) 99 } 100 o.reqParams.Set(key, value) 101 } 102 103 // AddReqParam - add request query string parameter 104 // supported key: see supportedQueryValues. 105 // If an unsupported key is passed in, it will be ignored and nothing will be done. 106 func (o *GetObjectOptions) AddReqParam(key, value string) { 107 if !isStandardQueryValue(key) { 108 // do nothing 109 return 110 } 111 if o.reqParams == nil { 112 o.reqParams = make(url.Values) 113 } 114 o.reqParams.Add(key, value) 115 } 116 117 // SetMatchETag - set match etag. 118 func (o *GetObjectOptions) SetMatchETag(etag string) error { 119 if etag == "" { 120 return errInvalidArgument("ETag cannot be empty.") 121 } 122 o.Set("If-Match", "\""+etag+"\"") 123 return nil 124 } 125 126 // SetMatchETagExcept - set match etag except. 127 func (o *GetObjectOptions) SetMatchETagExcept(etag string) error { 128 if etag == "" { 129 return errInvalidArgument("ETag cannot be empty.") 130 } 131 o.Set("If-None-Match", "\""+etag+"\"") 132 return nil 133 } 134 135 // SetUnmodified - set unmodified time since. 136 func (o *GetObjectOptions) SetUnmodified(modTime time.Time) error { 137 if modTime.IsZero() { 138 return errInvalidArgument("Modified since cannot be empty.") 139 } 140 o.Set("If-Unmodified-Since", modTime.Format(http.TimeFormat)) 141 return nil 142 } 143 144 // SetModified - set modified time since. 145 func (o *GetObjectOptions) SetModified(modTime time.Time) error { 146 if modTime.IsZero() { 147 return errInvalidArgument("Modified since cannot be empty.") 148 } 149 o.Set("If-Modified-Since", modTime.Format(http.TimeFormat)) 150 return nil 151 } 152 153 // SetRange - set the start and end offset of the object to be read. 154 // See https://tools.ietf.org/html/rfc7233#section-3.1 for reference. 155 func (o *GetObjectOptions) SetRange(start, end int64) error { 156 switch { 157 case start == 0 && end < 0: 158 // Read last '-end' bytes. `bytes=-N`. 159 o.Set("Range", fmt.Sprintf("bytes=%d", end)) 160 case 0 < start && end == 0: 161 // Read everything starting from offset 162 // 'start'. `bytes=N-`. 163 o.Set("Range", fmt.Sprintf("bytes=%d-", start)) 164 case 0 <= start && start <= end: 165 // Read everything starting at 'start' till the 166 // 'end'. `bytes=N-M` 167 o.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end)) 168 default: 169 // All other cases such as 170 // bytes=-3- 171 // bytes=5-3 172 // bytes=-2-4 173 // bytes=-3-0 174 // bytes=-3--2 175 // are invalid. 176 return errInvalidArgument( 177 fmt.Sprintf( 178 "Invalid range specified: start=%d end=%d", 179 start, end)) 180 } 181 return nil 182 } 183 184 // toQueryValues - Convert the versionId, partNumber, and reqParams in Options to query string parameters. 185 func (o *GetObjectOptions) toQueryValues() url.Values { 186 urlValues := make(url.Values) 187 if o.VersionID != "" { 188 urlValues.Set("versionId", o.VersionID) 189 } 190 if o.PartNumber > 0 { 191 urlValues.Set("partNumber", strconv.Itoa(o.PartNumber)) 192 } 193 194 if o.reqParams != nil { 195 for key, values := range o.reqParams { 196 for _, value := range values { 197 urlValues.Add(key, value) 198 } 199 } 200 } 201 202 return urlValues 203 }