Changeset View
Changeset View
Standalone View
Standalone View
src/applications/files/storage/PhabricatorFile.php
Show First 20 Lines • Show All 445 Lines • ▼ Show 20 Lines | if (!$engine_identifier || strlen($engine_identifier) > 32) { | ||||
"identifier '{$engine_identifier}': it must be nonempty ". | "identifier '{$engine_identifier}': it must be nonempty ". | ||||
"and no longer than 32 characters."); | "and no longer than 32 characters."); | ||||
} | } | ||||
return array($engine_identifier, $data_handle); | return array($engine_identifier, $data_handle); | ||||
} | } | ||||
/** | |||||
* Download a remote resource over HTTP and save the response body as a file. | |||||
* | |||||
* This method respects `security.outbound-blacklist`, and protects against | |||||
* HTTP redirection (by manually following "Location" headers and verifying | |||||
* each destination). It does not protect against DNS rebinding. See | |||||
* discussion in T6755. | |||||
*/ | |||||
public static function newFromFileDownload($uri, array $params = array()) { | public static function newFromFileDownload($uri, array $params = array()) { | ||||
$timeout = 5; | |||||
$redirects = array(); | |||||
$current = $uri; | |||||
while (true) { | |||||
try { | |||||
if (count($redirects) > 10) { | |||||
throw new Exception( | |||||
pht('Too many redirects trying to fetch remote URI.')); | |||||
} | |||||
PhabricatorEnv::requireValidRemoteURIForFetch( | PhabricatorEnv::requireValidRemoteURIForFetch( | ||||
$uri, | $current, | ||||
array( | array( | ||||
'http', | 'http', | ||||
'https', | 'https', | ||||
)); | )); | ||||
$timeout = 5; | list($status, $body, $headers) = id(new HTTPSFuture($current)) | ||||
list($file_data) = id(new HTTPSFuture($uri)) | ->setFollowLocation(false) | ||||
->setTimeout($timeout) | ->setTimeout($timeout) | ||||
->resolvex(); | ->resolve(); | ||||
if ($status->isRedirect()) { | |||||
// This is an HTTP 3XX status, so look for a "Location" header. | |||||
$location = null; | |||||
foreach ($headers as $header) { | |||||
list($name, $value) = $header; | |||||
if (phutil_utf8_strtolower($name) == 'location') { | |||||
$location = $value; | |||||
break; | |||||
} | |||||
} | |||||
// HTTP 3XX status with no "Location" header, just treat this like | |||||
// a normal HTTP error. | |||||
if ($location === null) { | |||||
throw $status; | |||||
} | |||||
if (isset($redirects[$location])) { | |||||
throw new Exception( | |||||
pht( | |||||
'Encountered loop while following redirects.')); | |||||
} | |||||
$redirects[$location] = $location; | |||||
$current = $location; | |||||
// We'll fall off the bottom and go try this URI now. | |||||
} else if ($status->isError()) { | |||||
// This is something other than an HTTP 2XX or HTTP 3XX status, so | |||||
// just bail out. | |||||
throw $status; | |||||
} else { | |||||
// This is HTTP 2XX, so use the the response body to save the | |||||
// file data. | |||||
$params = $params + array( | $params = $params + array( | ||||
'name' => basename($uri), | 'name' => basename($uri), | ||||
); | ); | ||||
return self::newFromFileData($file_data, $params); | return self::newFromFileData($body, $params); | ||||
} | |||||
} catch (Exception $ex) { | |||||
if ($redirects) { | |||||
throw new PhutilProxyException( | |||||
pht( | |||||
'Failed to fetch remote URI "%s" after following %s redirect(s) '. | |||||
'(%s): %s', | |||||
$uri, | |||||
new PhutilNumber(count($redirects)), | |||||
implode(' > ', array_keys($redirects)), | |||||
$ex->getMessage()), | |||||
$ex); | |||||
} else { | |||||
throw $ex; | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
public static function normalizeFileName($file_name) { | public static function normalizeFileName($file_name) { | ||||
$pattern = "@[\\x00-\\x19#%&+!~'\$\"\/=\\\\?<> ]+@"; | $pattern = "@[\\x00-\\x19#%&+!~'\$\"\/=\\\\?<> ]+@"; | ||||
$file_name = preg_replace($pattern, '_', $file_name); | $file_name = preg_replace($pattern, '_', $file_name); | ||||
$file_name = preg_replace('@_+@', '_', $file_name); | $file_name = preg_replace('@_+@', '_', $file_name); | ||||
$file_name = trim($file_name, '_'); | $file_name = trim($file_name, '_'); | ||||
▲ Show 20 Lines • Show All 822 Lines • Show Last 20 Lines |