Conditional operations
Conditional operations let you tell HCP to perform an operation only if the current object or specified version meets certain conditions. A conditional operation can use an ETag or a datetime value. HCP compares the value that you provide in an HTTP header with the corresponding value for the object or version and performs the requested action only if the specified condition is met.
Here are two typical uses for conditional operations:
- Managing a local object cache. You can reduce the load on HCP and your network by maintaining a local cache of frequently used objects. When the local application requires an object, it can send a conditional GET request to HCP to retrieve a new version only if the object has changed.
- Managing storage by multiple users or applications. An application that updates an object can use a conditional PUT request that tells HCP to store the new version only if the ETag of the existing version equals the ETag of the last known version of the object. Otherwise, the application gets an error return, and can handle the data conflict appropriately. This technique can be useful in cases where several users might update the same object.
You can specify conditions in GET, HEAD, and PUT requests for objects and versions. You cannot use them in DELETE requests for these items. Doing so results in an HTTP 400 (Bad Request) error code.
Request headers
You use the headers described in the table below to specify conditional operations.
Header | Value | Description |
If-Match |
One of:
|
Perform the operation only if the ETag of the object or version is identical to one of the specified ETag values. For an asterisk, perform the operation if the object exists. |
If-None-Match |
One of:
|
Perform the operation only if the ETag of the object or version is not equal to any of the specified ETag values. For an asterisk, perform the operation if the object doesn’t exist. |
If-Modified-Since | Datetime value | Perform the operation only if the object or version change time was after the specified time. |
If-Unmodified-Since | Datetime value | Perform the operation only if the object or version change time was at or before the specified time. |
When you use the PUT method to copy an object, the headers listed in the table above apply to any existing version of the target object. You can use the headers describe in the table below to specify conditions for the source object.
Header | Contents | Description |
X-HCP-CopySource-If-Match |
One of:
|
Perform the copy operation only if the ETag of the source object or version is equal to one of the specified ETag values. For an asterisk, perform the operation if the object exists. |
X-HCP-CopySource-If-None-Match |
One of:
|
Perform the copy operation only if the ETag of the source object or version is not equal to any of the specified ETag values. For an asterisk, perform the operation if the object does not exist. |
X-HCP-CopySource-If-Modified-Since | Datetime value | Perform the copy operation only if the source object or version change time was after the specified time. |
X-HCP-CopySource-If-Unmodified-Since | Datetime value | Perform the copy operation only if the source object or version change time was at or before the specified time. |
A request can specify more than one condition. In such a request:
- HCP evaluates all the conditions. However, if the request includes both If-None-Match and If-Modified-Since headers, the If-Modified-Since header is ignored.
- Headers that use ETag values are processed before headers that use datetime values.
ETag values
The list of ETag values used in the If-Match
and If-None-Match
header has this format:
"ETag-value"[, "ETag-value"]...
Because the individual ETag values are enclosed in double quotation marks ("), in curl and PycURL commands, you need to enclose the entire header in single quotation marks ('), as shown below:
'If-None-Match: "d158a5494cf76bf2cbbe40a7aa674543","638c9bd8d4c2c1022c6fcac9227f5af4"'
In the If-Match
and If-None-Match
headers, you typically use the ETag values returned in ETag headers of prior requests, such as when you store objects. This way, for example, you can prevent your application from retrieving a version of an object that your application has already cached or from storing an object version that already exists in HCP.
Datetime headers
Datetime headers let you perform operations based on whether an object has been modified since a specific time.
Datetime values for the If-Modified-Since
and If-Unmodified-Since
headers must be in one of these formats:
- Format: DDD, dd MMM yyyy hh:mm:ss GMT
Example: Mon, 01 Jan 2013 15:30:00 GMT
The
Last-Modified
header returned by GET and HEAD requests for objects and versions is in this format. - Format: Day, dd-MMM-yy hh:mm:ss GMT
Example: Monday, 01-Jan-13 15:30:00 GMT
- Format: DDD MMM d hh:mm:ss yyyy
Example: Mon Jan 1 15:30:00 2013
The following considerations apply to using datetime headers for conditional processing:
- HCP compares the header value with the object change time. Several events, including system events, cause HCP to update the object change time.
- Change time resolution is only to the second, so you cannot use these headers to differentiate between changes that happened during the same second.
- If a header contains an invalid datetime value, HCP ignores the header and does not return an error response.
Handling objects that might not have ETags
If the HCP system has been upgraded from a release earlier than 6.0, some objects that were stored in the namespace before the upgrade may not yet have ETags. In such cases, the HCP behavior depends on the request type and object size, as follows:
- For a GET request for an object 512,000 bytes or smaller, HCP automatically calculates the ETag, returns it in the ETag header and uses it, if needed, for conditional processing.
- For a GET request for an object larger than 512,000 bytes, by default, HCP does not calculate the ETag. In this case:
- The response does not return an ETag header.
- If the request has an
If-Match
orIf-None-Match
header, HCP returns a 400 error response with a message explaining the cause.
- For a PUT request to copy an object, HCP handles the source object the same way it handles the object in a GET request. For source objects of 512,000 bytes or less, HCP calculates and saves the ETag and uses it to processes any
X-HCP-CopySource-If-Match
orX-HCP-CopySource-If-None-Match
header. For larger source objects, using these headers results in a 400 error response. - For a PUT or HEAD request, including for the target of a PUT request to copy an object, HCP does not generate the ETag for an existing object. If a PUT or HEAD request has an
If-Match
orIf-None-Match
header and specifies an object that does not yet have an ETag, HCP returns a 400 error.
If you get an error because an object does not have an ETag, you can force HCP to calculate the missing ETag by including a forceEtag query parameter with a value of true in either of these requests:
- A GET request. In this case, HCP processes any
If-Match
orIf-None-Match
header and includes an ETag header when it returns an object. - A PUT request to copy an object. In this case, HCP processes any
X-HCP-CopySource-If-Match
orX-HCP-CopySource-If-None-Match
header and can copy the specified object if the condition is met.
Once HCP has generated an object ETag, you can use conditional headers in GET, PUT, and HEAD requests for the object.
Example: Conditionally storing a new version
Here’s a sample HTTP PUT request that stores a new version of an object named Q3_2012.ppt in the quarterly_rpts directory if the current version of the object has not been modified since 9:00 a.m., EST on Monday, November 5, 2012.
Request with curl command line
curl -k -iT Q1_2012.ppt -H "If-Unmodified-Since: Mon, 05 Nov 2012 14:00:00 GMT" -H "Authorization: HCP bXl1c2Vy:3f3c6784e97531774380db177774ac8d" "https://finance.europe.hcp.example.com/rest/quarterly_rpts/Q1_2012.ppt"
Request in Python using PycURL
import pycurl import os filehandle = open("Q3_2012.ppt", 'rb') curl = pycurl.Curl() curl.setopt(pycurl.HTTPHEADER, ["Authorization: HCP bXl1c2Vy:3f3c6784e97531774380db177774ac8d"]) curl.setopt(pycurl.URL, "https://finance.europe.hcp.example.com/ \ rest/quarterly_rpts/Q3_2012.ppt") curl.setopt(pycurl.SSL_VERIFYPEER, 0) curl.setopt(pycurl.SSL_VERIFYHOST, 0) curl.setopt(pycurl.HTTPHEADER, ["If-Unmodified-Since: Mon, 05 Nov 2012 14:00:00 GMT"]) curl.setopt(pycurl.UPLOAD, 1) curl.setopt(pycurl.INFILESIZE, os.path.getsize("Q1_2012.ppt")) curl.setopt(pycurl.READFUNCTION, filehandle.read) curl.perform() print curl.getinfo(pycurl.RESPONSE_CODE) curl.close() filehandle.close()
Request headers
PUT /rest/quarterly_rpts/Q1_2012.ppt HTTP/1.1 Host: /finance.europe.hcp.example.com Authorization: HCP bXl1c2Vy:3f3c6784e97531774380db177774ac8d If-Unmodified-Since: Mon, 05 Nov 2012 14:00:00 Content-Length: 678400
Response headers
HTTP/1.1 201 Created X-HCP-ServicedBySystem: hcp.example.com ETag: 78821a05d282822e4abec190c061ba78 Location: /rest/quarterly_rpts/Q1_2012.ppt X-HCP-VersionId: 79885459513089 X-HCP-Hash: SHA-256 E830B86212A66A792A79D58BB185EE63A4FADA76BB8A1... X-HCP-Time: 1358245832 Content-Length: 0
Example: Conditionally retrieving all object data
Here’s a sample HTTP GET request that retrieves an object named
Q1_2012.ppt in the quarterly_rpts directory if the ETag of the object data does not match the ETag of version of the object that was previously retrieved from HCP. This technique prevents downloading a copy of an object that’s already available.
Request with curl command line
curl -k -H "Authorization: HCP bXl1c2Vy:3f3c6784e97531774380db177774ac8d" -H 'If-None-Match: "d158a5494cf76bf2cbbe40a7aa674543"' "https://finance.europe.hcp.example.com/rest/quarterly_rpts/Q1_2012.ppt" > Q1_2012.ppt
Request in Python using PycURL
import pycurl filehandle = open("Q1_2012.ppt", 'wb') curl = pycurl.Curl() curl.setopt(pycurl.HTTPHEADER, ["Authorization: HCP bXl1c2Vy:3f3c6784e97531774380db177774ac8d", "If-None-Match: d158a5494cf76bf2cbbe40a7aa674543"]) curl.setopt(pycurl.URL, "https://finance.europe.hcp.example.com \ /rest/quarterly_rpts/Q1_2012.ppt") curl.setopt(pycurl.SSL_VERIFYPEER, 0) curl.setopt(pycurl.SSL_VERIFYHOST, 0) curl.setopt(pycurl.WRITEFUNCTION, filehandle.write) curl.perform() print curl.getinfo(pycurl.RESPONSE_CODE) curl.close() filehandle.close()
Request headers
GET /rest/quarterly_rpts/Q1_2012.ppt HTTP/1.1 Host: finance.europe.hcp.example.com Authorization: HCP bXl1c2Vy:3f3c6784e97531774380db177774ac8d If-None-Match: d158a5494cf76bf2cbbe40a7aa674543
Response headers
HTTP/1.1 200 OK X-HCP-ServicedBySystem: hcp.example.com X-HCP-Time: 1353352625 X-HCP-SoftwareVersion: 7.0.0.16 ETag: "d45e5b124c1807d6ec4f8088b5e51f8d" Content-Type: application/vnd.ms-powerpoint Content-Length: 130919 X-HCP-Type: object X-HCP-Size: 130919 X-HCP-Hash: SHA-256 F19D0CA6D684F4B9C48789828A31551A50673597ABAC66C6D7.... X-HCP-VersionId: 86614553936513 X-HCP-IngestTime: 1353352405 X-HCP-RetentionClass: X-HCP-RetentionString: Deletion Allowed X-HCP-Retention: 0 X-HCP-IngestProtocol: HTTP X-HCP-RetentionHold: false X-HCP-Shred: false X-HCP-DPL: 2 X-HCP-Index: true X-HCP-Custom-Metadata: false X-HCP-ACL: false X-HCP-Owner: europe X-HCP-Domain: X-HCP-UID: X-HCP-GID: X-HCP-Replicated: false X-HCP-ReplicationCollision: false X-HCP-ChangeTimeMilliseconds: 1353352405323.00 X-HCP-ChangeTimeString: 2012-11-19T14:13:25-0500 Last-Modified: Mon, Nov 19 2012 19:13:25 GMT
Response body: The contents of the Q1_2012.ppt object