
Copy content from http://docs.openstack.org/developer/swift/cors.html to replace misleading content in http://docs.openstack.org/api/openstack-object-storage/1.0/ content/assigning-cors-headers-to-requests.html Change ">" to ">" in example Use $publicURL to represent the endpoint which includes the API version number and the account/tenantID. Closes-Bug: #1260840 Change-Id: I9dfe46d610bfcf2f9646cb28a4246954c180252d
1060 lines
58 KiB
XML
1060 lines
58 KiB
XML
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE section [
|
|
<!-- Some useful entities borrowed from HTML -->
|
|
<!ENTITY ndash "–">
|
|
<!ENTITY mdash "—">
|
|
<!ENTITY hellip "…">
|
|
|
|
<!-- Useful for describing APIs -->
|
|
<!ENTITY COPY '<command xmlns="http://docbook.org/ns/docbook">COPY</command>'>
|
|
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
|
|
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
|
|
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
|
|
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
|
|
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
|
|
]>
|
|
<section xmlns="http://docbook.org/ns/docbook"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
|
|
xml:id="storage-object-services">
|
|
<title>Storage Object Services</title>
|
|
<para>An object represents the data and metadata for the files
|
|
stored in the system. Through the ReST interface, you can
|
|
include metadata for an object by adding custom HTTP headers
|
|
to the request and the data payload as the request body.
|
|
Objects cannot exceed 5 GB and must have names that do not
|
|
exceed 1024 bytes after URL encoding. However, you can segment
|
|
a large object into 5 GB segments and upload the segments.
|
|
Then, you can download the segments as a single concatenated
|
|
object. You can use HTTP requests to work with the segments
|
|
and manifests directly.</para>
|
|
<informaltable rules="all">
|
|
<thead>
|
|
<tr>
|
|
<td colspan="1">Verb</td>
|
|
<td colspan="2">URI</td>
|
|
<td colspan="3">Description</td>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="1">&GET;</td>
|
|
<td colspan="2"
|
|
>/<parameter>account</parameter>/<parameter>container</parameter>/<parameter>object</parameter></td>
|
|
<td colspan="3">Gets object details.</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="1">&PUT;</td>
|
|
<td colspan="2"
|
|
>/<parameter>account</parameter>/<parameter>container</parameter>/<parameter>object</parameter></td>
|
|
<td colspan="3">Creates or updates object.</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="1">&PUT;</td>
|
|
<td colspan="2"
|
|
>/<parameter>account</parameter>/<parameter>container</parameter>/<parameter>object</parameter></td>
|
|
<td colspan="3">Chunked transfer encoding.</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="1">&DELETE;</td>
|
|
<td colspan="2"
|
|
>/<parameter>account</parameter>/<parameter>container</parameter>/<parameter>object</parameter></td>
|
|
<td colspan="3">Deletes a specified object.</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="1">&HEAD;</td>
|
|
<td colspan="2"
|
|
>/<parameter>account</parameter>/<parameter>container</parameter>/<parameter>object</parameter></td>
|
|
<td colspan="3">Gets object metadata.</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="1">&POST;</td>
|
|
<td colspan="2"
|
|
>/<parameter>account</parameter>/<parameter>container</parameter>/<parameter>object</parameter></td>
|
|
<td colspan="3">Updates object metadata.</td>
|
|
</tr>
|
|
</tbody>
|
|
</informaltable>
|
|
<variablelist>
|
|
<title>Optional headers for HEAD and GET</title>
|
|
<varlistentry>
|
|
<term><code>X-Newest</code></term>
|
|
<listitem>
|
|
<para>Set the optional <code>X-newest</code> header to
|
|
<code>True</code> in HEAD and GET requests to
|
|
have Object Storage return the latest version of
|
|
the object. If set to <code>True</code>, Object
|
|
Storage queries all replicas to return the most
|
|
recent one. Without this header, Object Storage
|
|
responds faster after it finds one valid replica.
|
|
Because setting this header to <code>True</code>
|
|
is more expensive for the back end, use it only
|
|
when it is absolutely needed.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
<section xml:id="retrieve-object">
|
|
<title>Get Object Details</title>
|
|
<para>Perform &GET; operations against an object to get object
|
|
data.</para>
|
|
<para>You can perform conditional &GET; requests by using the
|
|
following HTTP headers in the request:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal>If-Match</literal></para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><literal>If-None-Match</literal></para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><literal>If-Modified-Since</literal></para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><literal>If-Unmodified-Since</literal></para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>These headers are documented in <link
|
|
xlink:href="http://www.ietf.org/rfc/rfc2616.txt"
|
|
>http://www.ietf.org/rfc/rfc2616.txt</link>.</para>
|
|
<para>You can use the HTTP <code>Range</code> header to fetch
|
|
portions of data by using one or more range
|
|
specifications. To specify many ranges, separate the range
|
|
specifications with a comma.</para>
|
|
<para>The types of range specifications are:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><emphasis role="bold">Byte range
|
|
specification</emphasis>. Use
|
|
FIRST_BYTE_OFFSET to specify the start of the data
|
|
range, and LAST_BYTE_OFFSET to specify the end.
|
|
You can omit the LAST_BYTE_OFFSET and if you do,
|
|
the value defaults to the offset of the last byte
|
|
of data.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><emphasis role="bold">Suffix byte range
|
|
specification</emphasis>. Use LENGTH bytes to
|
|
specify the length of the data range.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>The following forms of the header specify the following
|
|
ranges of data:</para>
|
|
<informaltable rules="all">
|
|
<col width="40%"/>
|
|
<col width="60%"/>
|
|
<thead>
|
|
<tr>
|
|
<th>Header</th>
|
|
<th>Range of object data</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>
|
|
<para><code>Range: bytes=-5</code></para></td>
|
|
<td><para>The last five bytes.</para>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><para><code>Range:
|
|
bytes=10-14</code></para></td>
|
|
<td>The five bytes of data after a 10-byte
|
|
offset.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><para><code>Range:
|
|
bytes=10-14,-5</code></para></td>
|
|
<td><para>A multi-part response that contains the five bytes of data after
|
|
a 10-byte offset and the last five
|
|
bytes.</para>
|
|
<para>The <code>Content-Type</code> of the
|
|
response is then
|
|
<code>multipart/byteranges</code>.</para>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<para><code>Range:
|
|
bytes=4-6</code></para></td>
|
|
<td><para>Bytes 4 to 6 inclusive.</para></td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<para><code>Range:
|
|
bytes=2-2</code></para></td>
|
|
<td><para>Byte 2, which is the third byte of the data.</para>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<para><code>Range: bytes=6-</code></para></td>
|
|
<td><para>Byte 6 and after.</para>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<para><code>Range:
|
|
bytes=1-3,2-5</code></para></td>
|
|
<td><para>A multi-part response that contains
|
|
bytes 1 to 3 inclusive, and bytes 2 to 5
|
|
inclusive.</para>
|
|
<para>The <code>Content-Type</code> of the
|
|
response is then
|
|
<code>multipart/byteranges</code>.</para>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</informaltable>
|
|
<example>
|
|
<title>Get Object Details HTTP Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-get-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>The object data is returned in the response body. Object
|
|
metadata is returned as HTTP headers. A status of
|
|
2<replaceable>xx</replaceable> (between 200 and 299,
|
|
inclusive) indicates success; status 404 (Not Found) is
|
|
returned if no such object exists.</para>
|
|
<example>
|
|
<title>Get Object Details HTTP Response</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-get-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>These examples include an object that contains 10 bytes
|
|
of data: <literal>0123456789</literal>.</para>
|
|
<example>
|
|
<title>Get Object Details HTTP Request Using Range</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-get-range-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<example>
|
|
<title>Get Object Details HTTP Response When Using
|
|
Range</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-get-range-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<example>
|
|
<title>Get Object Details HTTP Request Using Multiple
|
|
Ranges</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-get-ranges-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<example>
|
|
<title>Get Object Details HTTP Response When Using
|
|
Multiple Ranges</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-get-ranges-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
</section>
|
|
<section xml:id="create-update-object">
|
|
<title>Create or Update Object</title>
|
|
<para>&PUT; operations are used to write, or overwrite, an
|
|
object's content and metadata.</para>
|
|
<para>You can ensure end-to-end data integrity by including an
|
|
MD5 checksum of your object's data in the ETag header. You
|
|
are not required to include the ETag header, but it is
|
|
recommended to ensure that the storage system successfully
|
|
stored your object's content.</para>
|
|
<para>You can cause an object to expire after a certain date
|
|
by using the <code>X-Delete-At</code> or
|
|
<code>X-Delete-After</code> headers during an object
|
|
&PUT; operation. When Object Storage detects one of these
|
|
headers, the system automatically stops serving that
|
|
object at the specified time and shortly after the
|
|
expiration date, it removes the object from the storage
|
|
system.</para>
|
|
<para>The HTTP response will include the MD5 checksum of the
|
|
data written to the storage system. If you do not send the
|
|
ETag in the request, you should compare the value returned
|
|
with your content's MD5 locally to perform the end-to-end
|
|
data validation on the client side. For manifest objects,
|
|
the ETag is the MD5 checksum of the concatenated string of
|
|
ETags for each of the segments in the manifest. Refer to
|
|
<link linkend="large-object-creation">Create Large
|
|
Objects</link> for more information.</para>
|
|
<para>Objects can be assigned custom metadata by including
|
|
additional HTTP headers on the &PUT; request.</para>
|
|
<para>The object can be created with custom metadata via HTTP
|
|
headers identified with the <code>X-Object-Meta-</code>
|
|
prefix, or arbitrary headers set with the
|
|
<literal>allowed_headers</literal> option in the
|
|
object-server configuration.</para>
|
|
<example>
|
|
<title>Create or Update Object HTTP Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-create-req.txt" parse="text"/></literallayout>
|
|
<literallayout class="monospaced">[ ... ]</literallayout>
|
|
</example>
|
|
<para>No response body is returned. A status code of 201
|
|
(Created) indicates a successful write; status 411 (Length
|
|
Required) denotes a missing <code>Content-Length</code> or
|
|
<code>Content-Type</code> header in the request. If
|
|
the MD5 checksum of the data written to the storage system
|
|
does NOT match the (optionally) supplied ETag value, a 422
|
|
(Unprocessable Entity) response is returned.</para>
|
|
<example>
|
|
<title>Create or Update Object HTTP Response</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-create-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<section xml:id="chunked-transfer-encoding">
|
|
<title>Chunked Transfer Encoding</title>
|
|
<para>Users can upload data without needing to know in
|
|
advance the amount of data to be uploaded. Users can
|
|
do this by specifying an HTTP header of
|
|
<code>Transfer-Encoding: chunked</code> and not
|
|
using a <code>Content-Length</code> header. A good use
|
|
of this feature would be doing a DB dump, piping the
|
|
output through gzip, then piping the data directly
|
|
into OpenStack Object Storage without having to buffer
|
|
the data to disk to compute the file size. If users
|
|
attempt to upload more than 5GB with this method, the
|
|
server will close the TCP/IP connection after 5GB and
|
|
purge the customer data from the system. Users must
|
|
take responsibility for ensuring the data they
|
|
transfer will be less than 5GB or for splitting it
|
|
into 5GB chunks, each in its own storage object. If
|
|
you have files that are larger than 5GB see <xref
|
|
linkend="large-object-creation"/>.</para>
|
|
<example>
|
|
<title>Upload Unspecified Quantity of Content HTTP
|
|
Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/chunked-transfer-encoding-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<example>
|
|
<title>Upload Unspecified Quantity of Content HTTP
|
|
Response</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/chunked-transfer-encoding-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
</section>
|
|
</section>
|
|
<section xml:id="large-object-creation">
|
|
<title>Create Large Objects</title>
|
|
<para>The content of an object cannot be larger than 5GB (by
|
|
default). However, you can store larger content using two
|
|
types of objects:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Divide your content into pieces and upload each
|
|
piece into its own object. These objects are known
|
|
as segment objects.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Create a manifest object. A manifest object
|
|
"points to" the segment objects.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>Segment objects do not have any special features and can
|
|
be created, updated, downloaded and deleted as described
|
|
elsewhere in this document. However, a manifest object is
|
|
special -- when you download, the system concatenates the
|
|
contents of the segment objects and returns this in the
|
|
response body of the request. This behavior extends to the
|
|
response headers returned by &GET; and &HEAD; operations.
|
|
The Content-Length is the total size of all segment
|
|
objects and the ETag is calculated by taking the ETag
|
|
value of each segment, concatenating them together and
|
|
then returning the MD5 checksum of the result.</para>
|
|
<note>
|
|
<para>If you use the © operation using a manifest
|
|
object as the source, the new object is a "normal"
|
|
object (not segmented). If the total size of the
|
|
source segment objects exceeds 5 GB, the ©
|
|
operation fails. However, as explained later, you can
|
|
make a duplicate of the manifest object. This new
|
|
object can be larger than 5 GB.</para>
|
|
</note>
|
|
<para>The manifest object type are:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Static large objects. The manifest object
|
|
content is an ordered list of the names of the
|
|
segment objects in json format.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Dynamic large objects. The manifest object has
|
|
no content. However, it has
|
|
<code>X-Object-Manifest</code> metadata. The
|
|
value of this is
|
|
<code><container>/<prefix></code>, where
|
|
<code><container></code> is the name of the
|
|
container where the segment objects are stored and
|
|
<code><prefix></code> is a string that all
|
|
the segment objects have in common.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>While both types of manifest objects have similar
|
|
behavior, there are differences as explained in the
|
|
following table.</para>
|
|
<table rules="all">
|
|
<caption>Comparison of Static and Dynamic Large
|
|
Objects</caption>
|
|
<thead>
|
|
<tr>
|
|
<th>Feature</th>
|
|
<th>Static Large Object</th>
|
|
<th>Dynamic Large Object</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>End-to-end integrity</td>
|
|
<td>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 will
|
|
result in an error.</td>
|
|
<td>Not guaranteed. The eventual consistency model
|
|
means that although you may have uploaded a
|
|
segment object, it may not appear in the
|
|
container listing until later. If you download
|
|
the manifest before it appears in the
|
|
container, it will not form part of the
|
|
content returned in response to a &GET;
|
|
request.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Upload order</td>
|
|
<td>The segment objects must be uploaded before
|
|
the manifest object.</td>
|
|
<td>You can upload manifest and segment objects in
|
|
any order. You are recommended to upload the
|
|
manifest object after the segments in case a
|
|
premature download of the manifest occurs.
|
|
However, this is not enforced.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Removal or addition of segment objects</td>
|
|
<td>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.</td>
|
|
<td>You can upload new segment objects or remove
|
|
existing segments --- the names must simply
|
|
match the <code><prefix></code> supplied in
|
|
<code>X-Object-Manifest</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Segment object size and number</td>
|
|
<td>Segment objects must be at least 1MB in size
|
|
(by default). The final segment object can be
|
|
any size. At most 1000 segments are supported
|
|
(by default).</td>
|
|
<td>Segment objects can be of any size.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Segment object container name</td>
|
|
<td>The manifest list includes the container name
|
|
of each object, i.e., segment objects may be
|
|
in different containers.</td>
|
|
<td>All segment objects must be in the same
|
|
container</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Manifest Object Metadata</td>
|
|
<td>The object has
|
|
<code>X-Static-Large-Object</code> set to
|
|
<code>true</code>. You do not set this
|
|
metadata directly. Instead the system sets it
|
|
when you &PUT; a static manifest object.</td>
|
|
<td>The <code>X-Object-Manifest</code> value is
|
|
the <code><container>/<prefix></code>
|
|
indicating where the segment objects are
|
|
located. You supply this request header in the
|
|
&PUT; operation</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Making a copy of the manifest object</td>
|
|
<td>To make a copy of the manifest object, include
|
|
the <code>?multipart-manifest=get</code> query
|
|
string with the © 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.</td>
|
|
<td>The © operation does not create a
|
|
manifest object. To duplicate a manifest
|
|
object, use the &GET; operation to read the
|
|
value of <code>X-Object-Manifest</code> and
|
|
use this value in the
|
|
<code>X-Object-Manifest</code> 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.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<section xml:id="dynamic-large-object-creation">
|
|
<title>Dynamic Large Objects</title>
|
|
<para>Objects that are larger than 5GB must be segmented,
|
|
prior to upload. You then upload the segments like you
|
|
would any other object and create a dynamic large
|
|
manifest object telling OpenStack Object Storage how
|
|
to find the segments of 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.</para>
|
|
<para>To ensure 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 it sorts in the order in which it should be
|
|
concatenated. You also create and upload a manifest
|
|
file. The manifest file is a zero-byte file with the
|
|
extra X-Object-Manifest:
|
|
<container>/<prefix> header, where
|
|
<container> is the container 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.</para>
|
|
<para>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.</para>
|
|
<example>
|
|
<title>Upload Segment of Large Object HTTP
|
|
Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/large-object-upload-segment-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<example>
|
|
<title>Upload Segment of Large Object HTTP
|
|
Response</title>
|
|
<literallayout class="monospaced">s</literallayout>
|
|
</example>
|
|
<para>No response body is returned. A status code of 2xx
|
|
(between 200 and 299, inclusive) indicates a
|
|
successful write; status 411 (Length Required) denotes
|
|
a missing <code>Content-Length</code> or
|
|
<code>Content-Type</code> header in the request.
|
|
If the MD5 checksum of the data written to the storage
|
|
system does NOT match the (optionally) supplied ETag
|
|
value, a 422 (Unprocessable Entity) response is
|
|
returned.</para>
|
|
<para>You can continue uploading segments like this
|
|
example shows, prior to uploading the manifest.</para>
|
|
<example>
|
|
<title>Upload Next Segment of Large Object HTTP
|
|
Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/large-object-upload-next-segment-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<example>
|
|
<title>Upload Next Segment of Large Object HTTP
|
|
Response</title>
|
|
<literallayout class="monospaced">w</literallayout>
|
|
</example>
|
|
<para>Next, upload the manifest you created that indicates
|
|
the container the object segments reside within. Note
|
|
that uploading additional segments after the manifest
|
|
is created will cause the concatenated object to be
|
|
that much larger but you do not need to recreate the
|
|
manifest file for subsequent additional
|
|
segments.</para>
|
|
<example>
|
|
<title>Upload Manifest HTTP Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/upload-manifest-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<example>
|
|
<title>Upload Manifest HTTP Response</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/upload-manifest-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>The response's Content-Type for a &GET; or &HEAD; on
|
|
the manifest will be the same as the Content-Type set
|
|
during the PUT request that created the manifest. You
|
|
can easily change the Content-Type by reissuing the
|
|
&PUT; request.</para>
|
|
</section>
|
|
<section xml:id="static-large-objects">
|
|
<title>Static Large Objects</title>
|
|
<para>To create a static large object:</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>Divide your content into pieces and create
|
|
(upload) a segment object to contain each
|
|
piece. You must record the <code>ETag</code>
|
|
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
|
|
<code>ETag</code> request header. This
|
|
ensures that the upload cannot corrupt your
|
|
data.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>List the name of each segment object along
|
|
with its size and MD5 checksum in order.
|
|
Create a manifest object. You indicate that
|
|
this is a manifest object by including the
|
|
<code>?multipart-manifest=put</code> query
|
|
string at the end of the manifest object
|
|
name.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>The body of the &PUT; request on the manifest object
|
|
comprises a json list, where each element contains the
|
|
following:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><code>path</code> - this is the container
|
|
and object name in the following format:
|
|
<code><container-name>/<object-name></code></para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><code>etag</code> - this is the MD5 checksum
|
|
of the content of the segment object. This
|
|
must match the <code>ETag</code> of that
|
|
object.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><code>size_bytes</code> - this is the size
|
|
of the segment object. This must match the
|
|
<code>Content-Length</code> of that
|
|
object</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<example>
|
|
<title>Static Large Object Manifest List</title>
|
|
<para>This is an example containing three segment
|
|
objects. In this example, you can use several
|
|
containers and the object names do not have to
|
|
conform to a specific pattern, in contrast to
|
|
dynamic large objects.</para>
|
|
<literallayout class="monospaced"><xi:include href="samples/slo-manifest-example.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>The <code>Content-Length</code> request header must
|
|
contain the length of the json content -- not the
|
|
length of the segment objects. However, after the
|
|
&PUT; operation completes, the
|
|
<code>Content-Length</code> metadata is set to the
|
|
total length of all the object segments. A similar
|
|
situation applies to the <code>ETag</code>. If used in
|
|
the &PUT; operation, it must contain the MD5 checksum
|
|
of the json content. The <code>ETag</code> metadata
|
|
value is then set to be the MD5 checksum of the
|
|
concatenated <code>ETag</code> values of the object
|
|
segments. You may also set the
|
|
<code>Content-Type</code> request header and
|
|
custom object metadata.</para>
|
|
<para>When the &PUT; operation sees the
|
|
<code>?multipart-manifest=put</code> 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 will
|
|
fail.</para>
|
|
<para>If everything matches, the manifest object is
|
|
created. The <code>X-Static-Large-Object</code>
|
|
metadata is set to <code>true</code> indicating that
|
|
this is a static object manifest.</para>
|
|
<para>Normally when you perform a &GET; operation on the
|
|
manifest object, the response body contains the
|
|
concatenated content of the segment objects. To
|
|
download the manifest list, use the query string
|
|
<code>?multipart-manifest=get</code>. The
|
|
resulting list will not be identically formatted as
|
|
the manifest you originally used in the &PUT;
|
|
operation.</para>
|
|
<para>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
|
|
query parameter
|
|
<code>?multipart-manifest=delete</code>, the
|
|
segment objects are deleted and if all are
|
|
successfully deleted, the manifest object is also
|
|
deleted.</para>
|
|
<para>To change the manifest, use a &PUT; operation with
|
|
the <code>?multipart-manifest=put</code> query string.
|
|
This will create a <emphasis>new</emphasis> manifest
|
|
object. You may also update the object metadata in the
|
|
usual way.</para>
|
|
</section>
|
|
</section>
|
|
<section xml:id="assigning-cors-headers-to-requests">
|
|
<title>Assign CORS headers to requests</title>
|
|
<para>CORS is a specification that stands for Cross-Origin
|
|
Resource Sharing. It defines how browsers and servers
|
|
communicate across origins using HTTP headers, such as
|
|
those assigned by Object Storage API requests. These
|
|
headers are supported with the Object Storage API. You can
|
|
read more about the definition of the Access-Control-
|
|
response headers and Origin response header at <link
|
|
xlink:href="http://www.w3.org/TR/access-control/"
|
|
>www.w3.org/TR/access-control/</link>.
|
|
<table rules="all">
|
|
<caption>Supported Headers</caption>
|
|
<col width="50%"/>
|
|
<col width="50%"/>
|
|
<thead>
|
|
<tr>
|
|
<td><emphasis>Metadata</emphasis></td>
|
|
<td><emphasis>Use</emphasis></td>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>X-Container-Meta-Access-Control-Allow-Origin</td>
|
|
<td>Origins to be allowed to make Cross Origin Requests, space separated.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>X-Container-Meta-Access-Control-Max-Age</td>
|
|
<td>Max age for the Origin to hold the preflight results.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>X-Container-Meta-Access-Control-Expose-Headers</td>
|
|
<td>Headers exposed to the user agent (e.g. browser) in the the actual request response. Space separated.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</para>
|
|
<para>CORS metadata is held on the container only. The values given apply to the container itself and all objects within it.</para>
|
|
<example>
|
|
<title>Assign CORS header request: HTTP</title>
|
|
<para>In the example, the origin header is assigned that
|
|
indicates where the file came from. This allows you to
|
|
provide security that requests to your Object Storage
|
|
repository are indeed from the correct
|
|
origination:</para>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-assign-cors-header-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>You can find more details in the <link
|
|
xlink:href="http://docs.openstack.org/developer/swift/cors.html"
|
|
>Swift Documentation</link>.</para>
|
|
</section>
|
|
<section
|
|
xml:id="enabling-file-compression-with-content-encoding-header">
|
|
<title>Enabling File Compression with the Content-Encoding
|
|
Header</title>
|
|
<para>The Content-Encoding header allows a file to be
|
|
compressed without losing the identity of the underlying
|
|
media type of the file, for example, a video.</para>
|
|
<example>
|
|
<title>Content-Encoding Header HTTP Request</title>
|
|
<para>In the example, the content-encoding header is
|
|
assigned with an attachment type that indicates how
|
|
the file should be downloaded:</para>
|
|
<literallayout class="monospaced"><xi:include href="samples/content-encoding-header-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
</section>
|
|
<section
|
|
xml:id="enabling-browser-bypass-with-content-disposition-header">
|
|
<title>Enabling Browser Bypass with the Content-Disposition
|
|
Header</title>
|
|
<para>When an object is assigned the Content-Disposition
|
|
header you can override a browser's default behavior for a
|
|
file so that the download program saves the file rather
|
|
than displaying it using default browser settings.</para>
|
|
<example>
|
|
<title>Content-Disposition Header HTTP Request</title>
|
|
<para>In the example, the content-encoding header is
|
|
assigned with an attachment type that indicates how
|
|
the file should be downloaded.</para>
|
|
<literallayout class="monospaced"><xi:include href="samples/content-disposition-header-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
</section>
|
|
<section xml:id="Expiring_Objects-e1e3228">
|
|
<title>Expiring Objects with the X-Delete-After and
|
|
X-Delete-At Headers</title>
|
|
<para>When an object is assigned either an
|
|
<code>X-Delete-After</code> or
|
|
<code>X-Delete-At</code> header when doing a &PUT; or
|
|
&POST; on the object, it is scheduled for deletion. This
|
|
feature is helpful for objects you do not want to
|
|
permanently store, such as log files, recurring full
|
|
backups of a dataset, or documents or images you know will
|
|
be outdated at a future time.</para>
|
|
<para>The <code>X-Delete-At</code> header requires a Unix
|
|
Epoch timestamp, in integer form; for example: 1348691905
|
|
represents Wed, 26 Sep 2012 20:38:25 GMT.
|
|
<!-- Exchanged POSIX in / favor of Epoch for the / sake of clarity dsh 02-06-12 -->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.</para>
|
|
<para>The <code>X-Delete-After</code> header takes an integer
|
|
number of seconds and calculates the amount of time from
|
|
now that you want the object to be deleted. The proxy
|
|
server that receives the request converts this header into
|
|
an <code>X-Delete-At</code> header and calculates the
|
|
deletion time using its current time plus the value given
|
|
in seconds.</para>
|
|
<para>For existing objects that you want to assign expiration
|
|
headers to, use the &POST; operation.</para>
|
|
<example>
|
|
<title>Delete Object at HTTP Request</title>
|
|
<para>In the example, the <code>X-Delete-At</code> header
|
|
is assigned with a Unix Epoch timestamp in integer
|
|
form for Mon, 11 Jun 2012 15:38:25 GMT. Use <link
|
|
xlink:href="http://www.epochconverter.com/"
|
|
>http://www.epochconverter.com/</link> for example
|
|
timestamps and a batch converter.</para>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-delete-at-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<example>
|
|
<title>Delete Object after HTTP Request</title>
|
|
<para><!-- Reworded this here / paragraph to make more sense / and match what I see dsh 02-06-12 -->In
|
|
this example, the <code>X-Delete-After</code> header
|
|
is assigned a value in seconds, equivalent to 10 days.
|
|
After this time, the object expires.</para>
|
|
<!-- Removed, "The system then converts the time necessary for an <code>X-Delete-At</code> header operation." Doesn't seem to match dsh 02-06-12-->
|
|
<literallayout class="monospaced"><xi:include href="samples/object-delete-after-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
</section>
|
|
|
|
<section xml:id="Object_Versioning-e1e3230">
|
|
<!-- begin 4.3.2.7 -->
|
|
<title>Object Versioning</title>
|
|
<para>Object versioning allows you to store multiple versions
|
|
of your content to recover from unintended overwrites. It
|
|
provides an easy method to implement version control which
|
|
can be used on any type of content. It is strongly
|
|
recommended that you put non-current objects in a
|
|
container apart from where the current versions exist.
|
|
Once you enable Object Versioning on a container (such as
|
|
a "current version" container), &PUT;s to existing objects
|
|
in that container copy the prior object to a separate
|
|
"non-current version" container. Each of the non-current
|
|
versions of an object has a time stamp appended to it, so
|
|
you know when it was created.</para>
|
|
<para>To enable object versioning, your cloud provider has to
|
|
set <code>allow_versions</code> to <code>TRUE</code> in
|
|
their container config. Then, create a container where
|
|
your non-current versions will be written. Next, set the
|
|
metadata <code>X-Versions-Location</code> header on the
|
|
container that holds the current versions of your objects.
|
|
Set the metadata header to point to the new non-current
|
|
version container you created. The name of the container
|
|
must be UTF-8 encoded and then URL-encoded before putting
|
|
into the <code>X-Versions-Location</code> header. This is
|
|
where your non-current versions will be stored. Once this
|
|
is done, each object in your current-version container
|
|
will have Object Versioning enabled; changes to the
|
|
objects automatically create non-current versions in the
|
|
separate container.</para>
|
|
<para>Nothing is written to the non-current version container
|
|
when you initially &PUT; an object into the
|
|
current-version container. Only when you make edits to the
|
|
objects via &PUT; will you create non-current versions.
|
|
These non-current versions are labeled according to the
|
|
schema below.</para>
|
|
<para>
|
|
<emphasis>Naming Schema:</emphasis> Non-current versions
|
|
are assigned the name
|
|
<length><object_name>/<timestamp>, where
|
|
length is the 3-character zero-padded hexadecimal
|
|
character length of the <object_name> and
|
|
<timestamp> is when the it was initially created as
|
|
a current version.</para>
|
|
<para>Any return status in the 2xx range, such as 202
|
|
(Accepted), denotes success. Status codes in the 4xx or
|
|
5xx range denote failure. You should retry your request if
|
|
you receive an error. Please note, however, that if you
|
|
have specified a container that does not exist as your
|
|
non-current version container, a status of 412
|
|
(Precondition Failed) returns when you edit the versioned
|
|
object. If you receive this error, check that the
|
|
container exists.</para>
|
|
<para>A &GET; to a versioned object returns the current
|
|
version of the object without having to do any request
|
|
redirects or metadata lookups.</para>
|
|
<para>A &POST; to a versioned object only updates the object's
|
|
metadata; it does not create a new version of the object.
|
|
In other words, new versions are only created when the
|
|
content of the object changes.</para>
|
|
<para>A &DELETE; to a versioned object removes the current
|
|
version of the object and replaces it with the next-most
|
|
current version, moving it from the non-current container
|
|
to the current. This next-most current version carries
|
|
with it any metadata last set on it. If want to completely
|
|
remove an object and you have five total versions of it,
|
|
you must &DELETE; it five times.</para>
|
|
<note>
|
|
<para>A large-object manifest file cannot be versioned,
|
|
but it may point to versioned segments.</para>
|
|
</note>
|
|
<para>To turn off Object Versioning on your current version
|
|
container, remove its <code>X-Versions-Location</code>
|
|
metadata by sending an empty key value.</para>
|
|
<example>
|
|
<title>Object Versioning with cURL</title>
|
|
<para>Make sure a version-storing container exists,
|
|
creating it if necessary (this example names it
|
|
"versions"). Then create a container with the
|
|
<code>X-Versions-Location</code> header. In this
|
|
example, this container is named "current". You can
|
|
also add the <code>X-Versions-Location</code> header
|
|
to an existing container. In this example, the name of
|
|
the container is “versions”; the location for the
|
|
current version is the container "current".</para>
|
|
<para>Create a container named versions.</para>
|
|
<screen><prompt>$</prompt> <userinput>curl -i -XPUT -H "X-Auth-Token: <token>" http://<storage_url>/versions</userinput></screen>
|
|
<para>Create a container named current with the
|
|
<code>X-Versions-Location</code> header that
|
|
references "versions".</para>
|
|
<screen><prompt>$</prompt> <userinput>curl -i -XPUT -H "X-Auth-Token: <token>" \
|
|
-H "X-Versions-Location: versions" http://<storage_url>/current</userinput></screen>
|
|
<para>Create an object (the first version):</para>
|
|
<screen><prompt>$</prompt> <userinput>curl -i -XPUT --data-binary 1 -H "X-Auth-Token: <token>" \
|
|
http://<storage_url>/current/myobject</userinput></screen>
|
|
<para>Now create a new version of that object:</para>
|
|
<screen><prompt>$</prompt> <userinput>curl -i -XPUT --data-binary 2 -H "X-Auth-Token: <token>" \
|
|
http://<storage_url>/current/myobject</userinput></screen>
|
|
<para>See a listing of the older versions of the
|
|
object:</para>
|
|
<screen><prompt>$</prompt> <userinput>curl -i -H "X-Auth-Token: <token>" \
|
|
http://<storage_url>/versions?prefix=008myobject/</userinput></screen>
|
|
<para>Now delete the current version of the object and see
|
|
that the older version is gone:</para>
|
|
<screen><prompt>$</prompt> <userinput>curl -i -XDELETE -H "X-Auth-Token: <token>" \
|
|
http://<storage_url>/current/myobject</userinput></screen>
|
|
<screen><userinput><prompt>$</prompt> curl -i -H "X-Auth-Token: <token>" \
|
|
http://<storage_url>/versions?prefix=008myobject/</userinput></screen>
|
|
</example>
|
|
</section>
|
|
<section xml:id="copy-object">
|
|
<title>Copy Object</title>
|
|
<para>Suppose you upload a file with the wrong object name or
|
|
content type, or you needed to move some objects to
|
|
another container. Without a server-side copy feature, you
|
|
would need to repeat uploading the same content and then
|
|
delete the existing object. With server-side object copy,
|
|
you can save the step of re-uploading the content and thus
|
|
also save the associated bandwidth charges, if any were to
|
|
apply.</para>
|
|
<para>There are two ways to copy an existing object to another
|
|
object in OpenStack Object Storage. One way is to do a
|
|
&PUT; to the new object (the target) location, but add the
|
|
<code>“X-Copy-From”</code> header to designate the
|
|
source of the data. The header value should be the
|
|
container and object name of the source object in the form
|
|
of “/container/object”. The container and object name must
|
|
be UTF-8 encoded and then URL-encoded. Also, the
|
|
<code>X-Copy-From</code> &PUT; requests require a
|
|
Content-Length header, even if it is zero (0).</para>
|
|
<example>
|
|
<title>Object Copy Method 1</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-copy-1-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>The second way to do an object copy is similar. Do a
|
|
© to the existing object, and include the
|
|
“Destination” header to specify the target of the copy.
|
|
The header value is the container and new object name in
|
|
the form of “/container/object”.</para>
|
|
<example>
|
|
<title>Object Copy Method 2</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-copy-2-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>With both of these methods, the destination container
|
|
must exist before attempting the copy.</para>
|
|
<para>If the source object is a manifest object, i.e., an
|
|
object with <code>X-Object-Manifest</code> or
|
|
<code>X-Static-Large-Object:true</code> metadata, the
|
|
copy operation concatenates the segment objects when
|
|
making the content for the destination object. You cannot
|
|
copy an object larger than 5GB (by default). Refer to
|
|
<link linkend="large-object-creation">Large Object
|
|
Creation</link> for more information about large
|
|
objects.</para>
|
|
<para>However, for a <link linkend="static-large-objects"
|
|
>Static Large Object</link> manifest, it is possible
|
|
to copy the manifest so that the destination becomes a
|
|
manifest object. Use the
|
|
<code>?multipart-manifest=get</code> query string to
|
|
indicate that you want a copy of the manifest object. The
|
|
new object will contain 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.</para>
|
|
<para>If you wanted to move the object rather than copy it,
|
|
you need to send a &DELETE; request to the old object. A
|
|
move is simply a © + &DELETE;. All metadata is
|
|
preserved during the object copy. Note that you can set
|
|
metadata on the request to copy the object (either the
|
|
&PUT; or the ©) and the metadata will overwrite any
|
|
conflicting keys on the target (new) object. One
|
|
interesting use case is to copy an object to itself and
|
|
set the content type to a new value. This is the only way
|
|
to change the content type of an existing object.</para>
|
|
</section>
|
|
<section xml:id="delete-object">
|
|
<title>Delete Object</title>
|
|
<para>&DELETE; operations on an object are used to permanently
|
|
remove an object from the storage system (metadata and
|
|
data).</para>
|
|
<para>Deleting an object is processed immediately at the time
|
|
of the request. Any subsequent &GET;, &HEAD;, &POST;, or
|
|
&DELETE; operations will return a 404 (Not Found)
|
|
error.</para>
|
|
<para>For <link linkend="static-large-objects">static large
|
|
object manifests</link>, you can add the query
|
|
parameter <code>?multipart-manifest=delete</code>. The
|
|
segment objects are deleted and if all are successfully
|
|
deleted, the manifest object is also deleted.</para>
|
|
<para>Objects with the <code>X-Delete-At</code> or
|
|
<code>X-Delete-After</code> header assigned are
|
|
deleted within one day of the expiration time and the
|
|
object is not served immediately after the expiration
|
|
time. Refer to <link linkend="Expiring_Objects-e1e3228"
|
|
>Expiring Objects</link> for more details.</para>
|
|
<example>
|
|
<title>Object Delete HTTP Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-delete-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>No response body is returned. A status code of 2xx (
|
|
between 200 and 299, inclusive) indicates success; status
|
|
code 404 (Not Found) is returned when the object does not
|
|
exist.</para>
|
|
<example>
|
|
<title>Object Delete HTTP Response</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-delete-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
</section>
|
|
<section xml:id="retrieve-object-metadata">
|
|
<title>Get Object Metadata</title>
|
|
<para>&HEAD; operations on an object are used to retrieve
|
|
object metadata and other standard HTTP headers.</para>
|
|
<para>The only required header to be sent in the request is
|
|
the authorization token.</para>
|
|
<example>
|
|
<title>Get Object Metadata HTTP Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-metadata-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>No response body is returned. Metadata is returned as
|
|
HTTP headers. A status code of 2xx (between 200 and 299,
|
|
inclusive) indicates success; status 404 (Not Found) is
|
|
returned when the object does not exist.</para>
|
|
<example>
|
|
<title>Get Object Metadata HTTP Response</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-metadata-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
</section>
|
|
<section xml:id="update-object-metadata">
|
|
<title>Update Object Metadata</title>
|
|
<para>&POST; operations against an object name are used to set
|
|
and overwrite arbitrary key/value metadata or to assign
|
|
headers not already assigned such as
|
|
<code>X-Delete-At</code> or
|
|
<code>X-Delete-After</code> for expiring objects. You
|
|
cannot use the &POST; operation to change any of the
|
|
object's other headers such as <code>Content-Type</code>,
|
|
<code>ETag</code>, etc. It is not used to upload
|
|
storage objects (see &PUT;). Also refer to <link
|
|
linkend="copy-object">copying an object</link> when
|
|
you need to update metadata or other headers such as
|
|
Content-Type or CORS headers.</para>
|
|
<para>Key names must be prefixed with
|
|
<code>X-Object-Meta-</code>. A &POST; request will
|
|
delete all existing metadata added with a previous
|
|
&PUT;/&POST;.</para>
|
|
<example>
|
|
<title>Update Object Metadata HTTP Request</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-update-metadata-req.txt" parse="text"/></literallayout>
|
|
</example>
|
|
<para>No response body is returned. A status code of 2xx
|
|
(between 200 and 299, inclusive) indicates success; status
|
|
404 (Not Found) is returned if the requested object does
|
|
not exist.</para>
|
|
<example>
|
|
<title>Update Object Metadata HTTP Response</title>
|
|
<literallayout class="monospaced"><xi:include href="samples/object-update-metadata-resp.txt" parse="text"/></literallayout>
|
|
</example>
|
|
</section>
|
|
</section>
|