Beispiel #1
0
// This multipart upload operation uploads a part of an archive.You can upload
// archive parts in any order because in your Upload Part request you specify
// the range of bytes in the assembled archive that will be uploaded in this
// part.You can also upload these parts in parallel.You can upload up to 10,000
// parts for a multipart upload.
//
// Amazon Glacier rejects your upload part request if any of the following
// conditions is true:
// * SHA256 tree hash does not match—To ensure that part data is not corrupted
// in transmission, you compute a SHA256 tree hash of the part and include it in
// your request. Upon receiving the part data, Amazon Glacier also computes a
// SHA256 tree hash. If the two hash values don't match, the operation fails.
// * Part size does not match—The size of each part except the last must match
// the size that is specified in the corresponding Initiate Multipart Upload.
// The size of the last part must be the same size as, or smaller than, the
// specified size. Note: If you upload a part whose size is smaller than the
// part size you specified in your initiate multipart upload request and that
// part is not the last part, then the upload part request will succeed.
// However, the subsequent Complete Multipart Upload request will fail.
// * Range does not align—The byte range value in the request does not align
// with the part size specified in the corresponding initiate request. For
// example, if you specify a part size of 4194304 bytes (4 MB), then 0 to
// 4194303 bytes (4 MB —1) and 4194304 (4 MB) to 8388607 (8 MB —1) are valid
// part ranges. However, if you set a range value of 2 MB to 6 MB, the range
// does not align with the part size and the upload will fail.
//
// This operation is idempotent. If you upload the same part multiple times, the
// data included in the most recent request overwrites the previously uploaded
// data.
func (c *Connection) UploadMultipart(vault, uploadId string, start int64, body io.ReadSeeker) error {
	// TODO check that data size and start location make sense

	// Build request.
	request, err := http.NewRequest("PUT", "https://"+c.Signature.Region.Glacier+"/-/vaults/"+vault+
		"/multipart-uploads/"+uploadId, body)
	if err != nil {
		return err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	th := NewTreeHash()
	n, err := io.Copy(th, body)
	if err != nil {
		return err
	}
	th.Close()

	_, err = body.Seek(0, 0)
	if err != nil {
		return err
	}

	hash := th.Hash()

	request.Header.Add("x-amz-content-sha256", toHex(hash))
	request.Header.Add("x-amz-sha256-tree-hash", toHex(th.TreeHash()))
	request.Header.Add("Content-Range", fmt.Sprintf("bytes %d-%d/*", start, start+n-1))
	request.ContentLength = n

	c.Signature.Sign(request, aws.HashedPayload(hash))

	// Perform request.
	response, err := c.client().Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusNoContent {
		return aws.ParseError(response)
	}

	io.Copy(ioutil.Discard, response.Body)

	// Parse success response.
	return nil
}
Beispiel #2
0
// Upload archive to vault with optional description. The entire archive will
// be read in order to create its tree hash before uploading.
//
// Returns the archive ID or the first error encountered.
func (c *Connection) UploadArchive(vault string, archive io.ReadSeeker, description string) (string, error) {
	// Build reuest.
	request, err := http.NewRequest("POST", c.vault(vault)+"/archives",
		archive)
	if err != nil {
		return "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")

	th := NewTreeHash()
	request.ContentLength, err = io.Copy(th, archive)
	if err != nil {
		return "", err
	}
	th.Close()

	_, err = archive.Seek(0, 0)
	if err != nil {
		return "", err
	}

	hash := th.Hash()

	request.Header.Add("x-amz-archive-description", description)
	request.Header.Add("x-amz-sha256-tree-hash", toHex(th.TreeHash()))
	request.Header.Add("x-amz-content-sha256", toHex(hash))

	c.Signature.Sign(request, aws.HashedPayload(hash))

	// Perform request.
	response, err := c.client().Do(request)
	if err != nil {
		return "", err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusCreated {
		return "", aws.ParseError(response)
	}

	io.Copy(ioutil.Discard, response.Body)

	// Parse success response.
	_, location := path.Split(response.Header.Get("Location"))
	return location, nil
}