Object use cases#

The section provides additional information about using objects in Cloud Files.

Chunked transfer encoding#

You can upload data without knowing in advance the amount of data to be uploaded. You can do this by specifying the HTTP header Transfer-Encoding: chunked and not using a Content-Length header. A good use of this feature would be performing a database dump, piping the output to gzip, and then piping the gzip file directly to Cloud Files without writing the data to disk to compute the file size. If you attempt to upload more than 5 GB, the server closes the connection and removes the previously sent data from the system. You must ensure that the data that you transfer is less than 5 GB or split it into 5 GB chunks, each in its own storage object.

If you have files that are larger than 5 GB and you want to use Cloud Files, you can segment the files before you upload them, upload them to the same container, and then use a manifest file to allow downloading of a concatenated object that contains all the segmented objects. For more information, see Creating large objects.

Example: Upload unspecified quantity of data: HTTP request

PUT /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer/MyObject HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
Transfer-Encoding: chunked
X-Object-Meta-PIN: 1234

Example: Upload unspecified quantity of data response

19
A bunch of data broken up
D
into chunks.
0

Creating large objects#

The content of an object cannot be larger than 5 GB, by default. However, you can store a larger amount of content by using the following types of objects:

  • Segment objects: You divide your content into pieces and upload each piece into its own object, which is a segment object.

  • Manifest objects: You create a manifest object that “points to” the segment objects.

Segment objects do not have any special features and can be created, updated, downloaded, and deleted. However, a manifest object is special—when you download, the system concatenates the contents of the segment objects and returns the concatenation in the response body of the request. This behavior extends to the response headers returned by GET and HEAD operations. The value of the Content-Length header is the total size of all segment objects, and the value of the ETag header is calculated by taking the ETag value of each segment, concatenating them together, and then returning the MD5 checksum of the result.

Note

If you use a manifest object as the source in a COPY operation, the new object is a “normal” object (not segmented). If the total size of the source segment objects exceeds 5 GB, the COPY operation fails. However, you can make a duplicate of the manifest object. This new object can be larger than 5 GB.

Following are the types of manifest objects:

  • Dynamic large objects: The manifest object has no content. However, it has the X-Object-Manifest metadata header. The value of this header is container/prefix, where container is the name of the container where the segment objects are stored and prefix is a string that all the segment objects have in common.

  • Static large objects: The manifest object content is an ordered list of the names of the segment objects in JSON format.

Although both types of manifest objects have similar behavior, there are differences as explained in the following table.

Table: Comparison of static and dynamic large objects

Feature

Static large object

Dynamic large object

End-to-end integrity

Assured. The list of segments includes the MD5 checksum (ETag) of each segment. You cannot upload the manifest object if the ETag in the list differs from the segment object already uploaded. If a segment is somehow lost, an attempt to download the manifest object results in an error.

Not assured. The eventual consistency model means that although you have uploaded a segment object, it might not appear in the container list immediately. If you download the manifest before the object appears in the container, the object will not be part of the content returned in response to a GET request.

Upload order

The segment objects must be uploaded before the manifest object.

You can upload manifest and segment objects in any order. We recommend that you upload the manifest object after the segments in case a premature download of the manifest occurs. However, this is not enforced.

Removal or addition of segment objects

You cannot add or remove segment objects from the manifest. However, you can create a completely new manifest object of the same name with a different manifest list.

You can upload new segment objects or remove existing segments—the names must simply match the <prefix> supplied in the X-Object-Manifest header.

Segment object size and number

Segment objects must be at least 1 MB in size, by default. The final segment object can be any size. By default, a maximum of 1000 segments are supported.

Segment objects can be of any size.

Segment object container name

The manifest list includes the container name of each object (that is, segment objects might be in different containers).

All segment objects must be in the same container.

Manifest object metadata

The object has the X-Static-Large-Object

metadata header set to True. You do not set this metadata directly. Instead the system sets it when you use a PUT operation on a static manifest object.

The X-Object-Manifest header value is container/ prefix indicating where the segment objects are located. You supply this request header in the PUT operation.

Making a copy of the manifest object

