From 443d72ee87fa1b67863d5666f2fcd4eb3dc7b390 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 15 Mar 2016 17:22:16 +0100 Subject: [PATCH 1/2] Fix dropbox storage to not store the whole file in memory Since the library can only store the full response in memory on download, we use an alternate client lib and set the correct headers to be able to stream the content to a temp file. --- .../3rdparty/Dropbox/OAuth/Curl.php | 2 +- apps/files_external/lib/dropbox.php | 34 +++++++++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/apps/files_external/3rdparty/Dropbox/OAuth/Curl.php b/apps/files_external/3rdparty/Dropbox/OAuth/Curl.php index fd66e34bd2d..41134511b80 100644 --- a/apps/files_external/3rdparty/Dropbox/OAuth/Curl.php +++ b/apps/files_external/3rdparty/Dropbox/OAuth/Curl.php @@ -196,7 +196,7 @@ class Dropbox_OAuth_Curl extends Dropbox_OAuth { * @return array Array for request's headers section like * array('Authorization' => 'OAuth ...'); */ - private function getOAuthHeader($uri, $params, $method = 'GET', $oAuthParams = null) { + public function getOAuthHeader($uri, $params, $method = 'GET', $oAuthParams = null) { $oAuthParams = $oAuthParams ? $oAuthParams : $this->getOAuthBaseParams(); // create baseString to encode for the sent parameters diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php index 3c4022f24ce..f59b5a460e1 100644 --- a/apps/files_external/lib/dropbox.php +++ b/apps/files_external/lib/dropbox.php @@ -39,6 +39,7 @@ class Dropbox extends \OC\Files\Storage\Common { private $root; private $id; private $metaData = array(); + private $oauth; private static $tempFiles = array(); @@ -51,10 +52,10 @@ class Dropbox extends \OC\Files\Storage\Common { ) { $this->root = isset($params['root']) ? $params['root'] : ''; $this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $this->root; - $oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']); - $oauth->setToken($params['token'], $params['token_secret']); + $this->oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']); + $this->oauth->setToken($params['token'], $params['token_secret']); // note: Dropbox_API connection is lazy - $this->dropbox = new \Dropbox_API($oauth, 'auto'); + $this->dropbox = new \Dropbox_API($this->oauth, 'auto'); } else { throw new \Exception('Creating \OC\Files\Storage\Dropbox storage failed'); } @@ -248,10 +249,31 @@ class Dropbox extends \OC\Files\Storage\Common { switch ($mode) { case 'r': case 'rb': - $tmpFile = \OCP\Files::tmpFile(); try { - $data = $this->dropbox->getFile($path); - file_put_contents($tmpFile, $data); + // slashes need to stay + $encodedPath = str_replace('%2F', '/', rawurlencode(trim($path, '/'))); + $downloadUrl = 'https://api-content.dropbox.com/1/files/auto/' . $encodedPath; + $headers = $this->oauth->getOAuthHeader($downloadUrl, [], 'GET'); + + $client = \OC::$server->getHTTPClientService()->newClient(); + try { + $tmpFile = \OC::$server->getTempManager()->getTemporaryFile(); + $client->get($downloadUrl, [ + 'headers' => $headers, + 'save_to' => $tmpFile, + ]); + } catch (RequestException $e) { + if (!is_null($e->getResponse())) { + if ($e->getResponse()->getStatusCode() === 404) { + return false; + } else { + throw $e; + } + } else { + throw $e; + } + } + return fopen($tmpFile, 'r'); } catch (\Exception $exception) { \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); From 195cf4111e7d9ec4e3984d69f60818d7de8eb47d Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 23 Mar 2016 15:38:20 +0100 Subject: [PATCH 2/2] Dropbox stream download with RetryWrapper --- apps/files_external/lib/dropbox.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php index f59b5a460e1..8381ccbae59 100644 --- a/apps/files_external/lib/dropbox.php +++ b/apps/files_external/lib/dropbox.php @@ -29,7 +29,9 @@ namespace OC\Files\Storage; +use GuzzleHttp\Exception\RequestException; use Icewind\Streams\IteratorDirectory; +use Icewind\Streams\RetryWrapper; require_once __DIR__ . '/../3rdparty/Dropbox/autoload.php'; @@ -257,10 +259,9 @@ class Dropbox extends \OC\Files\Storage\Common { $client = \OC::$server->getHTTPClientService()->newClient(); try { - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile(); - $client->get($downloadUrl, [ + $response = $client->get($downloadUrl, [ 'headers' => $headers, - 'save_to' => $tmpFile, + 'stream' => true, ]); } catch (RequestException $e) { if (!is_null($e->getResponse())) { @@ -274,7 +275,8 @@ class Dropbox extends \OC\Files\Storage\Common { } } - return fopen($tmpFile, 'r'); + $handle = $response->getBody(); + return RetryWrapper::wrap($handle); } catch (\Exception $exception) { \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false;