public function __invoke(Request $req, Response $res, $args = []) { $vaultName = $args['vaultName']; if (!($vault = Vault::get($vaultName))) { return $res->withStatus(404); } if (!($contentLength = $req->getHeaderLine('Content-Length'))) { return $res->withStatus(400)->write('Content-Length header missing.'); } $contentLength = (int) $contentLength; if (!($desc = $req->getHeaderLine('x-amz-archive-description'))) { $desc = ''; } if (!($contentHash = $req->getHeaderLine('x-amz-content-sha256'))) { return $res->withStatus(400)->write('Header x-amz-content-sha256 missing.'); } if (!($treeHash = $req->getHeaderLine('x-amz-sha256-tree-hash'))) { return $res->withStatus(400)->write('Header x-amz-sha256-tree-hash missing.'); } $putData = file_get_contents('php://input'); $actualContentLength = strlen($putData); if ($actualContentLength != $contentLength) { return $res->withStatus(400)->write("invalid content length (expected: {$contentLength} actual: {$actualContentLength})"); } $hash = new TreeHash(); $hash->update($putData); $actualTreeHash = bin2hex($hash->complete()); if ($treeHash !== $actualTreeHash) { return $res->withStatus(400)->write("tree hash mismatch actual:{$actualTreeHash} exp:{$treeHash}"); } if (isset($GLOBALS['config']['uploadThrottle'])) { $GLOBALS['config']['uploadThrottle'](); } $a = new Archive(true, $vault); $a->setParam('SHA256TreeHash', $treeHash); $a->setParam('Size', (int) $contentLength); $a->setParam('Description', $desc); if (($ret = file_put_contents($a->getFile('data'), $putData)) !== $contentLength) { return $res->withStatus(500)->write("Could not write archive data: " . $a->getFile('data')); } $vault->invalidateInventory(); return $res->withStatus(201)->withHeader('x-amz-archive-id', $a->getId())->withHeader('x-amz-sha256-tree-hash', $treeHash); }
public function __invoke(Request $req, Response $res, $args = []) { $vaultName = $args['vaultName']; $multipartID = $args['multipartID']; if (!($vault = Vault::get($vaultName))) { return $res->withStatus(404); } if (!($m = $vault->getMultipart($multipartID))) { return $res->withStatus(404); } $contentHash = $req->getHeaderLine('x-amz-content-sha256'); $treeHash = $req->getHeaderLine('x-amz-sha256-tree-hash'); $contentRange = $req->getHeaderLine('Content-Range'); $contentLength = $req->getHeaderLine('Content-Length'); // 'bytes 0-1048575/*' if (!preg_match('@(\\d+)-(\\d+)@', $contentRange, $match)) { return $res->withStatus(400)->write('Invalid range'); } $rangeFrom = $match[1]; $rangeTo = $match[2]; $putData = file_get_contents('php://input'); $actualContentLength = strlen($putData); if ($actualContentLength != $contentLength) { return $res->withStatus(400)->write("invalid content length (expected: {$contentLength} actual: {$actualContentLength})"); } $hash = new TreeHash(); $hash->update($putData); $actualTreeHash = bin2hex($hash->complete()); if ($treeHash !== $actualTreeHash) { return $res->withStatus(400)->write("tree hash mismatch actual:{$actualTreeHash} exp:{$treeHash}"); } if (isset($GLOBALS['config']['uploadThrottle'])) { $GLOBALS['config']['uploadThrottle'](); } if (!$m->putPart($rangeFrom, $rangeTo, $contentLength, $putData, $treeHash)) { return $res->withStatus(400)->write('putPart failed'); } return $res->withStatus(204)->withHeader('x-amz-sha256-tree-hash', $treeHash); }
use Aws\Glacier\TreeHash; $I = new ApiTester($scenario); $I->wantTo('Upload, retrieve and delete an archive.'); $I->haveAuth(); $I->sendPUT('/-/vaults/testvault'); $I->seeResponseCodeIs(201); $data = ''; $archiveSize = 1024 * 1024 + 10; for ($i = 0; $i < $archiveSize; $i++) { $data .= chr(rand(0, 255)); } $data[0] = 'A'; $data[1] = 'B'; $data[2] = 'C'; $data[3] = 'D'; $treeHash = new TreeHash(); $treeHash->update($data); $treeHash = bin2hex($treeHash->complete()); $hash = hash('sha256', $data); $I->haveHttpHeader('Content-Type', 'application/octet-stream'); $I->haveHttpHeader('x-amz-archive-description', 'test123'); $I->haveHttpHeader('x-amz-sha256-tree-hash', $treeHash); $I->haveHttpHeader('x-amz-content-sha256', $hash); $I->sendPOST('/-/vaults/testvault/archives', $data); $I->seeResponseCodeIs(201); $I->seeResponseEquals(''); $archiveID = $I->grabHttpHeader('x-amz-archive-id'); $I->haveHttpHeader('Content-Type', 'application/json'); $I->sendPOST('/-/vaults/testvault/jobs', ['Type' => 'archive-retrieval', 'ArchiveId' => $archiveID]); $I->seeResponseCodeIs(202); $jobID = $I->grabHttpHeader('x-amz-job-id');
protected function getCompleteParamsFn() { return function () { $treeHash = new TreeHash(); $archiveSize = 0; foreach ($this->state->getUploadedParts() as $part) { $archiveSize += $part['size']; $treeHash->addChecksum($part['checksum']); } return ['archiveSize' => $archiveSize, 'checksum' => bin2hex($treeHash->complete())]; }; }
public function dumpOutput($res, $range = false, $httpRange = false) { if (($archive = $this->getArchive()) === false) { return $res->withStatus(500); } if (($f = fopen($file = $archive->getFile('data'), 'r')) === false) { return $res->withStatus(500); } if ($range) { list($from, $to) = $range; } else { $from = 0; $to = filesize($file) - 1; } if (fseek($f, $from) === -1) { return $res->withStatus(500); } $bufSize = 1024 * 1024 * 1; $readBytes = $to - $from + 1; $contentLength = $readBytes; $bytesWritten = 0; $data = ''; while ($readBytes > 0 && !feof($f)) { $buf = fread($f, max($bufSize, $readBytes)); if ($buf === false) { return $res->withStatus(500); } $readBytes -= strlen($buf); $data .= $buf; } if ($range && $range[0] == 0 && $range[1] == filesize($file) - 1) { $computeTreeHash = true; } else { if ($range) { $computeTreeHash = \Gsandbox\TreeHashCheck::isTreeHashAligned($to + 1, $from, $to); } else { $computeTreeHash = true; } } if ($computeTreeHash) { $hash = new TreeHash(); $hash->update($data); $treeHash = bin2hex($hash->complete()); $res = $res->withHeader('x-amz-sha256-tree-hash', $treeHash); } $res = $res->withHeader('Content-Type', 'application/octet-stream'); $res = $res->withHeader('Content-Length', $contentLength); if ($httpRange) { $res = $res->withHeader('Content-Range', "{$httpRange[0]}-{$httpRange[1]}/{$contentLength}"); } if (fseek($f, $from) === -1) { return $res->withStatus(500); } $readBytes = $to - $from + 1; $dumped = 0; $dumpBufSize = 1024 * 1024 / 2; while ($readBytes > 0 && !feof($f)) { $len = max($bufSize, $readBytes); if ($len > $readBytes) { $len = $readBytes; } $buf = fread($f, $len); if ($buf === false) { return $res->withStatus(500); } while (strlen($buf)) { $dump = substr($buf, 0, $dumpBufSize); $buf = substr($buf, strlen($dump)); $res->getBody()->write($dump); $dumped += strlen($dump); $readBytes -= strlen($dump); } if (isset($GLOBALS['config']['downloadThrottle'])) { $GLOBALS['config']['downloadThrottle'](); } } fclose($f); return $res->withStatus($httpRange ? 206 : 200); }