storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/gateway/s3/gateway-s3-metadata.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2018 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package s3
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"errors"
    24  	"net/http"
    25  	"time"
    26  
    27  	jsoniter "github.com/json-iterator/go"
    28  
    29  	minio "storj.io/minio/cmd"
    30  	"storj.io/minio/cmd/logger"
    31  	"storj.io/minio/pkg/hash"
    32  )
    33  
    34  var (
    35  	errGWMetaNotFound      = errors.New("dare.meta file not found")
    36  	errGWMetaInvalidFormat = errors.New("dare.meta format is invalid")
    37  )
    38  
    39  // A gwMetaV1 represents `gw.json` metadata header.
    40  type gwMetaV1 struct {
    41  	Version string         `json:"version"` // Version of the current `gw.json`.
    42  	Format  string         `json:"format"`  // Format of the current `gw.json`.
    43  	Stat    minio.StatInfo `json:"stat"`    // Stat of the current object `gw.json`.
    44  	ETag    string         `json:"etag"`    // ETag of the current object
    45  
    46  	// Metadata map for current object `gw.json`.
    47  	Meta map[string]string `json:"meta,omitempty"`
    48  	// Captures all the individual object `gw.json`.
    49  	Parts []minio.ObjectPartInfo `json:"parts,omitempty"`
    50  }
    51  
    52  // Gateway metadata constants.
    53  const (
    54  	// Gateway meta version.
    55  	gwMetaVersion = "1.0.0"
    56  
    57  	// Gateway meta version.
    58  	gwMetaVersion100 = "1.0.0"
    59  
    60  	// Gateway meta format string.
    61  	gwMetaFormat = "gw"
    62  
    63  	// Add new constants here.
    64  )
    65  
    66  // newGWMetaV1 - initializes new gwMetaV1, adds version.
    67  func newGWMetaV1() (gwMeta gwMetaV1) {
    68  	gwMeta = gwMetaV1{}
    69  	gwMeta.Version = gwMetaVersion
    70  	gwMeta.Format = gwMetaFormat
    71  	return gwMeta
    72  }
    73  
    74  // IsValid - tells if the format is sane by validating the version
    75  // string, format fields.
    76  func (m gwMetaV1) IsValid() bool {
    77  	return ((m.Version == gwMetaVersion || m.Version == gwMetaVersion100) &&
    78  		m.Format == gwMetaFormat)
    79  }
    80  
    81  // Converts metadata to object info.
    82  func (m gwMetaV1) ToObjectInfo(bucket, object string) minio.ObjectInfo {
    83  	filterKeys := append([]string{
    84  		"ETag",
    85  		"Content-Length",
    86  		"Last-Modified",
    87  		"Content-Type",
    88  		"Expires",
    89  	}, defaultFilterKeys...)
    90  	objInfo := minio.ObjectInfo{
    91  		IsDir:           false,
    92  		Bucket:          bucket,
    93  		Name:            object,
    94  		Size:            m.Stat.Size,
    95  		ModTime:         m.Stat.ModTime,
    96  		ContentType:     m.Meta["content-type"],
    97  		ContentEncoding: m.Meta["content-encoding"],
    98  		ETag:            minio.CanonicalizeETag(m.ETag),
    99  		UserDefined:     minio.CleanMinioInternalMetadataKeys(minio.CleanMetadataKeys(m.Meta, filterKeys...)),
   100  		Parts:           m.Parts,
   101  	}
   102  
   103  	if sc, ok := m.Meta["x-amz-storage-class"]; ok {
   104  		objInfo.StorageClass = sc
   105  	}
   106  	var (
   107  		t time.Time
   108  		e error
   109  	)
   110  	if exp, ok := m.Meta["expires"]; ok {
   111  		if t, e = time.Parse(http.TimeFormat, exp); e == nil {
   112  			objInfo.Expires = t.UTC()
   113  		}
   114  	}
   115  	// Success.
   116  	return objInfo
   117  }
   118  
   119  // ObjectToPartOffset - translate offset of an object to offset of its individual part.
   120  func (m gwMetaV1) ObjectToPartOffset(ctx context.Context, offset int64) (partIndex int, partOffset int64, err error) {
   121  	if offset == 0 {
   122  		// Special case - if offset is 0, then partIndex and partOffset are always 0.
   123  		return 0, 0, nil
   124  	}
   125  	partOffset = offset
   126  	// Seek until object offset maps to a particular part offset.
   127  	for i, part := range m.Parts {
   128  		partIndex = i
   129  		// Offset is smaller than size we have reached the proper part offset.
   130  		if partOffset < part.Size {
   131  			return partIndex, partOffset, nil
   132  		}
   133  		// Continue to towards the next part.
   134  		partOffset -= part.Size
   135  	}
   136  	logger.LogIf(ctx, minio.InvalidRange{})
   137  	// Offset beyond the size of the object return InvalidRange.
   138  	return 0, 0, minio.InvalidRange{}
   139  }
   140  
   141  // Constructs GWMetaV1 using `jsoniter` lib to retrieve each field.
   142  func gwMetaUnmarshalJSON(ctx context.Context, gwMetaBuf []byte) (gwMeta gwMetaV1, err error) {
   143  	var json = jsoniter.ConfigCompatibleWithStandardLibrary
   144  	err = json.Unmarshal(gwMetaBuf, &gwMeta)
   145  	return gwMeta, err
   146  }
   147  
   148  // readGWMeta reads `dare.meta` and returns back GW metadata structure.
   149  func readGWMetadata(ctx context.Context, buf bytes.Buffer) (gwMeta gwMetaV1, err error) {
   150  	if buf.Len() == 0 {
   151  		return gwMetaV1{}, errGWMetaNotFound
   152  	}
   153  	gwMeta, err = gwMetaUnmarshalJSON(ctx, buf.Bytes())
   154  	if err != nil {
   155  		return gwMetaV1{}, err
   156  	}
   157  	if !gwMeta.IsValid() {
   158  		return gwMetaV1{}, errGWMetaInvalidFormat
   159  	}
   160  	// Return structured `dare.meta`.
   161  	return gwMeta, nil
   162  }
   163  
   164  // getGWMetadata - unmarshals dare.meta into a *minio.PutObjReader
   165  func getGWMetadata(ctx context.Context, bucket, prefix string, gwMeta gwMetaV1) (*minio.PutObjReader, error) {
   166  	// Marshal json.
   167  	metadataBytes, err := json.Marshal(&gwMeta)
   168  	if err != nil {
   169  		logger.LogIf(ctx, err)
   170  		return nil, err
   171  	}
   172  	hashReader, err := hash.NewReader(bytes.NewReader(metadataBytes), int64(len(metadataBytes)), "", "", int64(len(metadataBytes)))
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	return minio.NewPutObjReader(hashReader), nil
   177  }