oss/client_presign.go (142 lines of code) (raw):

package oss import ( "context" "fmt" "net/http" "reflect" "time" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/signer" ) type PresignOptions struct { // Expires sets the expiration duration for the generated presign url. Expires time.Duration // Expiration sets the expiration time for the generated presign url. Expiration time.Time } type PresignResult struct { Method string URL string Expiration time.Time SignedHeaders map[string]string } type nopHttpClient struct { } func (c *nopHttpClient) Do(*http.Request) (*http.Response, error) { return &http.Response{ StatusCode: 200, Header: http.Header{}, Body: http.NoBody, }, nil } var ( defaultNopHttpClient = &nopHttpClient{} defaultPresignOptions = []func(*Options){ func(o *Options) { o.HttpClient = defaultNopHttpClient o.AuthMethod = Ptr(AuthMethodQuery) }, } ) func (c *Client) Presign(ctx context.Context, request any, optFns ...func(*PresignOptions)) (*PresignResult, error) { options := PresignOptions{} if request == nil { return nil, NewErrParamNull("request") } for _, fn := range optFns { fn(&options) } input := OperationInput{} if err := c.marshalPresignInput(request, &input); err != nil { return nil, err } // expiration if !options.Expiration.IsZero() { input.OpMetadata.Set(signer.SignTime, options.Expiration) } else if options.Expires > 0 { input.OpMetadata.Set(signer.SignTime, time.Now().Add(options.Expires)) } output, err := c.invokeOperation(ctx, &input, defaultPresignOptions) if err != nil { return nil, err } result := &PresignResult{} err = c.unmarshalPresignOutput(result, output) return result, err } func PresignExpires(value time.Duration) func(*PresignOptions) { return func(o *PresignOptions) { o.Expires = value } } func PresignExpiration(value time.Time) func(*PresignOptions) { return func(o *PresignOptions) { o.Expiration = value } } func (c *Client) marshalPresignInput(request any, input *OperationInput) error { switch t := request.(type) { case *GetObjectRequest: input.OpName = "GetObject" input.Method = "GET" input.Bucket = t.Bucket input.Key = t.Key case *PutObjectRequest: input.OpName = "PutObject" input.Method = "PUT" input.Bucket = t.Bucket input.Key = t.Key case *HeadObjectRequest: input.OpName = "HeadObject" input.Method = "HEAD" input.Bucket = t.Bucket input.Key = t.Key case *InitiateMultipartUploadRequest: input.OpName = "InitiateMultipartUpload" input.Method = "POST" input.Bucket = t.Bucket input.Key = t.Key input.Parameters = map[string]string{ "uploads": "", } case *UploadPartRequest: input.OpName = "UploadPart" input.Method = "PUT" input.Bucket = t.Bucket input.Key = t.Key case *CompleteMultipartUploadRequest: input.OpName = "CompleteMultipartUpload" input.Method = "POST" input.Bucket = t.Bucket input.Key = t.Key case *AbortMultipartUploadRequest: input.OpName = "AbortMultipartUpload" input.Method = "DELETE" input.Bucket = t.Bucket input.Key = t.Key default: return NewErrParamInvalid(fmt.Sprintf("request %v", reflect.ValueOf(request).Type().String())) } return c.marshalInput(request, input) } func (c *Client) unmarshalPresignOutput(result *PresignResult, output *OperationOutput) error { if chk, ok := c.options.Signer.(interface{ IsSignedHeader([]string, string) bool }); ok { header := map[string]string{} for k, v := range output.httpRequest.Header { if chk.IsSignedHeader(c.options.AdditionalHeaders, k) { header[k] = v[0] } } if len(header) > 0 { result.SignedHeaders = header } } result.Method = output.httpRequest.Method result.URL = output.httpRequest.URL.String() if signTime, ok := output.OpMetadata.Get(signer.SignTime).(time.Time); ok { result.Expiration = signTime } _, ok := c.options.Signer.(*signer.SignerV4) if ok { if !result.Expiration.IsZero() && (result.Expiration.After(time.Now().Add(7 * 24 * time.Hour))) { return fmt.Errorf("expires should be not greater than 604800(seven days)") } } return nil }