Skip to content

Commit

Permalink
Propagate ContentType field on create/modify ops (#1141)
Browse files Browse the repository at this point in the history
* Propagate ContentType field on create/modify ops

This commit tries to address 2 bugs that where found when using
some of the create/modify operations GCS supports like:
* using the streamable upload operations of GCS to upload of a File.
* update the blob metadata content-type without modifying the bytes of
  the blob.

For the streamable upload, by default if no content-type is provided;
GCS sets it up to 'application/octet-stream' or uses the one provided by
the user in the BlobInfo (This is the expected behaviour for this operation in GCS).

For the update, when we merge metadata information regarding the
content-type, it should override it the update response should propagate
this change.

* Test for updateObject with content type

This adds a unit test to check that when calling
the updateObject method and a content type is provided,
we override the previous value stored.

* Update fakestorage/object_test.go

---------

Co-authored-by: fsouza <108725+fsouza@users.noreply.github.com>
  • Loading branch information
alorlea and fsouza committed May 2, 2023
1 parent 5d4dc2d commit e2d2de1
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 5 deletions.
9 changes: 5 additions & 4 deletions fakestorage/object.go
Expand Up @@ -996,9 +996,10 @@ func (s *Server) updateObject(r *http.Request) jsonResponse {
}

var payload struct {
Metadata map[string]string `json:"metadata"`
CustomTime string
Acl []acls
Metadata map[string]string `json:"metadata"`
ContentType string `json:"contentType"`
CustomTime string
Acl []acls
}
err := json.NewDecoder(r.Body).Decode(&payload)
if err != nil {
Expand All @@ -1012,7 +1013,7 @@ func (s *Server) updateObject(r *http.Request) jsonResponse {

attrsToUpdate.Metadata = payload.Metadata
attrsToUpdate.CustomTime = payload.CustomTime

attrsToUpdate.ContentType = payload.ContentType
if len(payload.Acl) > 0 {
attrsToUpdate.ACL = []storage.ACLRule{}
for _, aclData := range payload.Acl {
Expand Down
51 changes: 51 additions & 0 deletions fakestorage/object_test.go
Expand Up @@ -1669,6 +1669,57 @@ func TestServerClientObjectUpdateCustomTime(t *testing.T) {
})
}

func TestServerClientObjectUpdateContentType(t *testing.T) {
const (
bucketName = "some-bucket"
objectName = "data.txt"
content = "some nice content"
contentType = "some content-type"
)
objs := []Object{
{
ObjectAttrs: ObjectAttrs{
BucketName: bucketName,
Name: objectName,
ContentType: contentType,
},
Content: []byte(content),
},
}
url := fmt.Sprintf("https://storage.googleapis.com/storage/v1/b/%s/o/%s", bucketName, objectName)
runServersTest(t, runServersOptions{objs: objs}, func(t *testing.T, server *Server) {
client := server.HTTPClient()
jsonBody := []byte(`{"ContentType": "another content-type"}`)
bodyReader := bytes.NewReader(jsonBody)
req, err := http.NewRequest(http.MethodPost, url, bodyReader)
if err != nil {
t.Fatal(err)
}
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("wrong status returned\nwant %d\ngot %d", http.StatusOK, resp.StatusCode)
}
data, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
var respJsonBody ObjectAttrs
err = json.Unmarshal(data, &respJsonBody)
if err != nil {
t.Fatal(err)
}
updatedContentType := respJsonBody.ContentType
expectedContentType := "another content-type"
if updatedContentType != expectedContentType {
t.Errorf("unexpected content type time\nwant %q\ngot %q", expectedContentType, updatedContentType)
}
})
}

func TestServerClientObjectPatchCustomTime(t *testing.T) {
const (
bucketName = "some-bucket"
Expand Down
7 changes: 6 additions & 1 deletion fakestorage/upload.go
Expand Up @@ -485,7 +485,12 @@ func (s *Server) uploadFileContent(r *http.Request) jsonResponse {
obj.Crc32c = checksum.EncodedCrc32cChecksum(obj.Content)
obj.Md5Hash = checksum.EncodedMd5Hash(obj.Content)
obj.Etag = fmt.Sprintf("%q", obj.Md5Hash)
obj.ContentType = r.Header.Get(contentTypeHeader)
contentTypeHeader := r.Header.Get(contentTypeHeader)
if contentTypeHeader != "" {
obj.ContentType = contentTypeHeader
} else {
obj.ContentType = "application/octet-stream"
}
responseHeader := make(http.Header)
if contentRange := r.Header.Get("Content-Range"); contentRange != "" {
parsed, err := parseContentRange(contentRange)
Expand Down

0 comments on commit e2d2de1

Please sign in to comment.