protected function getProxiedFuture() { if (!$this->future) { $params = $this->params; if (!$this->action) { throw new Exception(pht('You must %s!', 'setRawGitHubQuery()')); } if (!$this->accessToken) { throw new Exception(pht('You must %s!', 'setAccessToken()')); } $uri = new PhutilURI('https://api.github.com/'); $uri->setPath('/' . ltrim($this->action, '/')); $future = new HTTPSFuture($uri); $future->setData($this->params); $future->addHeader('Authorization', 'token ' . $this->accessToken); // NOTE: GitHub requires a 'User-Agent' header. $future->addHeader('User-Agent', __CLASS__); $future->setMethod($this->method); foreach ($this->headers as $header) { list($key, $value) = $header; $future->addHeader($key, $value); } $this->future = $future; } return $this->future; }
public static function getServerStatus() { $uri = PhabricatorEnv::getEnvConfig('notification.server-uri'); $uri = new PhutilURI($uri); $uri->setPath('/status/'); list($body) = id(new HTTPSFuture($uri))->setTimeout(3)->resolvex(); $status = json_decode($body, true); if (!is_array($status)) { throw new Exception(pht('Expected JSON response from notification server, received: %s', $body)); } return $status; }
protected function run() { $argv = $this->getArgv(); if (count($argv) !== 1) { throw new Exception(pht('Usage: %s %s', __CLASS__, '<json_config_file>')); } $json_raw = Filesystem::readFile($argv[0]); try { $config = phutil_json_decode($json_raw); } catch (PhutilJSONParserException $ex) { throw new PhutilProxyException(pht("File '%s' is not valid JSON!", $argv[0]), $ex); } $nick = idx($config, 'nick', 'phabot'); $handlers = idx($config, 'handlers', array()); $protocol_adapter_class = idx($config, 'protocol-adapter', 'PhabricatorIRCProtocolAdapter'); $this->pollFrequency = idx($config, 'poll-frequency', 1); $this->config = $config; foreach ($handlers as $handler) { $obj = newv($handler, array($this)); $this->handlers[] = $obj; } $ca_bundle = idx($config, 'https.cabundle'); if ($ca_bundle) { HTTPSFuture::setGlobalCABundleFromPath($ca_bundle); } $conduit_uri = idx($config, 'conduit.uri'); if ($conduit_uri) { $conduit_token = idx($config, 'conduit.token'); // Normalize the path component of the URI so users can enter the // domain without the "/api/" part. $conduit_uri = new PhutilURI($conduit_uri); $conduit_host = (string) $conduit_uri->setPath('/'); $conduit_uri = (string) $conduit_uri->setPath('/api/'); $conduit = new ConduitClient($conduit_uri); if ($conduit_token) { $conduit->setConduitToken($conduit_token); } else { $conduit_user = idx($config, 'conduit.user'); $conduit_cert = idx($config, 'conduit.cert'); $response = $conduit->callMethodSynchronous('conduit.connect', array('client' => __CLASS__, 'clientVersion' => '1.0', 'clientDescription' => php_uname('n') . ':' . $nick, 'host' => $conduit_host, 'user' => $conduit_user, 'certificate' => $conduit_cert)); } $this->conduit = $conduit; } // Instantiate Protocol Adapter, for now follow same technique as // handler instantiation $this->protocolAdapter = newv($protocol_adapter_class, array()); $this->protocolAdapter->setConfig($this->config)->connect(); $this->runLoop(); $this->protocolAdapter->disconnect(); }
public function getRedirectURI() { if (strlen($this->getAlias())) { $path = '/u/' . $this->getAlias(); } else { $path = '/u/' . $this->getID(); } $short_domain = PhabricatorEnv::getEnvConfig('phurl.short-uri'); if (!$short_domain) { return $path; } $uri = new PhutilURI($short_domain); $uri->setPath($path); return (string) $uri; }
protected function validateHost($host) { if (!$host) { // If the client doesn't send a host key, don't complain. We should in // the future, but this change isn't severe enough to bump the protocol // version. // TODO: Remove this once the protocol version gets bumped past 2 (i.e., // require the host key be present and valid). return; } $host = new PhutilURI($host); $host->setPath('/'); $host = (string) $host; $self = PhabricatorEnv::getProductionURI('/'); if ($self !== $host) { throw new Exception("Your client is connecting to this install as '{$host}', but it is " . "configured as '{$self}'. The client and server must use the exact " . "same URI to identify the install. Edit your .arcconfig or " . "phabricator/conf so they agree on the URI for the install."); } }
protected function getProxiedFuture() { if (!$this->future) { $params = $this->params; if (!$this->action) { throw new Exception(pht('You must %s!', 'setRawSlackQuery()')); } if (!$this->accessToken) { throw new Exception(pht('You must %s!', 'setAccessToken()')); } $uri = new PhutilURI('https://slack.com/'); $uri->setPath('/api/' . $this->action); $uri->setQueryParam('token', $this->accessToken); $future = new HTTPSFuture($uri); $future->setData($this->params); $future->setMethod($this->method); $this->future = $future; } return $this->future; }
public function processRequest() { $uri = PhabricatorEnv::getEnvConfig('notification.server-uri'); $uri = new PhutilURI($uri); $uri->setPath('/status/'); $future = id(new HTTPSFuture($uri))->setTimeout(3); try { list($body) = $future->resolvex(); $body = json_decode($body, true); if (!is_array($body)) { throw new Exception("Expected JSON response from server!"); } $status = $this->renderServerStatus($body); } catch (Exception $ex) { $status = new AphrontErrorView(); $status->setTitle("Notification Server Issue"); $status->appendChild('Unable to determine server status. This probably means the server ' . 'is not in great shape. The specific issue encountered was:' . '<br />' . '<br />' . '<strong>' . phutil_escape_html(get_class($ex)) . '</strong> ' . nl2br(phutil_escape_html($ex->getMessage()))); } return $this->buildStandardPageResponse($status, array('title' => 'Aphlict Server Status')); }
protected function getProxiedFuture() { if (!$this->future) { $params = $this->params; if (!$this->action) { throw new Exception(pht('You must %s!', 'setRawAsanaQuery()')); } if (!$this->accessToken) { throw new Exception(pht('You must %s!', 'setAccessToken()')); } $uri = new PhutilURI('https://app.asana.com/'); $uri->setPath('/api/1.0/' . ltrim($this->action, '/')); $future = new HTTPSFuture($uri); $future->setData($this->params); $future->addHeader('Authorization', 'Bearer ' . $this->accessToken); $future->setMethod($this->method); $this->future = $future; } return $this->future; }
protected function getProxiedFuture() { if (!$this->future) { $params = $this->params; if (!$this->action) { throw new Exception("You must setRawWordPressQuery()!"); } if (!$this->accessToken) { throw new Exception("You must setAccessToken()!"); } $uri = new PhutilURI('https://public-api.wordpress.com/'); $uri->setPath('/rest/v1/' . ltrim($this->action, '/')); $future = new HTTPSFuture($uri); $future->setData($this->params); $future->setMethod($this->method); // NOTE: This is how WordPress.com REST API authenticates $future->addHeader('Authorization', 'Bearer ' . $this->accessToken); $this->future = $future; } return $this->future; }
public function processRequest() { $request = $this->getRequest(); $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain'); $uri = new PhutilURI($alt); $alt_domain = $uri->getDomain(); if ($alt_domain && $alt_domain != $request->getHost()) { return id(new AphrontRedirectResponse())->setURI($uri->setPath($request->getPath())); } $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $this->phid); if (!$file) { return new Aphront404Response(); } if (!$file->validateSecretKey($this->key)) { return new Aphront403Response(); } $data = $file->loadFileData(); $response = new AphrontFileResponse(); $response->setContent($data); $response->setCacheDurationInSeconds(60 * 60 * 24 * 30); $is_view = $file->isViewableInBrowser(); if ($is_view) { $response->setMimeType($file->getViewableMimeType()); } else { if (!$request->isHTTPPost()) { // NOTE: Require POST to download files. We'd rather go full-bore and // do a real CSRF check, but can't currently authenticate users on the // file domain. This should blunt any attacks based on iframes, script // tags, applet tags, etc., at least. Send the user to the "info" page // if they're using some other method. return id(new AphrontRedirectResponse())->setURI(PhabricatorEnv::getProductionURI($file->getBestURI())); } $response->setMimeType($file->getMimeType()); $response->setDownload($file->getName()); } return $response; }
protected function getProxiedFuture() { if (!$this->future) { $params = $this->params; if (!$this->action) { throw new Exception('You must setRawTwitchQuery()!'); } if (!$this->accessToken) { throw new Exception('You must setAccessToken()!'); } $uri = new PhutilURI('https://api.twitch.tv/'); $uri->setPath('/kraken/' . ltrim($this->action, '/')); $uri->setQueryParam('oauth_token', $this->accessToken); $future = new HTTPSFuture($uri); $future->setData($this->params); $future->setMethod($this->method); // NOTE: This is how the Twitch API is versioned. $future->addHeader('Accept', 'application/vnd.twitchtv.2+json'); // NOTE: This is required to avoid rate limiting. $future->addHeader('Client-ID', $this->clientID); $this->future = $future; } return $this->future; }
public function getViewURI() { if (!$this->getPHID()) { throw new Exception("You must save a file before you can generate a view URI."); } $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain'); if ($alt) { $path = '/file/alt/' . $this->getSecretKey() . '/' . $this->getPHID() . '/'; $uri = new PhutilURI($alt); $uri->setPath($path); return (string) $uri; } else { return '/file/view/' . $this->getPHID() . '/'; } }
private function getURIObject() { // Users can provide Git/SCP-style URIs in the form "user@host:path". // In the general case, these are not equivalent to any "ssh://..." form // because the path is relative. if ($this->isBuiltin()) { $builtin_protocol = $this->getForcedProtocol(); $builtin_domain = $this->getForcedHost(); $raw_uri = "{$builtin_protocol}://{$builtin_domain}"; } else { $raw_uri = $this->getURI(); } $port = $this->getForcedPort(); $default_ports = array('ssh' => 22, 'http' => 80, 'https' => 443); $uri = new PhutilURI($raw_uri); // Make sure to remove any password from the URI before we do anything // with it; this should always be provided by the associated credential. $uri->setPass(null); $protocol = $this->getForcedProtocol(); if ($protocol) { $uri->setProtocol($protocol); } if ($port) { $uri->setPort($port); } // Remove any explicitly set default ports. $uri_port = $uri->getPort(); $uri_protocol = $uri->getProtocol(); $uri_default = idx($default_ports, $uri_protocol); if ($uri_default && $uri_default == $uri_port) { $uri->setPort(null); } $user = $this->getForcedUser(); if ($user) { $uri->setUser($user); } $host = $this->getForcedHost(); if ($host) { $uri->setDomain($host); } $path = $this->getForcedPath(); if ($path) { $uri->setPath($path); } return $uri; }
if ($force_conduit) { $conduit_uri = $force_conduit; } else { $conduit_uri = $configuration_manager->getConfigFromAnySource('phabricator.uri'); if ($conduit_uri === null) { $conduit_uri = $configuration_manager->getConfigFromAnySource('default'); } } if ($conduit_uri) { // Set the URI path to '/api/'. TODO: Originally, I contemplated letting // you deploy Phabricator somewhere other than the domain root, but ended // up never pursuing that. We should get rid of all "/api/" silliness // in things users are expected to configure. This is already happening // to some degree, e.g. "arc install-certificate" does it for you. $conduit_uri = new PhutilURI($conduit_uri); $conduit_uri->setPath('/api/'); $conduit_uri = (string) $conduit_uri; } $workflow->setConduitURI($conduit_uri); // Apply global CA bundle from configs. $ca_bundle = $configuration_manager->getConfigFromAnySource('https.cabundle'); if ($ca_bundle) { $ca_bundle = Filesystem::resolvePath($ca_bundle, $working_copy->getProjectRoot()); HTTPSFuture::setGlobalCABundleFromPath($ca_bundle); } $blind_key = 'https.blindly-trust-domains'; $blind_trust = $configuration_manager->getConfigFromAnySource($blind_key); if ($blind_trust) { HTTPSFuture::setBlindlyTrustDomains($blind_trust); } if ($need_conduit) {
private function makeInternalURI($uri_string) { $uri = new PhutilURI($uri_string); $proto = $uri->getProtocol(); if ($proto !== 'svn+ssh') { throw new Exception(pht('Protocol for URI "%s" MUST be "svn+ssh".', $uri_string)); } $path = $uri->getPath(); // Subversion presumably deals with this, but make sure there's nothing // skethcy going on with the URI. if (preg_match('(/\\.\\./)', $path)) { throw new Exception(pht('String "/../" is invalid in path specification "%s".', $uri_string)); } $repository = $this->loadRepository($path); $path = preg_replace('(^/diffusion/[A-Z]+)', rtrim($repository->getLocalPath(), '/'), $path); if (preg_match('(^/diffusion/[A-Z]+/\\z)', $path)) { $path = rtrim($path, '/'); } $uri->setPath($path); // If this is happening during the handshake, these are the base URIs for // the request. if ($this->externalBaseURI === null) { $pre = (string) id(clone $uri)->setPath(''); $this->externalBaseURI = $pre . '/diffusion/' . $repository->getCallsign(); $this->internalBaseURI = $pre . rtrim($repository->getLocalPath(), '/'); } return (string) $uri; }
private function makeInternalURI($uri_string) { if ($this->isProxying) { return $uri_string; } $uri = new PhutilURI($uri_string); $repository = $this->getRepository(); $path = $this->getPathFromSubversionURI($uri_string); $external_base = $this->getBaseRequestPath(); // Replace "/diffusion/X" in the request with the repository local path, // so "/diffusion/X/master/" becomes "/path/to/repository/X/master/". $local_path = rtrim($repository->getLocalPath(), '/'); $path = $local_path . substr($path, strlen($external_base)); // NOTE: We are intentionally NOT removing username information from the // URI. Subversion retains it over the course of the request and considers // two repositories with different username identifiers to be distinct and // incompatible. $uri->setPath($path); // If this is happening during the handshake, these are the base URIs for // the request. if ($this->externalBaseURI === null) { $pre = (string) id(clone $uri)->setPath(''); $external_path = $external_base; $external_path = $this->normalizeSVNPath($external_path); $this->externalBaseURI = $pre . $external_path; $internal_path = rtrim($repository->getLocalPath(), '/'); $internal_path = $this->normalizeSVNPath($internal_path); $this->internalBaseURI = $pre . $internal_path; } return (string) $uri; }
public function run() { $argv = $this->getArgv(); if (count($argv) !== 1) { throw new Exception("usage: PhabricatorIRCBot <json_config_file>"); } $json_raw = Filesystem::readFile($argv[0]); $config = json_decode($json_raw, true); if (!is_array($config)) { throw new Exception("File '{$argv[0]}' is not valid JSON!"); } $server = idx($config, 'server'); $port = idx($config, 'port', 6667); $handlers = idx($config, 'handlers', array()); $pass = idx($config, 'pass'); $nick = idx($config, 'nick', 'phabot'); $user = idx($config, 'user', $nick); $ssl = idx($config, 'ssl', false); $nickpass = idx($config, 'nickpass'); $this->config = $config; if (!preg_match('/^[A-Za-z0-9_`[{}^|\\]\\-]+$/', $nick)) { throw new Exception("Nickname '{$nick}' is invalid!"); } foreach ($handlers as $handler) { $obj = newv($handler, array($this)); $this->handlers[] = $obj; } $conduit_uri = idx($config, 'conduit.uri'); if ($conduit_uri) { $conduit_user = idx($config, 'conduit.user'); $conduit_cert = idx($config, 'conduit.cert'); // Normalize the path component of the URI so users can enter the // domain without the "/api/" part. $conduit_uri = new PhutilURI($conduit_uri); $conduit_uri->setPath('/api/'); $conduit_uri = (string) $conduit_uri; $conduit = new ConduitClient($conduit_uri); $response = $conduit->callMethodSynchronous('conduit.connect', array('client' => 'PhabricatorIRCBot', 'clientVersion' => '1.0', 'clientDescription' => php_uname('n') . ':' . $nick, 'user' => $conduit_user, 'certificate' => $conduit_cert)); $this->conduit = $conduit; } $errno = null; $error = null; if (!$ssl) { $socket = fsockopen($server, $port, $errno, $error); } else { $socket = fsockopen('ssl://' . $server, $port, $errno, $error); } if (!$socket) { throw new Exception("Failed to connect, #{$errno}: {$error}"); } $ok = stream_set_blocking($socket, false); if (!$ok) { throw new Exception("Failed to set stream nonblocking."); } $this->socket = $socket; $this->writeCommand('USER', "{$user} 0 * :{$user}"); if ($pass) { $this->writeCommand('PASS', "{$pass}"); } $this->writeCommand('NICK', "{$nick}"); $this->runSelectLoop(); }
protected final function getURI($path) { $base_uri = new PhutilURI($this->bot->getConfig('conduit.uri')); $base_uri->setPath($path); return (string) $base_uri; }
public function testURIGeneration() { $uri = new PhutilURI('http://example.com'); $uri->setPath('bar'); $this->assertEqual('http://example.com/bar', $uri->__toString()); }
public static function getJIRAIssueBrowseURIFromJIRARestURI($uri, $object_id) { $uri = new PhutilURI($uri); // The JIRA install might not be at the domain root, so we may need to // keep an initial part of the path, like "/jira/". Find the API specific // part of the URI, strip it off, then replace it with the web version. $path = $uri->getPath(); $pos = strrpos($path, 'rest/api/2/issue/'); if ($pos === false) { return null; } $path = substr($path, 0, $pos); $path = $path . 'browse/' . $object_id; $uri->setPath($path); return (string) $uri; }
private function determineConduitURI() { $uri = $this->getArgument('uri'); if (count($uri) > 1) { throw new ArcanistUsageException(pht('Specify at most one URI.')); } else { if (count($uri) == 1) { $uri = reset($uri); } else { $conduit_uri = $this->getConduitURI(); if (!$conduit_uri) { throw new ArcanistUsageException(pht('Specify an explicit URI or run this command from within a ' . 'project which is configured with a %s.', '.arcconfig')); } $uri = $conduit_uri; } } $uri_object = new PhutilURI($uri); if (!$uri_object->getProtocol() || !$uri_object->getDomain()) { throw new ArcanistUsageException(pht('Server URI "%s" must include a protocol and domain. It should be ' . 'in the form "%s".', $uri, 'https://phabricator.example.com/')); } $uri_object->setPath('/api/'); return (string) $uri_object; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $viewer_is_anonymous = !$user->isLoggedIn(); $params = array_filter(array('status' => $request->getStr('status'), 'order' => $request->getStr('order'))); $default_filter = $viewer_is_anonymous ? 'all' : 'active'; $filters = $this->getFilters(); $this->filter = $this->selectFilter($filters, $this->filter, $default_filter); // Redirect from search to canonical URL. $phid_arr = $request->getArr('view_user'); if ($phid_arr) { $view_user = id(new PhabricatorUser())->loadOneWhere('phid = %s', head($phid_arr)); $base_uri = '/differential/filter/' . $this->filter . '/'; if ($view_user) { // This is a user, so generate a pretty URI. $uri = $base_uri . phutil_escape_uri($view_user->getUserName()) . '/'; } else { // We're assuming this is a mailing list, generate an ugly URI. $uri = $base_uri; $params['phid'] = head($phid_arr); } $uri = new PhutilURI($uri); $uri->setQueryParams($params); return id(new AphrontRedirectResponse())->setURI($uri); } $uri = new PhutilURI('/differential/filter/' . $this->filter . '/'); $uri->setQueryParams($params); $username = ''; if ($this->username) { $view_user = id(new PhabricatorUser())->loadOneWhere('userName = %s', $this->username); if (!$view_user) { return new Aphront404Response(); } $username = phutil_escape_uri($this->username) . '/'; $uri->setPath('/differential/filter/' . $this->filter . '/' . $username); $params['phid'] = $view_user->getPHID(); } else { $phid = $request->getStr('phid'); if (strlen($phid)) { $params['phid'] = $phid; } } // Fill in the defaults we'll actually use for calculations if any // parameters are missing. $params += array('phid' => $user->getPHID(), 'status' => 'all', 'order' => 'modified'); $side_nav = new AphrontSideNavView(); foreach ($filters as $filter) { list($filter_name, $display_name) = $filter; if ($filter_name) { $href = clone $uri; $href->setPath('/differential/filter/' . $filter_name . '/' . $username); if ($filter_name == $this->filter) { $class = 'aphront-side-nav-selected'; } else { $class = null; } $item = phutil_render_tag('a', array('href' => (string) $href, 'class' => $class), phutil_escape_html($display_name)); } else { $item = phutil_render_tag('span', array(), phutil_escape_html($display_name)); } $side_nav->addNavItem($item); } $panels = array(); $handles = array(); $controls = $this->getFilterControls($this->filter); if ($this->getFilterRequiresUser($this->filter) && !$params['phid']) { // In the anonymous case, we still want to let you see some user's // list, but we don't have a default PHID to provide (normally, we use // the viewing user's). Show a warning instead. $warning = new AphrontErrorView(); $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING); $warning->setTitle('User Required'); $warning->appendChild('This filter requires that a user be specified above.'); $panels[] = $warning; } else { $query = $this->buildQuery($this->filter, $params['phid']); $pager = null; if ($this->getFilterAllowsPaging($this->filter)) { $pager = new AphrontPagerView(); $pager->setOffset($request->getInt('page')); $pager->setPageSize(1000); $pager->setURI($uri, 'page'); $query->setOffset($pager->getOffset()); $query->setLimit($pager->getPageSize() + 1); } foreach ($controls as $control) { $this->applyControlToQuery($control, $query, $params); } $revisions = $query->execute(); if ($pager) { $revisions = $pager->sliceResults($revisions); } $views = $this->buildViews($this->filter, $params['phid'], $revisions); $view_objects = array(); foreach ($views as $view) { if (empty($view['special'])) { $view_objects[] = $view['view']; } } $phids = array_mergev(mpull($view_objects, 'getRequiredHandlePHIDs')); $phids[] = $params['phid']; $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); foreach ($views as $view) { if (empty($view['special'])) { $view['view']->setHandles($handles); } $panel = new AphrontPanelView(); $panel->setHeader($view['title']); $panel->appendChild($view['view']); if ($pager) { $panel->appendChild($pager); } $panels[] = $panel; } } $filter_form = id(new AphrontFormView())->setMethod('GET')->setAction('/differential/filter/' . $this->filter . '/')->setUser($user); foreach ($controls as $control) { $control_view = $this->renderControl($control, $handles, $uri, $params); $filter_form->appendChild($control_view); } $filter_form->addHiddenInput('status', $params['status'])->addHiddenInput('order', $params['order'])->appendChild(id(new AphrontFormSubmitControl())->setValue('Filter Revisions')); $filter_view = new AphrontListFilterView(); $filter_view->appendChild($filter_form); if (!$viewer_is_anonymous) { $create_uri = new PhutilURI('/differential/diff/create/'); $filter_view->addButton(phutil_render_tag('a', array('href' => (string) $create_uri, 'class' => 'green button'), 'Create Revision')); } $side_nav->appendChild($filter_view); foreach ($panels as $panel) { $side_nav->appendChild($panel); } return $this->buildStandardPageResponse($side_nav, array('title' => 'Differential Home')); }
/** * Get the fully-qualified production URI for a static resource path. * * @task read */ public static function getCDNURI($path) { $alt = self::getEnvConfig('security.alternate-file-domain'); if (!$alt) { $alt = self::getEnvConfig('phabricator.base-uri'); } $uri = new PhutilURI($alt); $uri->setPath($path); return (string) $uri; }
private function executeRequest($path, array $data, $method = 'GET') { $uri = new PhutilURI($this->uri); $uri->setPath($this->index); $uri->appendPath($path); $data = json_encode($data); $future = new HTTPSFuture($uri, $data); if ($method != 'GET') { $future->setMethod($method); } if ($this->getTimeout()) { $future->setTimeout($this->getTimeout()); } list($body) = $future->resolvex(); if ($method != 'GET') { return null; } try { return phutil_json_decode($body); } catch (PhutilJSONParserException $ex) { throw new PhutilProxyException(pht('ElasticSearch server returned invalid JSON!'), $ex); } }
/** * Build a new @{class:HTTPSFuture} which proxies this request to another * node in the cluster. * * IMPORTANT: This is very dangerous! * * The future forwards authentication information present in the request. * Proxied requests must only be sent to trusted hosts. (We attempt to * enforce this.) * * This is not a general-purpose proxying method; it is a specialized * method with niche applications and severe security implications. * * @param string URI identifying the host we are proxying the request to. * @return HTTPSFuture New proxy future. * * @phutil-external-symbol class PhabricatorStartup */ public function newClusterProxyFuture($uri) { $uri = new PhutilURI($uri); $domain = $uri->getDomain(); $ip = gethostbyname($domain); if (!$ip) { throw new Exception(pht('Unable to resolve domain "%s"!', $domain)); } if (!PhabricatorEnv::isClusterAddress($ip)) { throw new Exception(pht('Refusing to proxy a request to IP address ("%s") which is not ' . 'in the cluster address block (this address was derived by ' . 'resolving the domain "%s").', $ip, $domain)); } $uri->setPath($this->getPath()); $uri->setQueryParams(self::flattenData($_GET)); $input = PhabricatorStartup::getRawInput(); $future = id(new HTTPSFuture($uri))->addHeader('Host', self::getHost())->addHeader('X-Phabricator-Cluster', true)->setMethod($_SERVER['REQUEST_METHOD'])->write($input); if (isset($_SERVER['PHP_AUTH_USER'])) { $future->setHTTPBasicAuthCredentials($_SERVER['PHP_AUTH_USER'], new PhutilOpaqueEnvelope(idx($_SERVER, 'PHP_AUTH_PW', ''))); } $headers = array(); $seen = array(); // NOTE: apache_request_headers() might provide a nicer way to do this, // but isn't available under FCGI until PHP 5.4.0. foreach ($_SERVER as $key => $value) { if (preg_match('/^HTTP_/', $key)) { // Unmangle the header as best we can. $key = str_replace('_', ' ', $key); $key = strtolower($key); $key = ucwords($key); $key = str_replace(' ', '-', $key); $headers[] = array($key, $value); $seen[$key] = true; } } // In some situations, this may not be mapped into the HTTP_X constants. // CONTENT_LENGTH is similarly affected, but we trust cURL to take care // of that if it matters, since we're handing off a request body. if (empty($seen['Content-Type'])) { if (isset($_SERVER['CONTENT_TYPE'])) { $headers[] = array('Content-Type', $_SERVER['CONTENT_TYPE']); } } foreach ($headers as $header) { list($key, $value) = $header; switch ($key) { case 'Host': case 'Authorization': // Don't forward these headers, we've already handled them elsewhere. unset($headers[$key]); break; default: break; } } foreach ($headers as $header) { list($key, $value) = $header; $future->addHeader($key, $value); } return $future; }
protected function performPost($endpoint, $data = null) { $uri = new PhutilURI($this->server); $uri->setPath($endpoint); $payload = json_encode($data); list($output) = id(new HTTPSFuture($uri))->setMethod('POST')->addHeader('Content-Type', 'application/json')->addHeader('Authorization', $this->getAuthorizationHeader())->setData($payload)->resolvex(); $output = trim($output); if (strlen($output)) { return json_decode($output, true); } return true; }
private function executeRequest($path, array $data, $is_write = false) { $uri = new PhutilURI($this->uri); $data = json_encode($data); $uri->setPath($path); $future = new HTTPSFuture($uri, $data); if ($is_write) { $future->setMethod('PUT'); } if ($this->getTimeout()) { $future->setTimeout($this->getTimeout()); } list($body) = $future->resolvex(); if ($is_write) { return null; } $body = json_decode($body, true); if (!is_array($body)) { throw new Exception("elasticsearch server returned invalid JSON!"); } return $body; }
private function determineConduitURI() { $uri = $this->getArgument('uri'); if (count($uri) > 1) { throw new ArcanistUsageException("Specify at most one URI."); } else { if (count($uri) == 1) { $uri = reset($uri); } else { $conduit_uri = $this->getConduitURI(); if (!$conduit_uri) { throw new ArcanistUsageException("Specify an explicit URI or run this command from within a project " . "which is configured with a .arcconfig."); } $uri = $conduit_uri; } } $uri = new PhutilURI($uri); $uri->setPath('/api/'); return (string) $uri; }
/** * Get the repository's HTTP clone/checkout URI, if one exists. */ public function getHTTPCloneURIObject() { if (!$this->isHosted()) { if ($this->shouldUseHTTP()) { return $this->getRemoteURIObject(); } else { return null; } } $serve_http = $this->getServeOverHTTP(); if ($serve_http === self::SERVE_OFF) { return null; } $uri = PhabricatorEnv::getProductionURI($this->getURI()); $uri = new PhutilURI($uri); if ($this->isGit()) { $uri->setPath($uri->getPath() . $this->getCloneName() . '.git'); } else { if ($this->isHg()) { $uri->setPath($uri->getPath() . $this->getCloneName() . '/'); } } return $uri; }
private function getRawHTTPCloneURIObject() { $uri = PhabricatorEnv::getProductionURI($this->getURI()); $uri = new PhutilURI($uri); if ($this->isGit()) { $uri->setPath($uri->getPath() . $this->getCloneName() . '.git'); } else { if ($this->isHg()) { $uri->setPath($uri->getPath() . $this->getCloneName() . '/'); } } return $uri; }