1/*
2 * Minio Go Library for Amazon S3 Compatible Cloud Storage
3 * Copyright 2017, 2018 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
18package minio
19
20import (
21	"context"
22	"io"
23	"io/ioutil"
24	"net/http"
25
26	"github.com/minio/minio-go/pkg/encrypt"
27)
28
29// CopyObject - copy a source object into a new object
30func (c Client) CopyObject(dst DestinationInfo, src SourceInfo) error {
31	return c.CopyObjectWithProgress(dst, src, nil)
32}
33
34// CopyObjectWithProgress - copy a source object into a new object, optionally takes
35// progress bar input to notify current progress.
36func (c Client) CopyObjectWithProgress(dst DestinationInfo, src SourceInfo, progress io.Reader) error {
37	header := make(http.Header)
38	for k, v := range src.Headers {
39		header[k] = v
40	}
41
42	var err error
43	var size int64
44	// If progress bar is specified, size should be requested as well initiate a StatObject request.
45	if progress != nil {
46		size, _, _, err = src.getProps(c)
47		if err != nil {
48			return err
49		}
50	}
51
52	if src.encryption != nil {
53		encrypt.SSECopy(src.encryption).Marshal(header)
54	}
55
56	if dst.encryption != nil {
57		dst.encryption.Marshal(header)
58	}
59	for k, v := range dst.getUserMetaHeadersMap(true) {
60		header.Set(k, v)
61	}
62
63	resp, err := c.executeMethod(context.Background(), "PUT", requestMetadata{
64		bucketName:   dst.bucket,
65		objectName:   dst.object,
66		customHeader: header,
67	})
68	if err != nil {
69		return err
70	}
71	defer closeResponse(resp)
72
73	if resp.StatusCode != http.StatusOK {
74		return httpRespToErrorResponse(resp, dst.bucket, dst.object)
75	}
76
77	// Update the progress properly after successful copy.
78	if progress != nil {
79		io.CopyN(ioutil.Discard, progress, size)
80	}
81
82	return nil
83}
84