/** * Changes how buckets are referenced in the HTTP request * * @param Event $event Event emitted */ public function onCommandBeforeSend(Event $event) { $command = $event['command']; $bucket = $command['Bucket']; $request = $command->getRequest(); $pathStyle = false; if ($key = $command['Key']) { // Modify the command Key to account for the {/Key*} explosion into an array if (is_array($key)) { $command['Key'] = $key = implode('/', $key); } } // Set the key and bucket on the request $request->getParams()->set('bucket', $bucket)->set('key', $key); // Switch to virtual if PathStyle is disabled, or not a DNS compatible bucket name, or the scheme is // http, or the scheme is https and there are no dots in the host header (avoids SSL issues) if (!$command['PathStyle'] && $command->getClient()->isValidBucketName($bucket) && !($command->getRequest()->getScheme() == 'https' && strpos($bucket, '.'))) { // Switch to virtual hosted bucket $request->setHost($bucket . '.' . $request->getHost()); $request->setPath(preg_replace("#^/{$bucket}#", '', $request->getPath())); } else { $pathStyle = true; } if (!$bucket) { $request->getParams()->set('s3.resource', '/'); } elseif ($pathStyle) { // Path style does not need a trailing slash $request->getParams()->set('s3.resource', '/' . rawurlencode($bucket) . ($key ? '/' . S3Client::encodeKey($key) : '')); } else { // Bucket style needs a trailing slash $request->getParams()->set('s3.resource', '/' . rawurlencode($bucket) . ($key ? '/' . S3Client::encodeKey($key) : '/')); } }
public function createPresignedUrl(RequestInterface $request, CredentialsInterface $credentials, $expires) { // Operate on a clone of the request, so the original is not altered. $request = clone $request; // URL encoding already occurs in the URI template expansion. Undo that // and encode using the same encoding as GET object, PUT object, etc. $path = S3Client::encodeKey(rawurldecode($request->getPath())); $request->setPath($path); // Make sure to handle temporary credentials if ($token = $credentials->getSecurityToken()) { $request->setHeader('X-Amz-Security-Token', $token); $request->getQuery()->set('X-Amz-Security-Token', $token); } if ($expires instanceof \DateTime) { $expires = $expires->getTimestamp(); } elseif (!is_numeric($expires)) { $expires = strtotime($expires); } // Set query params required for pre-signed URLs $query = $request->getQuery(); $query['AWSAccessKeyId'] = $credentials->getAccessKeyId(); $query['Expires'] = $expires; $query['Signature'] = $this->signString($this->createCanonicalizedString($request, $expires), $credentials); // Move X-Amz-* headers to the query string foreach ($request->getHeaders() as $name => $header) { $name = strtolower($name); if (strpos($name, 'x-amz-') === 0) { $request->getQuery()->set($name, implode(',', $header)); $request->removeHeader($name); } } return $request->getUrl(); }
private function modifyRequest(RequestInterface $request, CommandInterface $command) { $uri = $request->getUri(); $path = $uri->getPath(); $bucket = $command['Bucket']; $path = $this->removeBucketFromPath($path, $bucket); // Modify the Key to make sure the key is encoded, but slashes are not. if ($command['Key']) { $path = S3Client::encodeKey(rawurldecode($path)); } return $request->withUri($uri->withPath($path)); }
/** * Changes how buckets are referenced in the HTTP request * * @param PreparedEvent $event Event emitted */ public function setBucketStyle(PreparedEvent $event) { $command = $event->getCommand(); $request = $event->getRequest(); $bucket = $command['Bucket']; $path = $request->getPath(); if (!$bucket || isset(self::$exclusions[$command->getName()])) { return; } if ($this->bucketEndpoint) { $path = $this->removeBucketFromPath($path, $bucket); } elseif (!$command['PathStyle'] && S3Client::isBucketDnsCompatible($bucket) && !($request->getScheme() == 'https' && strpos($bucket, '.'))) { // Switch to virtual if PathStyle is disabled, or not a DNS // compatible bucket name, or the scheme is https and there are no // dots in the hostheader (avoids SSL issues). $request->setHost($bucket . '.' . $request->getHost()); $path = $this->removeBucketFromPath($path, $bucket); } // Modify the Key to make sure the key is encoded, but slashes are not. if ($command['Key']) { $path = S3Client::encodeKey(rawurldecode($path)); } $request->setPath($path); }
public function copy($path1, $path2) { $path1 = $this->normalizePath($path1); $path2 = $this->normalizePath($path2); if ($this->is_file($path1)) { try { $result = $this->connection->copyObject(array('Bucket' => $this->bucket, 'Key' => $this->cleanKey($path2), 'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1))); $this->testTimeout(); } catch (S3Exception $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } } else { if ($this->file_exists($path2)) { return false; } try { $result = $this->connection->copyObject(array('Bucket' => $this->bucket, 'Key' => $path2 . '/', 'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/'))); $this->testTimeout(); } catch (S3Exception $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } $dh = $this->opendir($path1); if (is_resource($dh)) { while (($file = readdir($dh)) !== false) { if ($file === '.' || $file === '..') { continue; } $source = $path1 . '/' . $file; $target = $path2 . '/' . $file; $this->copy($source, $target); } } } return true; }
/** * Create a canonicalized resource for a request * * @param RequestInterface $request Request for the resource * * @return string */ private function createCanonicalizedResource(RequestInterface $request) { $buffer = $request->getParams()->get('s3.resource'); // When sending a raw HTTP request (e.g. $client->get()) if (null === $buffer) { $bucket = $request->getParams()->get('bucket') ?: $this->parseBucketName($request); // Use any specified bucket name, the parsed bucket name, or no bucket name when interacting with GetService $buffer = $bucket ? "/{$bucket}" : ''; // Remove encoding from the path and use the S3 specific encoding $path = S3Client::encodeKey(rawurldecode($request->getPath())); // if the bucket was path style, then ensure that the bucket wasn't duplicated in the resource $buffer .= preg_replace("#^/{$bucket}/{$bucket}#", "/{$bucket}", $path); } // Remove double slashes $buffer = str_replace('//', '/', $buffer); // Add sub resource parameters $query = $request->getQuery(); $first = true; foreach ($this->signableQueryString as $key) { if ($query->hasKey($key)) { $value = $query[$key]; $buffer .= $first ? '?' : '&'; $first = false; $buffer .= $key; // Don't add values for empty sub-resources if ($value !== '' && $value !== false && $value !== null && $value !== QueryString::BLANK) { $buffer .= "={$value}"; } } } return $buffer; }
public function copy($path1, $path2) { $path1 = $this->normalizePath($path1); $path2 = $this->normalizePath($path2); if ($this->is_file($path1)) { try { $this->getConnection()->copyObject(array('Bucket' => $this->bucket, 'Key' => $this->cleanKey($path2), 'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1))); $this->testTimeout(); } catch (S3Exception $e) { \OCP\Util::logException('files_external', $e); return false; } } else { $this->remove($path2); try { $this->getConnection()->copyObject(array('Bucket' => $this->bucket, 'Key' => $path2 . '/', 'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/'))); $this->testTimeout(); } catch (S3Exception $e) { \OCP\Util::logException('files_external', $e); return false; } $dh = $this->opendir($path1); if (is_resource($dh)) { while (($file = readdir($dh)) !== false) { if (\OC\Files\Filesystem::isIgnoredDir($file)) { continue; } $source = $path1 . '/' . $file; $target = $path2 . '/' . $file; $this->copy($source, $target); } } } return true; }
/** * encodeKey * * @param string $key * * @return string */ public static function encodeKey($key) { return S3Client::encodeKey($key); }
public function testProperlyEncodesPrefixKeys() { $this->assertEquals('/foo/baz%20/bar%21', S3Client::encodeKey('/foo/baz /bar!')); $client = $this->getServiceBuilder()->get('s3', true); $command = $client->getCommand('PutObject', array('Key' => 'foo/baz /bar!', 'Bucket' => 'test', 'Body' => '')); $command->prepare(); $this->assertEquals('/foo/baz%20/bar%21', $command->getRequest()->getPath()); $this->assertEquals('test.s3.amazonaws.com', $command->getRequest()->getHost()); }
protected function computePath($path) { $this->ensureBucketExists(); return S3Client::encodeKey($path); }
/** * Changes how buckets are referenced in the HTTP request * * @param Event $event Event emitted */ public function onCommandAfterPrepare(Event $event) { $command = $event['command']; $bucket = $command['Bucket']; $request = $command->getRequest(); // Skip operations that do not need the bucket moved to the host. if (isset(self::$exclusions[$command->getName()])) { return; } if ($key = $command['Key']) { // Modify the command Key to account for the {/Key*} explosion into an array if (is_array($key)) { $command['Key'] = $key = implode('/', $key); } } // Set the key and bucket on the request $request->getParams()->set('bucket', $bucket)->set('key', $key); // Switch to virtual if PathStyle is disabled, or not a DNS compatible bucket name, or the scheme is // http, or the scheme is https and there are no dots in the host header (avoids SSL issues) // This is the initial code, automatically switching to VirtualHost /* if (!$command['PathStyle'] && $command->getClient()->isValidBucketName($bucket) && !($command->getRequest()->getScheme() == 'https' && strpos($bucket, '.')) ) { // Switch to virtual hosted bucket $request->setHost($bucket . '.' . $request->getHost()); $request->setPath(preg_replace("#^/{$bucket}#", '', $request->getPath())); } else { $pathStyle = true; } */ $pathStyle = true; if (!$bucket) { $request->getParams()->set('s3.resource', '/'); } elseif ($pathStyle) { // Path style does not need a trailing slash $path = $request->getPath(); $request->setHost(str_replace($bucket . ".", "", $request->getHost())); $request->setPath('/' . rawurlencode($bucket) . ($path == "/" ? "" : $path)); $request->getParams()->set('s3.resource', '/' . rawurlencode($bucket) . ($key ? '/' . S3Client::encodeKey($key) : '')); } else { // Bucket style needs a trailing slash $request->getParams()->set('s3.resource', '/' . rawurlencode($bucket) . ($key ? '/' . S3Client::encodeKey($key) : '/')); } }