Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new CopyObject API in Core client #836

Merged
merged 1 commit into from
Oct 2, 2017

Conversation

harshavardhana
Copy link
Member

This PR also fixes the problem of PutObject
call not handling additional headers.

Refer original problem here minio/minio#5000

core.go Outdated
return c.putObjectDo(context.Background(), bucket, object, data, md5Sum, sha256Sum, size, PutObjectOptions{UserMetadata: metadata})
delKey := func(m map[string]string, key string) {
delete(m, strings.ToLower(key))
delete(m, strings.ToUpper(key))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will miss key in mixed-case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you give me an example?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

example - if "Content-Type" is a key in the metadata map, the above code will not delete the entry.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops yeah i should have used http.CanonicalHeaderKey()

core.go Outdated
if v := getKeyValue(metadata, "content-encoding"); v != "" {
opts.ContentEncoding = v
delKey(metadata, "content-encoding")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opts := PutObjectOptions{}
m := make(map[string]string)
for k, v := range metadata {
	if strings.ToLower(k) == "content-encoding" {
		opts.ContentEncoding = v
	} else if strings.ToLower(k) == "content-disposition" {
		opts.ContentDisposition = v
	} else if strings.ToLower(k) == "content-type" {
		opts.ContentType = v
	} else if strings.ToLower(k) == "cache-control" {
		opts.CacheControl = v
	} else {
		m[k] = metadata[k]
	}
}
opts.UserMetadata = m

this would be more concise

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense..

// CopyObject - copies an object from source object to destination object on server side.
func (c Core) CopyObject(sourceBucket, sourceObject, destBucket, destObject string, metadata map[string]string) (ObjectInfo, error) {
return c.copyObjectDo(context.Background(), sourceBucket, sourceObject, destBucket, destObject, metadata)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

This PR also fixes the problem of PutObject
call not handling additional headers.

Refer original problem here minio/minio#5000
@donatello
Copy link
Member

donatello commented Oct 2, 2017

Sorry to come in late on this. The bug identified minio/minio#5000 (comment) can be fixed properly in ComposeObject().

Particularly, this part https://github.com/minio/minio-go/blob/master/api-compose-object.go#L110-L122 needs to be fixed to handle the standard headers (like Content-Encoding, etc). IIUC, then this PR is not needed (except perhaps to fix PutObject)?

@harshavardhana
Copy link
Member Author

Sorry to come in late on this. The bug identified minio/minio#5000 (comment) can be fixed properly in ComposeObject().

Particularly, this part https://github.com/minio/minio-go/blob/master/api-compose-object.go#L110-L122 needs to be fixed to handle the standard headers (like Content-Encoding, etc). IIUC, then this PR is not needed (except perhaps to fix PutObject)?

No we need to add a simpler version @donatello - we shouldn't use ComposeObject IMHO. Which uses multipart API underneath.

@donatello
Copy link
Member

No we need to add a simpler version @donatello - we shouldn't use ComposeObject IMHO. Which uses multipart API underneath.

@harshavardhana Got it, you're right. ComposeObject would also do a HEAD, which is not desirable in gateway mode where we do expect it to be a one-to-one API mapping.

@@ -128,7 +128,7 @@ type initiator struct {
// copyObjectResult container for copy object response.
type copyObjectResult struct {
ETag string
LastModified string // time string format "2006-01-02T15:04:05.000Z"
LastModified time.Time // time string format "2006-01-02T15:04:05.000Z"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would xmlDecoder() know the format (time layout) with which to parse the time? I am not sure the decoding will be correct as is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is the feature of xml Marshal @donatello also we need to have typed value.

Copy link
Member Author

@harshavardhana harshavardhana Oct 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example look at all the List() APIs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@harshavardhana - xml decoder is using a particular format within the ISO8601 standard by default to parse timestamps. Looks like by dumb luck AWS is using the same format!

opts.ContentType = v
} else if strings.ToLower(k) == "cache-control" {
opts.CacheControl = v
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two headers seem to be missing from this list - content-length and content-md5 according to https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is set internally @donatello

// Set all the metadata headers.
for k, v := range metadata {
headers.Set(k, v)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For metadata replacement to actually happen we need to make sure the x-amz-metadata-directive header is set to REPLACE. Perhaps we should throw an error if metadata is non-empty and this header is not set?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right let me do that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually we don't need to.. there is no error @donatello according to CopyObject() if REPLACE is set then the set metadata is honored, otherwise it does copy from the source object by default. So we don't need to error out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes. It is not needed, as AWS behaviour is also to silently ignore the headers without the directive header.

@deekoder deekoder merged commit 9690dc6 into minio:master Oct 2, 2017
@harshavardhana harshavardhana deleted the fix-copy-object branch October 2, 2017 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants