Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15458496
D16090.id38715.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D16090.id38715.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -211,6 +211,7 @@
'PhutilGitURI' => 'parser/PhutilGitURI.php',
'PhutilGitURITestCase' => 'parser/__tests__/PhutilGitURITestCase.php',
'PhutilGoogleAuthAdapter' => 'auth/PhutilGoogleAuthAdapter.php',
+ 'PhutilHTTPEngineExtension' => 'future/http/PhutilHTTPEngineExtension.php',
'PhutilHangForeverDaemon' => 'daemon/torture/PhutilHangForeverDaemon.php',
'PhutilHashingIterator' => 'utils/PhutilHashingIterator.php',
'PhutilHashingIteratorTestCase' => 'utils/__tests__/PhutilHashingIteratorTestCase.php',
@@ -770,6 +771,7 @@
'PhutilGitURI' => 'Phobject',
'PhutilGitURITestCase' => 'PhutilTestCase',
'PhutilGoogleAuthAdapter' => 'PhutilOAuthAuthAdapter',
+ 'PhutilHTTPEngineExtension' => 'Phobject',
'PhutilHangForeverDaemon' => 'PhutilTortureTestDaemon',
'PhutilHashingIterator' => array(
'PhutilProxyIterator',
diff --git a/src/future/http/HTTPSFuture.php b/src/future/http/HTTPSFuture.php
--- a/src/future/http/HTTPSFuture.php
+++ b/src/future/http/HTTPSFuture.php
@@ -9,7 +9,6 @@
private static $results = array();
private static $pool = array();
private static $globalCABundle;
- private static $blindTrustDomains = array();
private $handle;
private $profilerCallID;
@@ -118,17 +117,6 @@
}
/**
- * Set a list of domains to blindly trust. Certificates for these domains
- * will not be validated.
- *
- * @param list<string> List of domain names to trust blindly.
- * @return void
- */
- public static function setBlindlyTrustDomains(array $domains) {
- self::$blindTrustDomains = array_fuse($domains);
- }
-
- /**
* Load contents of remote URI. Behaves pretty much like
* `@file_get_contents($uri)` but doesn't require `allow_url_fopen`.
*
@@ -187,11 +175,15 @@
$domain = id(new PhutilURI($uri))->getDomain();
if (!$this->handle) {
+ $uri_object = new PhutilURI($uri);
+ $proxy = PhutilHTTPEngineExtension::buildHTTPProxyURI($uri_object);
+
$profiler = PhutilServiceProfiler::getInstance();
$this->profilerCallID = $profiler->beginServiceCall(
array(
'type' => 'http',
'uri' => $uri,
+ 'proxy' => (string)$proxy,
));
if (!self::$multi) {
@@ -347,15 +339,26 @@
curl_setopt($curl, CURLOPT_CAINFO, $this->getCABundle());
}
- $domain = id(new PhutilURI($uri))->getDomain();
- if (!empty(self::$blindTrustDomains[$domain])) {
- // Disable peer verification for domains that we blindly trust.
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
- } else {
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
+ $verify_peer = 1;
+ $verify_host = 2;
+
+ $extensions = PhutilHTTPEngineExtension::getAllExtensions();
+ foreach ($extensions as $extension) {
+ if ($extension->shouldTrustAnySSLAuthorityForURI($uri_object)) {
+ $verify_peer = 0;
+ }
+ if ($extension->shouldTrustAnySSLHostnameForURI($uri_object)) {
+ $verify_host = 0;
+ }
}
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $verify_peer);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $verify_host);
curl_setopt($curl, CURLOPT_SSLVERSION, 0);
+
+ if ($proxy) {
+ curl_setopt($curl, CURLOPT_PROXY, (string)$proxy);
+ }
} else {
$curl = $this->handle;
diff --git a/src/future/http/PhutilHTTPEngineExtension.php b/src/future/http/PhutilHTTPEngineExtension.php
new file mode 100644
--- /dev/null
+++ b/src/future/http/PhutilHTTPEngineExtension.php
@@ -0,0 +1,141 @@
+<?php
+
+/**
+ * Extend HTTP behavior by injecting proxies or compromising SSL.
+ *
+ * @task info Extension Information
+ * @task config Configuring HTTP Behavior
+ */
+abstract class PhutilHTTPEngineExtension
+ extends Phobject {
+
+
+ /**
+ * Human-readable name of this HTTP extension.
+ *
+ * @return string Human readable name.
+ * @task info
+ */
+ abstract public function getExtensionName();
+
+
+ /**
+ * Return `true` to disable SSL authority verification for a URI.
+ *
+ * By default, certificates must be signed by a recognized authority and
+ * requests fail if the host provides an invalid certificate. You can
+ * override this behavior to accept any certificate (including self-signed
+ * certificates). Doing this compromises the security of SSL.
+ *
+ * @return bool Return `true` to disable authority verification.
+ * @task config
+ */
+ public function shouldTrustAnySSLAuthorityForURI(PhutilURI $uri) {
+ return false;
+ }
+
+
+ /**
+ * Return `true` to disable SSL hostname verification for a URI.
+ *
+ * By default, certificates should be signed for the correct hostname,
+ * and requests fail if the host provides a certificate for a different
+ * hostname. You can override this behavior to accept any certificate,
+ * including certificates for a different host. Doing this compromises
+ * the security of SSL.
+ *
+ * @return bool Return `true` to disable hostname verification.
+ * @task config
+ */
+ public function shouldTrustAnySSLHostnameForURI(PhutilURI $uri) {
+ return false;
+ }
+
+
+ /**
+ * Return a @{class:PhutilURI} to proxy requests.
+ *
+ * If some or all outbound HTTP requests must be proxied, you can return
+ * the URI for a proxy to use from this method.
+ *
+ * @return null|PhutilURI Proxy URI.
+ * @task config
+ */
+ public function getHTTPProxyURI(PhutilURI $uri) {
+ return null;
+ }
+
+
+ final public function getExtensionKey() {
+ return $this->getPhobjectClassConstant('EXTENSIONKEY');
+ }
+
+ final public static function getAllExtensions() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getExtensionKey')
+ ->execute();
+ }
+
+ final public static function getExtension($key) {
+ $extensions = self::getAllExtensions();
+ return idx($extensions, $key);
+ }
+
+ final public static function requireExtension($key) {
+ $extension = self::getExtension($key);
+
+ if (!$extension) {
+ throw new Exception(
+ pht(
+ 'No HTTP engine extension exists with extension key "%s".',
+ $key));
+ }
+
+ return $extension;
+ }
+
+ final public static function buildHTTPProxyURI(PhutilURI $uri) {
+ $proxy = null;
+ $via = null;
+
+ $extensions = self::getAllExtensions();
+ foreach ($extensions as $extension) {
+ $extension_proxy = $extension->getHTTPProxyURI($uri);
+
+ if ($extension_proxy === null) {
+ continue;
+ }
+
+ if (!($extension_proxy instanceof PhutilURI)) {
+ throw new Exception(
+ pht(
+ 'HTTP extension "%s" (of class "%s") returned an invalid '.
+ 'result from "%s": expected null, or an object of class "%s".',
+ $extension->getExtensionName(),
+ get_class($extension),
+ 'getHTTPProxyURI()',
+ 'PhutilURI'));
+ }
+
+ if ($proxy) {
+ throw new Exception(
+ pht(
+ 'Two different HTTP extensions ("%s" of class "%s" and "%s" of '.
+ 'class "%s") both provided a proxy URI for URI "%s". No more '.
+ 'than one extension may provide a proxy for any URI.',
+ $extension->getExtensionName(),
+ get_class($extension),
+ $via->getExtensionName(),
+ get_class($via),
+ (string)$uri));
+ }
+
+ $proxy = $extension_proxy;
+ $via = $extension;
+ }
+
+ return $proxy;
+ }
+
+}
diff --git a/src/serviceprofiler/PhutilServiceProfiler.php b/src/serviceprofiler/PhutilServiceProfiler.php
--- a/src/serviceprofiler/PhutilServiceProfiler.php
+++ b/src/serviceprofiler/PhutilServiceProfiler.php
@@ -109,7 +109,20 @@
}
break;
case 'http':
- $desc = phutil_censor_credentials($data['uri']);
+ if (isset($data['proxy'])) {
+ $proxy = phutil_censor_credentials($data['proxy']);
+ } else {
+ $proxy = null;
+ }
+
+ $uri = phutil_censor_credentials($data['uri']);
+
+ if (strlen($proxy)) {
+ $desc = "{$proxy} >> {$uri}";
+ } else {
+ $desc = $uri;
+ }
+
break;
case 'lint':
$desc = $data['linter'];
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 1, 4:04 AM (18 h, 52 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7227748
Default Alt Text
D16090.id38715.diff (8 KB)
Attached To
Mode
D16090: Introduce PhutilHTTPEngineExtension, for flexibly compromising SSL
Attached
Detach File
Event Timeline
Log In to Comment