/** * @phutil-external-symbol class PhabricatorStartup */ public function handleRequest(AphrontRequest $request) { $raw_body = PhabricatorStartup::getRawInput(); $body = phutil_json_decode($raw_body); $payload = $body['payload']; $parameters = idx($payload, 'build_parameters'); if (!$parameters) { $parameters = array(); } $target_phid = idx($parameters, 'HARBORMASTER_BUILD_TARGET_PHID'); // NOTE: We'll get callbacks here for builds we triggered, but also for // arbitrary builds the system executes for other reasons. So it's normal // to get some notifications with no Build Target PHID. We just ignore // these under the assumption that they're routine builds caused by events // like branch updates. if ($target_phid) { $viewer = PhabricatorUser::getOmnipotentUser(); $target = id(new HarbormasterBuildTargetQuery())->setViewer($viewer)->withPHIDs(array($target_phid))->needBuildSteps(true)->executeOne(); if ($target) { $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $this->updateTarget($target, $payload); } } $response = new AphrontWebpageResponse(); $response->setContent(pht("Request OK\n")); return $response; }
/** * @phutil-external-symbol class PhabricatorStartup */ public function buildRequest() { $parser = new PhutilQueryStringParser(); $data = array(); // If the request has "multipart/form-data" content, we can't use // PhutilQueryStringParser to parse it, and the raw data supposedly is not // available anyway (according to the PHP documentation, "php://input" is // not available for "multipart/form-data" requests). However, it is // available at least some of the time (see T3673), so double check that // we aren't trying to parse data we won't be able to parse correctly by // examining the Content-Type header. $content_type = idx($_SERVER, 'CONTENT_TYPE'); $is_form_data = preg_match('@^multipart/form-data@i', $content_type); $raw_input = PhabricatorStartup::getRawInput(); if (strlen($raw_input) && !$is_form_data) { $data += $parser->parseQueryString($raw_input); } else { if ($_POST) { $data += $_POST; } } $data += $parser->parseQueryString(idx($_SERVER, 'QUERY_STRING', '')); $cookie_prefix = PhabricatorEnv::getEnvConfig('phabricator.cookie-prefix'); $request = new AphrontRequest($this->getHost(), $this->getPath()); $request->setRequestData($data); $request->setApplicationConfiguration($this); $request->setCookiePrefix($cookie_prefix); return $request; }
/** * @phutil-external-symbol class PhabricatorStartup */ public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); // NOTE: Throws if valid CSRF token is not present in the request. $request->validateCSRF(); $name = $request->getStr('name'); $file_phid = $request->getStr('phid'); // If there's no explicit view policy, make it very restrictive by default. // This is the correct policy for files dropped onto objects during // creation, comment and edit flows. $view_policy = $request->getStr('viewPolicy'); if (!$view_policy) { $view_policy = $viewer->getPHID(); } $is_chunks = $request->getBool('querychunks'); if ($is_chunks) { $params = array('filePHID' => $file_phid); $result = id(new ConduitCall('file.querychunks', $params))->setUser($viewer)->execute(); return id(new AphrontAjaxResponse())->setContent($result); } $is_allocate = $request->getBool('allocate'); if ($is_allocate) { $params = array('name' => $name, 'contentLength' => $request->getInt('length'), 'viewPolicy' => $view_policy); $result = id(new ConduitCall('file.allocate', $params))->setUser($viewer)->execute(); $file_phid = $result['filePHID']; if ($file_phid) { $file = $this->loadFile($file_phid); $result += $this->getFileDictionary($file); } return id(new AphrontAjaxResponse())->setContent($result); } // Read the raw request data. We're either doing a chunk upload or a // vanilla upload, so we need it. $data = PhabricatorStartup::getRawInput(); $is_chunk_upload = $request->getBool('uploadchunk'); if ($is_chunk_upload) { $params = array('filePHID' => $file_phid, 'byteStart' => $request->getInt('byteStart'), 'data' => $data); $result = id(new ConduitCall('file.uploadchunk', $params))->setUser($viewer)->execute(); $file = $this->loadFile($file_phid); if ($file->getIsPartial()) { $result = array(); } else { $result = array('complete' => true) + $this->getFileDictionary($file); } return id(new AphrontAjaxResponse())->setContent($result); } $file = PhabricatorFile::newFromXHRUpload($data, array('name' => $request->getStr('name'), 'authorPHID' => $viewer->getPHID(), 'viewPolicy' => $view_policy, 'isExplicitUpload' => true)); $result = $this->getFileDictionary($file); return id(new AphrontAjaxResponse())->setContent($result); }
/** * @phutil-external-symbol class PhabricatorStartup */ public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); // NOTE: Throws if valid CSRF token is not present in the request. $request->validateCSRF(); $data = PhabricatorStartup::getRawInput(); $name = $request->getStr('name'); // If there's no explicit view policy, make it very restrictive by default. // This is the correct policy for files dropped onto objects during // creation, comment and edit flows. $view_policy = $request->getStr('viewPolicy'); if (!$view_policy) { $view_policy = $viewer->getPHID(); } $file = PhabricatorFile::newFromXHRUpload($data, array('name' => $request->getStr('name'), 'authorPHID' => $viewer->getPHID(), 'viewPolicy' => $view_policy, 'isExplicitUpload' => true)); return id(new AphrontAjaxResponse())->setContent(array('id' => $file->getID(), 'phid' => $file->getPHID(), 'uri' => $file->getBestURI())); }
private function serveMercurialRequest(PhabricatorRepository $repository, PhabricatorUser $viewer) { $request = $this->getRequest(); $bin = Filesystem::resolveBinary('hg'); if (!$bin) { throw new Exception(pht('Unable to find `%s` in %s!', 'hg', '$PATH')); } $env = $this->getCommonEnvironment($viewer); $input = PhabricatorStartup::getRawInput(); $cmd = $request->getStr('cmd'); $args = $this->getMercurialArguments(); $args = $this->formatMercurialArguments($cmd, $args); if (strlen($input)) { $input = strlen($input) . "\n" . $input . "0\n"; } $command = csprintf('%s serve --stdio', $bin); $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); list($err, $stdout, $stderr) = id(new ExecFuture('%C', $command))->setEnv($env, true)->setCWD($repository->getLocalPath())->write("{$cmd}\n{$args}{$input}")->resolve(); if ($err) { return new PhabricatorVCSResponse(500, pht('Error %d: %s', $err, $stderr)); } if ($cmd == 'getbundle' || $cmd == 'changegroup' || $cmd == 'changegroupsubset') { // We're not completely sure that "changegroup" and "changegroupsubset" // actually work, they're for very old Mercurial. $body = gzcompress($stdout); } else { if ($cmd == 'unbundle') { // This includes diagnostic information and anything echoed by commit // hooks. We ignore `stdout` since it just has protocol garbage, and // substitute `stderr`. $body = strlen($stderr) . "\n" . $stderr; } else { list($length, $body) = explode("\n", $stdout, 2); if ($cmd == 'capabilities') { $body = DiffusionMercurialWireProtocol::filterBundle2Capability($body); } } } return id(new DiffusionMercurialResponse())->setContent($body); }
private function getGitLFSInput() { if (!$this->gitLFSInput) { $input = PhabricatorStartup::getRawInput(); $input = phutil_json_decode($input); $this->gitLFSInput = $input; } return $this->gitLFSInput; }
/** * 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; }