diff --git a/src/HPCloud/Storage/ObjectStorage/ContentVerificationException.php b/src/HPCloud/Storage/ObjectStorage/ContentVerificationException.php new file mode 100644 index 0000000..4f2ffcc --- /dev/null +++ b/src/HPCloud/Storage/ObjectStorage/ContentVerificationException.php @@ -0,0 +1,17 @@ +fetchObject(TRUE); - return $response->content(); + $content = $response->content(); + + $check = md5($content); + if ($check != $this->etag()) { + throw new ContentVerificationException("Checksum $check does not match Etag " . $this->etag()); + } + + return $content; + } + + /** + * Enable or disable content verification (checksum/md5). + * + * The default behavior of a RemoteObject is to verify that the MD5 + * provided by the server matches the locally generated MD5 of the + * file contents. + * + * If content verification is enabled, then whenever the content is + * fetched from the remote server, its checksum is calculated and + * tested against the ETag value. This provides a layer of assurance + * that the payload of the HTTP request was not altered during + * transmission. + * + * This featured can be turned off, which is sometimes necessary on + * systems that do not correctly produce MD5s. Turning this off might + * also provide a small performance improvement on large files, but at + * the expense of security. + * + * @param boolean $enabled + * If this is TRUE, content verification is performed. The content + * is hashed and checked against a server-supplied MD5 hashcode. If + * this is FALSE, no checking is done. + */ + public function setContentVerification($enabled) { + $this->contentVerification = $enabled; + } + + /** + * Indicate whether this object verifies content (checksum). + * + * When content verification is on, RemoteObject attemts to perform a + * checksum on the object, calculating the MD5 hash of the content + * returned by the remote server, and comparing that to the server's + * supplied ETag hash. + * + * @return boolean + * TRUE if this is verifying, FALSE otherwise. + */ + public function isVerifyingContent() { + return $this->contentVerification; } /** @@ -213,17 +273,4 @@ class RemoteObject extends Object { return $response; } - - /* - public function setContent($content, $type = NULL) { - throw new ReadOnlyObjectException(__CLASS__ . ' is read-only.'); - } - public function setContentType($type) { - throw new ReadOnlyObjectException(__CLASS__ . ' is read-only.'); - } - public function setMetadata(array $array) { - throw new ReadOnlyObjectException(__CLASS__ . ' is read-only.'); - } - */ - } diff --git a/test/Tests/ContainerTest.php b/test/Tests/ContainerTest.php index 6568e70..9e0f748 100644 --- a/test/Tests/ContainerTest.php +++ b/test/Tests/ContainerTest.php @@ -145,12 +145,18 @@ class ContainerTest extends \HPCloud\Tests\TestCase { $this->assertEquals('1234', $md['Foo']); $content = $object->content(); - $this->assertEquals(self::FCONTENT, $content); + // Make sure I can do this twice (regression). + // Note that this SHOULD perform another request. + $this->assertEquals(self::FCONTENT, $object->content()); + // Overwrite the copy: $object->setContent('HI'); $this->assertEquals('HI', $object->content()); + + // Make sure I can do this twice (regression check). + $this->assertEquals('HI', $object->content()); } /**