To make a copy of the manifest object, include the ?multipart-manifest=get query string with the COPY operation. The new object contains the same manifest as the original. The segment objects are not copied. Instead, both the original and new manifest objects share the same set of segment objects.

The COPY operation does not create a manifest object. To duplicate a manifest object, use the GET operation to read the value of X-Object-Manifest and use this value in the X-Object-Manifest request header in a PUT operation. This creates a new manifest object that shares the same set of segment objects as the original manifest object.

Creating a dynamic large object#

Objects that are larger than 5 GB must be segmented into smaller segment objects before you upload them. You then upload the segment objects as you would any other object. You create a manifest object that tells Cloud Files how to find the segments that make up the large object. The segments remain individually addressable, but retrieving the manifest object streams all the segments, concatenated. There is no limit to the number of segments that can be a part of a single large object. Dynamic large objects rely on the eventual consistency model.

Note

In this context, the eventual consistency model means that although you have uploaded a segment object, it might not appear in the container list immediately. If you download the manifest before the segment object appears in the container, the object will not be part of the content returned in response to a GET request.

To ensure that the download works correctly, you must upload all the object segments to the same container and ensure that each object name is prefixed in such a way that the names sort in the order in which they should be concatenated. You also create and upload a manifest file. The manifest file is simply a zero-byte file with the extra X-Object-Manifest: container/prefix header, where container is the container that the object segments are in and prefix is the common prefix for all the segments. The container and common prefix must be UTF-8 encoded and URL-encoded in the X-Object-Manifest header.

It is best to upload all the segments first and then create or update the manifest. With this method, the full object will not be available for downloading until the upload is complete. Also, you can upload a new set of segments to a second location and then update the manifest to point to this new location. During the upload of the new segments, the original manifest will still be available to download the first set of segments.

Note

The segments are deletable by the user at any time. If a segment is deleted by mistake, a dynamic large object, having no way of knowing the segment was ever there, ignores the deleted file, and the user is returned an incomplete file.

The following examples show how to upload a segment of a large object, the next segment of a large object, and the manifest.

Example: Upload a segment of a large object: HTTP request

PUT /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer/MyObject HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
ETag: 8a964ee2a5e88be344f36c22562a6486
Content-Length: 1

No response body is returned. A status code of 201 (Created) indicates a successful write. Status code 411 (Length Required) indicates that the Content-Length header is missing. If the MD5 checksum calculated by the storage system does not match the optionally supplied ETag value, a 422 (Unprocessable Entity) status code is returned.

You can continue uploading segments as this example shows, prior to uploading the manifest.

Example: Upload the next segment of the large object : HTTP request

PUT /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer/MyObject HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
ETag: 8a964ee2a5e88be344f36c22562a6486
Content-Length: 1

Next, upload the manifest that you created that indicates the container in which the object segments reside. Note that uploading additional segments after the manifest is created causes the concatenated object to be that much larger, but you do not need to re-create the manifest file for subsequent additional segments.

Example: Upload manifest: HTTP request

PUT /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer/MyObject HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
Content-Length: 0
X-Object-Manifest: container/prefix/object/segments

Example: Upload manifest response

[...]

A GET request to the manifest object returns the concatenation of the objects from the manifest.

When you perform a GET or HEAD request on the manifest, the response’s Content-Type is the same as the Content-Type that was set during the PUT request that created the manifest. You can easily change the Content-Type by reissuing the PUT request.

Note

The ETag in the response for a GET or HEAD on the manifest file is the MD5 sum of the concatenated string of ETags for each of the segments in the manifest. Usually, the ETag is the MD5 sum of the contents of the object, and that holds true for each segment independently. But it is not meaningful to generate such an ETag for the manifest itself, so this method was chosen to at least offer change detection.

Creating a static large object#

Static large object (SLO) support is similar to dynamic large object (DLO) support because it enables you to upload many objects concurrently and later download them as a single object. However, unlike dynamic large object support, static large object support does not rely on the eventual consistency model for the container listings. Instead, static large object support uses a user-defined manifest of the object segments.

The benefits of using static large objects are as follows:

  • The objects that are uploaded and downloaded can be in different containers, which can improve performance.

  • There is an explicit list of segments, instead of an implied list as with dynamic large objects.

