diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5f088e8be7..866ed861d9 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -830,6 +830,7 @@ phutil_register_library_map(array( 'PhabricatorChatLogQuery' => 'applications/chatlog/PhabricatorChatLogQuery.php', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php', 'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php', + 'PhabricatorConduitConfigOptions' => 'applications/conduit/config/PhabricatorConduitConfigOptions.php', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/PhabricatorConduitConnectionLog.php', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/PhabricatorConduitConsoleController.php', 'PhabricatorConduitController' => 'applications/conduit/controller/PhabricatorConduitController.php', @@ -2601,6 +2602,7 @@ phutil_register_library_map(array( 'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO', + 'PhabricatorConduitConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitController' => 'PhabricatorController', diff --git a/src/aphront/configuration/AphrontApplicationConfiguration.php b/src/aphront/configuration/AphrontApplicationConfiguration.php index c5eee79179..4e71a29c7b 100644 --- a/src/aphront/configuration/AphrontApplicationConfiguration.php +++ b/src/aphront/configuration/AphrontApplicationConfiguration.php @@ -113,18 +113,33 @@ abstract class AphrontApplicationConfiguration { } } - $path = $request->getPath(); - $host = $request->getHost(); - $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); - $prod_uri = PhabricatorEnv::getEnvConfig('phabricator.production-uri'); - $file_uri = PhabricatorEnv::getEnvConfig('security.alternate-file-domain'); + $path = $request->getPath(); + $host = $request->getHost(); + $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); + $prod_uri = PhabricatorEnv::getEnvConfig('phabricator.production-uri'); + $file_uri = PhabricatorEnv::getEnvConfig( + 'security.alternate-file-domain'); + $conduit_uris = PhabricatorEnv::getEnvConfig('conduit.servers'); + + $uris = array_merge( + array( + $base_uri, + $prod_uri, + $file_uri, + ), + $conduit_uris); + + $host_match = false; + foreach ($uris as $uri) { + if ($host === id(new PhutilURI($uri))->getDomain()) { + $host_match = true; + break; + } + } // NOTE: If the base URI isn't defined yet, don't activate alternate // domains. - if ($base_uri && - $host != id(new PhutilURI($base_uri))->getDomain() && - $host != id(new PhutilURI($prod_uri))->getDomain() && - $host != id(new PhutilURI($file_uri))->getDomain()) { + if ($base_uri && !$host_match) { try { $blog = id(new PhameBlogQuery()) diff --git a/src/applications/conduit/call/ConduitCall.php b/src/applications/conduit/call/ConduitCall.php index 29172c53e3..1b98dccb47 100644 --- a/src/applications/conduit/call/ConduitCall.php +++ b/src/applications/conduit/call/ConduitCall.php @@ -13,10 +13,14 @@ final class ConduitCall { private $method; private $request; private $user; + private $servers; + private $forceLocal; public function __construct($method, array $params) { - $this->method = $method; - $this->handler = $this->buildMethodHandler($method); + $this->method = $method; + $this->handler = $this->buildMethodHandler($method); + $this->servers = PhabricatorEnv::getEnvConfig('conduit.servers'); + $this->forceLocal = false; $invalid_params = array_diff_key( $params, @@ -27,6 +31,16 @@ final class ConduitCall { implode("', '", array_keys($invalid_params)) . "'."); } + if ($this->servers) { + $current_host = AphrontRequest::getHTTPHeader('HOST'); + foreach ($this->servers as $server) { + if ($current_host === id(new PhutilURI($server))->getDomain()) { + $this->forceLocal = true; + break; + } + } + } + $this->request = new ConduitAPIRequest($params); } @@ -39,6 +53,15 @@ final class ConduitCall { return $this->user; } + public function setForceLocal($force_local) { + $this->forceLocal = $force_local; + return $this; + } + + public function shouldForceLocal() { + return $this->forceLocal; + } + public function shouldRequireAuthentication() { return $this->handler->shouldRequireAuthentication(); } @@ -64,7 +87,35 @@ final class ConduitCall { $this->request->setUser($this->getUser()); } - return $this->handler->executeMethod($this->request); + if (!$this->shouldForceLocal() && $this->servers) { + $server = $this->pickRandomServer($this->servers); + $client = new ConduitClient($server); + $params = $this->request->getAllParameters(); + + $params["__conduit__"]["isProxied"] = true; + + if ($this->handler->shouldRequireAuthentication()) { + $client->callMethodSynchronous( + 'conduit.connect', + array( + 'client' => 'PhabricatorConduit', + 'clientVersion' => '1.0', + 'user' => $this->getUser()->getUserName(), + 'certificate' => $this->getUser()->getConduitCertificate(), + '__conduit__' => $params["__conduit__"], + )); + } + + return $client->callMethodSynchronous( + $this->method, + $params); + } else { + return $this->handler->executeMethod($this->request); + } + } + + protected function pickRandomServer($servers) { + return $servers[array_rand($servers)]; } protected function buildMethodHandler($method) { diff --git a/src/applications/conduit/call/__tests__/ConduitCallTestCase.php b/src/applications/conduit/call/__tests__/ConduitCallTestCase.php index d5e0c6f3ed..51bef15039 100644 --- a/src/applications/conduit/call/__tests__/ConduitCallTestCase.php +++ b/src/applications/conduit/call/__tests__/ConduitCallTestCase.php @@ -4,13 +4,15 @@ final class ConduitCallTestCase extends PhabricatorTestCase { public function testConduitPing() { $call = new ConduitCall('conduit.ping', array()); + $call->setForceLocal(true); $result = $call->execute(); $this->assertEqual(false, empty($result)); } public function testConduitAuth() { - $call = new ConduitCall('user.whoami', array()); + $call = new ConduitCall('user.whoami', array(), true); + $call->setForceLocal(true); $caught = null; try { diff --git a/src/applications/conduit/config/PhabricatorConduitConfigOptions.php b/src/applications/conduit/config/PhabricatorConduitConfigOptions.php new file mode 100644 index 0000000000..11f00d7ec0 --- /dev/null +++ b/src/applications/conduit/config/PhabricatorConduitConfigOptions.php @@ -0,0 +1,31 @@ +newOption("conduit.servers", "list", array()) + ->setLocked(true) + ->setSummary(pht("Servers that conduit can connect to.")) + ->setDescription( + pht( + "Set an array of servers where conduit can connect to. This is ". + "an advanced option. Don't touch this unless you know what you ". + "are doing.")) + ->addExample( + '["http://phabricator2.example.com/", '. + '"http://phabricator3.example.com/]"', + pht('Valid Setting')), + ); + } + +} diff --git a/src/applications/conduit/controller/PhabricatorConduitAPIController.php b/src/applications/conduit/controller/PhabricatorConduitAPIController.php index 412ee74f47..83908d73d5 100644 --- a/src/applications/conduit/controller/PhabricatorConduitAPIController.php +++ b/src/applications/conduit/controller/PhabricatorConduitAPIController.php @@ -35,7 +35,8 @@ final class PhabricatorConduitAPIController $metadata = idx($params, '__conduit__', array()); unset($params['__conduit__']); - $call = new ConduitCall($method, $params); + $call = new ConduitCall( + $method, $params, idx($metadata, 'isProxied', false)); $result = null; diff --git a/src/applications/differential/conduit/ConduitAPI_differential_finishpostponedlinters_Method.php b/src/applications/differential/conduit/ConduitAPI_differential_finishpostponedlinters_Method.php index 759d969670..47b3261808 100644 --- a/src/applications/differential/conduit/ConduitAPI_differential_finishpostponedlinters_Method.php +++ b/src/applications/differential/conduit/ConduitAPI_differential_finishpostponedlinters_Method.php @@ -98,6 +98,7 @@ final class ConduitAPI_differential_finishpostponedlinters_Method 'diff_id' => $diff_id, 'name' => 'arc:lint', 'data' => json_encode($messages))); + $call->setForceLocal(true); $call->setUser($request->getUser()); $call->execute(); $call = new ConduitCall( @@ -106,6 +107,7 @@ final class ConduitAPI_differential_finishpostponedlinters_Method 'diff_id' => $diff_id, 'name' => 'arc:lint-postponed', 'data' => json_encode($postponed_linters))); + $call->setForceLocal(true); $call->setUser($request->getUser()); $call->execute();