You create a static large object by performing the following steps:

  1. Divide your content into pieces and create (upload) a segment object to contain each piece. You must record the ETag response header returned by the PUT operation. Alternatively, you can calculate the MD5 checksum of the segment prior to uploading and include this in the ETag request header. Doing so ensures that the upload cannot corrupt your data. For detailed information, see Uploading the segments.

    The maximum number of segment objects per static large object is 1,000. Each segment, except for the final one, must be at least 1 MB.

  2. Create a manifest object by listing the name of each segment object along with its size and MD5 checksum, in order. You indicate that this is a manifest object by including the ?multipart-manifest=put query string at the end of the manifest object name. For detailed information, see Uploading the manifest.

Uploading the segments#

Upload your segment objects. All the segments, except the last one, need to be larger than 1 MB (1048576 bytes). It might help organizationally to keep them in the same container, but it is not required. You need the following information about each segment for the next step, uploading the manifest object:

  • path – The container and object name in the following format: containerName/objectName

  • etag – The ETag header from the successful 201 response of the PUT operation that uploaded the segment. This is the MD5 checksum of the segment object’s data.

  • size_bytes – The segment object’s size in bytes. This value must match the Content-Length of that object.

Uploading the manifest#

After you have uploaded the objects to be concatenated, you upload a manifest object. The request must use the PUT operation, with the following query parameter at the end of the manifest object name:

?multipart-manifest=put

The body of the PUT operation is an ordered list of files in JSON data format. The data to be supplied for each segment is as follows:

  • path – The container and object name in the following format: containerName/objectName

  • etag – The ETag header from the successful 201 response of the PUT operation that uploaded the segment. This is the MD5 checksum of the segment object’s data.

  • size_bytes – The segment object’s size in bytes. This value must match the Content-Length of that object.

Following is an example containing three segment objects. This example illustrates that in contrast to dynamic large objects, you can use a number of containers and the object names do not have to conform to a specific pattern.

Example: Static large object manifest list

[
        {
          "path": "/mycontainer/objseg1",
          "etag": "0228c7926b8b642dfb29554cd1f00963",
          "size_bytes": 1468006
        },
        {
          "path": "/mycontainer/pseudodir/seg-obj2",
          "etag": "5bfc9ea51a00b790717eeb934fb77b9b",
          "size_bytes": 1572864
        },
        {
          "path": "/other-container/seg-final",
          "etag": "b9c3da507d2557c1ddc51f27c54bae51",
          "size_bytes": 256
        }
]

The Content-Length request header must contain the length of the JSON content, not the length of the segment objects. However, after the PUT operation is complete, the Content-Length metadata is set to the total length of all the object segments. A similar situation applies to the ETag header. If it is used in the PUT operation, it must contain the MD5 checksum of the JSON content. The ETag metadata value is then set to be the MD5 checksum of the concatenated ETag values of the object segments. You can also set the Content-Type request header and custom object metadata.

When the PUT operation sees the ?multipart-manifest=put query string, it reads the request body and verifies that each segment object exists and that the sizes and ETags match. If there is a mismatch, the PUT operation fails.

When you upload the manifest object, the middleware reads every segment passed in and verifies the size and ETag of each. If any of the objects do not match (for example, an object is not found, the size or ETag is mismatched, or the minimum size is not met), or if everything does match and a manifest object is created, Cloud Files issues a response code. The response codes are the same as those issued for the create or update object operation (see “Create or update object”).

When Cloud Files creates the manifest object, Cloud Files sets the X-Static-Large-Object metadata header to True, indicating that this is a static object manifest.

When the manifest object is uploaded, you can be generally assured that every segment in the manifest exists and that it matches the specifications. However, nothing prevents a user from breaking the static large object download by deleting or replacing a segment that is referenced in the manifest. Users should use caution when handling the segments.

The order of the segments listed in the manifest determines the order in which the segments are concatenated when downloaded. The manifest can reference objects in separate containers, which improves concurrent upload speed. A single object can be referenced by multiple manifests.

Retrieving a large object#

A GET request to the manifest object returns the concatenated content of the segment objects listed in the manifest. If any of the segments from the manifest are not found or their ETag or Content-Length values no longer match, the GET operation fails and you receive partial results (up to the point of the failure due to not matching). As a result, a 409 (Conflict) status code is logged.

The headers from the GET or HEAD request return metadata for the manifest object as follows:

  • Content-Length: The total size of the static large object (the sum of the sizes of the segments in the manifest)

  • X-Static-Large-Object: True

  • ETag: The ETag of the static large object (generated the same way as a dynamic large object)

The GET request with the following query parameter returns the actual manifest file contents:

?multipart-manifest=get

The response body contains generated JSON. The resulting list is not identically formatted like the manifest that you originally used in the PUT operation (?multipart-manifest=put).

The main purpose of the GET or HEAD operation is for debugging.

Deleting a large object#

If you use the DELETE operation on a manifest object, the manifest object is deleted. The segment objects are not affected.

However, if you add the ?multipart-manifest=delete query parameter, the segment objects are deleted, and if all are successfully deleted, the manifest object is also deleted.

Modifying a large object#

PUT and POST operations work as follows:

  • A PUT operation overwrites the manifest object (and leaves the segments alone).

  • A POST operation changes the manifest file’s metadata and contents, as with any other object.

Listing containers with static large objects#

In a list of containers, the size listed for a static large object manifest object is the total size of the concatenated segments in the manifest, not the size of the manifest file itself. The overall X-Container-Bytes-Used for the container (and for the account) does not reflect the total size of the manifest, but the actual size of the stored JSON data. This enables you to see the total size of the static large object in a container list, but does not inflate the bytes used for the container or the account.

Enabling file compression#

The Content-Encoding header allows a file to be compressed while still preserving the identity of the underlying media type of the file, for example, a video.

The object must be compressed before it is uploaded. Cloud Files does not perform any automatic compression. The Content-Encoding header enables the client to set the metadata appropriately.

Note

The Rackspace CDN provider, Akamai, encodes HTML, JavaScript, and CSS files in gzip format. However, in your Cloud Files account, your files are not encoded. For more information, see the blog post Cloud Files CDN Compresses at the Edge. Compressing these objects helps lower costs and increases download speeds.

In the following example, the Content-Encoding header indicates the type of encoding used on the data.

Example: Content-Encoding: HTTP request

PUT /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
Content-Type: video/mp4
Content-Encoding: gzip

Enabling bypass of browser behavior#

When an object is assigned the Content-Disposition header, you can override a browser’s default behavior for a file so that the browser prompts to save the file rather than displaying it by using default browser settings.

In the following example, the Content-Disposition header is assigned with an attachment type that indicates how the file should be downloaded.

Example: Content-Disposition: HTTP request

PUT /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer/MyObject HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
Content-Type: image/tiff
Content-Disposition: attachment; filename=platmap.tif

Expiring objects#

When you perform a PUT or POST operation on an object and assign it either an X-Delete-After or X-Delete-At header, the object is scheduled for deletion. This feature is helpful for objects that you do not want to permanently store, such as log files, recurring full backups of a dataset, or documents or images that you know will be outdated at a future time.

Objects that are assigned the X-Delete-At or X-Delete-After header are deleted within one day of the expiration time, and the object stops being served immediately after the expiration time.

The X-Delete-At header requires a UNIX epoch timestamp, in integer form. For example, 1348691905 represents Wed, 26 Sep 2012 20:38:25 GMT. By setting the header to a specific epoch time, you indicate when you want the object to expire, not be served, and be deleted completely from the storage system.

The X-Delete-After header takes an integer number of seconds that represents the amount of time from now when you want the object to be deleted. The proxy server that receives the request converts this header into an X-Delete-At header and calculates the deletion time using its current time plus the value given in seconds.

To assign expiration headers to existing objects, use the POST operation.

In the following example, the X-Delete-At header is assigned with a UNIX epoch timestamp in integer form for Mon, 11 Jun 2012 15:38:25 GMT. For example timestamps and a batch converter, go to http://www.epochconverter.com/.

Example: X-Delete-At: HTTP request

PUT /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer/MyObject HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
Content-Type: image/jpeg
X-Delete-At: 1339429105

In the following example, the X-Delete-After header is assigned a value in seconds, equivalent to 10 days. After this time, the object expires.

Example: X-Delete-After: HTTP request

PUT /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer/MyObject HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
Content-Type: image/jpeg
X-Delete-After: 864000

Object versioning#

Object versioning enables you to store multiple versions of your content so that you can recover from unintended overwrites and deletions. It provides an easy way to implement version control that can be used on any type of content.

We strongly recommends that you put non-current objects in a separate container from the current versions of objects. After you enable object versioning, new data written to an object causes the last-current version to be written to the separate container. Each of the non-current versions has a timestamp appended to it, so you know when it was originally created.

To enable object versioning, you perform the following steps:

  1. Create a container where your non-current versions will be written.

  2. On the container that holds the current versions of your objects, set the X-Versions-Location metadata header to point to the new non-current version container that you created.

After you complete these steps, versioning is enabled on each object in your current-version container. Changes to the objects automatically create non-current versions in the separate container.

Nothing is written to the non-current version container when you initially use a PUT operation to add an object into the current-version container. You create non-current versions only when you edit existing objects with a PUT request. These non-current versions are labeled according to the following schema:

{length}{objectName}/{time stamp}

Where {length} is the 3-character zero-padded hexadecimal character length of the {objectName}, and {timestamp} indicates when the object was originally created as a current version.

Any return status in the 2nn range, such as 202 (Accepted), denotes success. Status codes in the 4nn or 5nn range denote failure. If you receive an error, you should retry your request. Note, however, that if you specify a container that does not exist as your non-current version container, a status of 412 (Precondition Failed) is returned when you edit the versioned object. If you receive this error, verify that the container exists.

When object versioning is enabled, requests on objects behave as follows:

  • A GET request to a versioned object returns the current version of the object, with no request redirects or metadata lookups required.

  • A POST request to a versioned object updates only the current version of the object’s metadata. It does not create a new version of the object. New versions are created when the content of the object changes.

  • A DELETE request to a versioned object removes the current version of the object and replaces it with the most recent non-current version, moving it from the non-current container to the current container. This most recent non-current version carries with it any metadata last set on it. If you want to completely remove an object and you have five total versions of it, you must perform five DELETE operations on it.

Note

A large-object manifest file cannot be versioned, but it can point to versioned segments.

To turn off object versioning on your current version container, remove its X-Versions-Location metadata by sending a key value that is an empty string.

Example: Object versioning with cURL

  1. Create a version-storing container named versions.

    curl -i -XPUT -H "X-Auth-Token: yourAuthToken" http://yourStorageUrl/versions
    
  2. Create a container named current with a X-Versions-Location header that references versions.

    curl -i -XPUT -H "X-Auth-Token: yourAuthToken" \
    -H "X-Versions-Location: versions" http://yourStorageUrl/current
    
  3. Create an object (the first version).

    curl -i -XPUT --data-binary 1 -H "X-Auth-Token: yourAuthToken" \
        http://yourStorageUrl/current/myobject
    
  4. Create a new version of that object.

    curl -i -XPUT --data-binary 2 -H "X-Auth-Token: yourAuthToken" \
        http://yourStorageUrl}/current/myobject
    
  5. See a list of the older versions of the object. (The example includes the hexadecimal number for the length of the file name.)

    curl -i -H "X-Auth-Token: yourAuthToken" \
        http://yourStorageUrl/versions?prefix=008myobject/
    
  6. Delete the current version of the object and see that the older version is no longer in the versions container.

    curl -i -XDELETE -H "X-Auth-Token: yourAuthToken" \
        http://yourStorageUrl>/current/myobject
    curl -i -H "X-Auth-Token: yourAuthToken " \
        http://yourStorageUrl/versions?prefix=008myobject/
    

Account to account copy#

The account to account copy capability adds the ability to copy objects between different accounts on the server.

To use this capability to read from or write to the accounts, you must have a access to the containers. You can use a container access control list (ACL) to control access to a container and its objects.

Use the following operations and headers to perform an account to account copy:

  • A COPY command with the following headers:

    • Destination-Account: Specifies the account name (which corresponds to the last part of the storage URL).

    • Destination: Used with COPY, specifies the container and object name of the destination object in the form of /container/object.

  • A PUT command with the following headers:

    • X-Copy-From-Account: Specifies the account name (which corresponds to the last part of storage URL).

    • X-Copy-From: Used with PUT, specifies the container and object name of the source object in the form of /container/object.

Note

If your storage URL is https://storage101.dfw1.clouddrive.com/v1/ MossoCloudFS_aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee, your account name is MossoCloudFS_aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee.

Use the following examples to complete the steps to use account to account copy.

COPY command steps

  1. Use the POST command to set X-Container-Write metadata on the destination container.

    Request:

    POST /v1/Destination_Account/Destination_Container HTTP/1.1
    Host: storage.clouddrive.com
    X-Auth-Token: Destination_User_Auth_Token
    X-Container-Write: Source_User_Name
    

    Response:

    204 No Content
    Content-Length: 0
    Content-Type: text/html; charset=UTF-8
    X-Trans-Id: tx1abc1d6005134be99b1db-0054da619adev1
    Date: Tue, 10 Feb 2015 19:52:58 GMT
    
  2. Use the COPY command to copy the object.

    Request:

    COPY /v1/Source_Account/Source_Destination/Source_Object HTTP/1.1
    Host: storage.clouddrive.com
    X-Auth-Token: Source_User_Auth_Token
    Destination: Destination_Container/Destination_Object
    Destination-Account: Destination_User_Account   (such as, MossoCloudFS_aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee)
    

    Response:

    201 Created
    Content-Length: 0
    X-Copied-From-Last-Modified: Tue, 13 Jan 2015 20:53:09 GMT
    X-Copied-From: copy_test/new_copy_object.txt
    Last-Modified: Tue, 10 Feb 2015 19:59:49 GMT
    Etag: c6995201745ed71f24ba352750bde444
    X-Copied-From-Account: StagingUS_xxxxxxxx-yyyy-zzzz-aaaa-bbbbbbbbbbbb
    Content-Type: text/html; charset=UTF-8
    X-Trans-Id: txd819a3f557de449cb0879-0054da6334dev1
    Date: Tue, 10 Feb 2015 19:59:48 GMT
    

PUT command steps

  1. Use the POST command to set X-Container-Write metadata on destination container.

    Request:

    POST  /v1/Destination_Account/Destination_Container HTTP/1.1
    Host: storage.clouddrive.com
    X-Auth-Token: Destination_User_Auth_Token
    X-Container-Write: Source_User_Name
    

    Response:

    204 No Content
    Content-Length: 0
    Content-Type: text/html; charset=UTF-8
    X-Trans-Id: tx0f6c102033564bb0800e3-0054da677fdev1
    Date: Tue, 10 Feb 2015 20:18:07 GMT
    
  2. Use the PUT command to copy the object.

    Request:

    PUT  /v1/Destination_Account/Dest_Container/Dest_Object HTTP/1.1
    Host: storage.clouddrive.com
    X-Auth-Token: Source_User_Auth_Token
    X-Copy-From: /source_container/source_object
    X-Copy-From-Account: Source_User_Account   (such as, MossoCloudFS_aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee)
    Content-Length: 0      (the actual value is ignored)
    

    Response:

    201 Created
    Content-Length: 0
    X-Copied-From-Last-Modified: Tue, 10 Feb 2015 20:46:32 GMT
    X-Copied-From: source/source_object.txt
    Last-Modified: Tue, 10 Feb 2015 21:14:50 GMT
    Etag: d41d8cd98f00b204e9800998ecf8427e
    X-Copied-From-Account: StagingUS_xxxxxxxx-yyyy-zzzz-aaaa-bbbbbbbbbbbb
    Content-Type: text/html; charset=UTF-8
    X-Trans-Id: txe3373a175f944020a63d9-0054da74c9dev1
    Date: Tue, 10 Feb 2015 21:14:49 GMT