diff --git a/src/aphront/configuration/AphrontApplicationConfiguration.php b/src/aphront/configuration/AphrontApplicationConfiguration.php index b89feaebb5..c0cd259992 100644 --- a/src/aphront/configuration/AphrontApplicationConfiguration.php +++ b/src/aphront/configuration/AphrontApplicationConfiguration.php @@ -1,718 +1,721 @@ request = $request; return $this; } final public function getRequest() { return $this->request; } final public function getConsole() { return $this->console; } final public function setConsole($console) { $this->console = $console; return $this; } final public function setHost($host) { $this->host = $host; return $this; } final public function getHost() { return $this->host; } final public function setPath($path) { $this->path = $path; return $this; } final public function getPath() { return $this->path; } public function willBuildRequest() {} /** * @phutil-external-symbol class PhabricatorStartup */ public static function runHTTPRequest(AphrontHTTPSink $sink) { if (isset($_SERVER['HTTP_X_PHABRICATOR_SELFCHECK'])) { $response = self::newSelfCheckResponse(); return self::writeResponse($sink, $response); } PhabricatorStartup::beginStartupPhase('multimeter'); $multimeter = MultimeterControl::newInstance(); $multimeter->setEventContext(''); $multimeter->setEventViewer(''); // Build a no-op write guard for the setup phase. We'll replace this with a // real write guard later on, but we need to survive setup and build a // request object first. $write_guard = new AphrontWriteGuard('id'); PhabricatorStartup::beginStartupPhase('preflight'); $response = PhabricatorSetupCheck::willPreflightRequest(); if ($response) { return self::writeResponse($sink, $response); } PhabricatorStartup::beginStartupPhase('env.init'); try { PhabricatorEnv::initializeWebEnvironment(); $database_exception = null; } catch (PhabricatorClusterStrandedException $ex) { $database_exception = $ex; } if ($database_exception) { $issue = PhabricatorSetupIssue::newDatabaseConnectionIssue( $database_exception, true); $response = PhabricatorSetupCheck::newIssueResponse($issue); return self::writeResponse($sink, $response); } $multimeter->setSampleRate( PhabricatorEnv::getEnvConfig('debug.sample-rate')); $debug_time_limit = PhabricatorEnv::getEnvConfig('debug.time-limit'); if ($debug_time_limit) { PhabricatorStartup::setDebugTimeLimit($debug_time_limit); } // This is the earliest we can get away with this, we need env config first. PhabricatorStartup::beginStartupPhase('log.access'); PhabricatorAccessLog::init(); $access_log = PhabricatorAccessLog::getLog(); PhabricatorStartup::setAccessLog($access_log); $address = PhabricatorEnv::getRemoteAddress(); if ($address) { $address_string = $address->getAddress(); } else { $address_string = '-'; } $access_log->setData( array( 'R' => AphrontRequest::getHTTPHeader('Referer', '-'), 'r' => $address_string, 'M' => idx($_SERVER, 'REQUEST_METHOD', '-'), )); DarkConsoleXHProfPluginAPI::hookProfiler(); // We just activated the profiler, so we don't need to keep track of // startup phases anymore: it can take over from here. PhabricatorStartup::beginStartupPhase('startup.done'); DarkConsoleErrorLogPluginAPI::registerErrorHandler(); $response = PhabricatorSetupCheck::willProcessRequest(); if ($response) { return self::writeResponse($sink, $response); } $host = AphrontRequest::getHTTPHeader('Host'); $path = $_REQUEST['__path__']; switch ($host) { default: $config_key = 'aphront.default-application-configuration-class'; $application = PhabricatorEnv::newObjectFromConfig($config_key); break; } $application->setHost($host); $application->setPath($path); $application->willBuildRequest(); $request = $application->buildRequest(); // Now that we have a request, convert the write guard into one which // actually checks CSRF tokens. $write_guard->dispose(); $write_guard = new AphrontWriteGuard(array($request, 'validateCSRF')); // Build the server URI implied by the request headers. If an administrator // has not configured "phabricator.base-uri" yet, we'll use this to generate // links. $request_protocol = ($request->isHTTPS() ? 'https' : 'http'); $request_base_uri = "{$request_protocol}://{$host}/"; PhabricatorEnv::setRequestBaseURI($request_base_uri); $access_log->setData( array( 'U' => (string)$request->getRequestURI()->getPath(), )); $processing_exception = null; try { $response = $application->processRequest( $request, $access_log, $sink, $multimeter); $response_code = $response->getHTTPResponseCode(); } catch (Exception $ex) { $processing_exception = $ex; $response_code = 500; } $write_guard->dispose(); $access_log->setData( array( 'c' => $response_code, 'T' => PhabricatorStartup::getMicrosecondsSinceStart(), )); $multimeter->newEvent( MultimeterEvent::TYPE_REQUEST_TIME, $multimeter->getEventContext(), PhabricatorStartup::getMicrosecondsSinceStart()); $access_log->write(); $multimeter->saveEvents(); DarkConsoleXHProfPluginAPI::saveProfilerSample($access_log); // Add points to the rate limits for this request. $rate_token = PhabricatorStartup::getRateLimitToken(); if ($rate_token !== null) { // The base score for a request allows users to make 30 requests per // minute. $score = (1000 / 30); // If the user was logged in, let them make more requests. if ($request->getUser() && $request->getUser()->getPHID()) { $score = $score / 5; } PhabricatorStartup::addRateLimitScore($rate_token, $score); } if ($processing_exception) { throw $processing_exception; } } public function processRequest( AphrontRequest $request, PhutilDeferredLog $access_log, AphrontHTTPSink $sink, MultimeterControl $multimeter) { $this->setRequest($request); list($controller, $uri_data) = $this->buildController(); $controller_class = get_class($controller); $access_log->setData( array( 'C' => $controller_class, )); $multimeter->setEventContext('web.'.$controller_class); $request->setController($controller); $request->setURIMap($uri_data); $controller->setRequest($request); // If execution throws an exception and then trying to render that // exception throws another exception, we want to show the original // exception, as it is likely the root cause of the rendering exception. $original_exception = null; try { $response = $controller->willBeginExecution(); if ($request->getUser() && $request->getUser()->getPHID()) { $access_log->setData( array( 'u' => $request->getUser()->getUserName(), 'P' => $request->getUser()->getPHID(), )); $multimeter->setEventViewer('user.'.$request->getUser()->getPHID()); } if (!$response) { $controller->willProcessRequest($uri_data); $response = $controller->handleRequest($request); $this->validateControllerResponse($controller, $response); } } catch (Exception $ex) { $original_exception = $ex; - $response = $this->handleException($ex); + $response = $this->handleThrowable($ex); + } catch (Throwable $ex) { + $original_exception = $ex; + $response = $this->handleThrowable($ex); } try { $response = $this->produceResponse($request, $response); $response = $controller->willSendResponse($response); $response->setRequest($request); self::writeResponse($sink, $response); } catch (Exception $ex) { if ($original_exception) { throw $original_exception; } throw $ex; } return $response; } private static function writeResponse( AphrontHTTPSink $sink, AphrontResponse $response) { $unexpected_output = PhabricatorStartup::endOutputCapture(); if ($unexpected_output) { $unexpected_output = pht( "Unexpected output:\n\n%s", $unexpected_output); phlog($unexpected_output); if ($response instanceof AphrontWebpageResponse) { $response->setUnexpectedOutput($unexpected_output); } } $sink->writeResponse($response); } /* -( URI Routing )-------------------------------------------------------- */ /** * Build a controller to respond to the request. * * @return pair Controller and dictionary of request * parameters. * @task routing */ final private function buildController() { $request = $this->getRequest(); // If we're configured to operate in cluster mode, reject requests which // were not received on a cluster interface. // // For example, a host may have an internal address like "170.0.0.1", and // also have a public address like "51.23.95.16". Assuming the cluster // is configured on a range like "170.0.0.0/16", we want to reject the // requests received on the public interface. // // Ideally, nodes in a cluster should only be listening on internal // interfaces, but they may be configured in such a way that they also // listen on external interfaces, since this is easy to forget about or // get wrong. As a broad security measure, reject requests received on any // interfaces which aren't on the whitelist. $cluster_addresses = PhabricatorEnv::getEnvConfig('cluster.addresses'); if ($cluster_addresses) { $server_addr = idx($_SERVER, 'SERVER_ADDR'); if (!$server_addr) { if (php_sapi_name() == 'cli') { // This is a command line script (probably something like a unit // test) so it's fine that we don't have SERVER_ADDR defined. } else { throw new AphrontMalformedRequestException( pht('No %s', 'SERVER_ADDR'), pht( 'Phabricator is configured to operate in cluster mode, but '. '%s is not defined in the request context. Your webserver '. 'configuration needs to forward %s to PHP so Phabricator can '. 'reject requests received on external interfaces.', 'SERVER_ADDR', 'SERVER_ADDR')); } } else { if (!PhabricatorEnv::isClusterAddress($server_addr)) { throw new AphrontMalformedRequestException( pht('External Interface'), pht( 'Phabricator is configured in cluster mode and the address '. 'this request was received on ("%s") is not whitelisted as '. 'a cluster address.', $server_addr)); } } } $site = $this->buildSiteForRequest($request); if ($site->shouldRequireHTTPS()) { if (!$request->isHTTPS()) { // Don't redirect intracluster requests: doing so drops headers and // parameters, imposes a performance penalty, and indicates a // misconfiguration. if ($request->isProxiedClusterRequest()) { throw new AphrontMalformedRequestException( pht('HTTPS Required'), pht( 'This request reached a site which requires HTTPS, but the '. 'request is not marked as HTTPS.')); } $https_uri = $request->getRequestURI(); $https_uri->setDomain($request->getHost()); $https_uri->setProtocol('https'); // In this scenario, we'll be redirecting to HTTPS using an absolute // URI, so we need to permit an external redirect. return $this->buildRedirectController($https_uri, true); } } $maps = $site->getRoutingMaps(); $path = $request->getPath(); $result = $this->routePath($maps, $path); if ($result) { return $result; } // If we failed to match anything but don't have a trailing slash, try // to add a trailing slash and issue a redirect if that resolves. // NOTE: We only do this for GET, since redirects switch to GET and drop // data like POST parameters. if (!preg_match('@/$@', $path) && $request->isHTTPGet()) { $result = $this->routePath($maps, $path.'/'); if ($result) { $target_uri = $request->getAbsoluteRequestURI(); // We need to restore URI encoding because the webserver has // interpreted it. For example, this allows us to redirect a path // like `/tag/aa%20bb` to `/tag/aa%20bb/`, which may eventually be // resolved meaningfully by an application. $target_path = phutil_escape_uri($path.'/'); $target_uri->setPath($target_path); $target_uri = (string)$target_uri; return $this->buildRedirectController($target_uri, true); } } $result = $site->new404Controller($request); if ($result) { return array($result, array()); } return $this->build404Controller(); } /** * Map a specific path to the corresponding controller. For a description * of routing, see @{method:buildController}. * * @param list List of routing maps. * @param string Path to route. * @return pair Controller and dictionary of request * parameters. * @task routing */ private function routePath(array $maps, $path) { foreach ($maps as $map) { $result = $map->routePath($path); if ($result) { return array($result->getController(), $result->getURIData()); } } } private function buildSiteForRequest(AphrontRequest $request) { $sites = PhabricatorSite::getAllSites(); $site = null; foreach ($sites as $candidate) { $site = $candidate->newSiteForRequest($request); if ($site) { break; } } if (!$site) { $path = $request->getPath(); $host = $request->getHost(); throw new AphrontMalformedRequestException( pht('Site Not Found'), pht( 'This request asked for "%s" on host "%s", but no site is '. 'configured which can serve this request.', $path, $host), true); } $request->setSite($site); return $site; } /* -( Response Handling )-------------------------------------------------- */ /** * Tests if a response is of a valid type. * * @param wild Supposedly valid response. * @return bool True if the object is of a valid type. * @task response */ private function isValidResponseObject($response) { if ($response instanceof AphrontResponse) { return true; } if ($response instanceof AphrontResponseProducerInterface) { return true; } return false; } /** * Verifies that the return value from an @{class:AphrontController} is * of an allowed type. * * @param AphrontController Controller which returned the response. * @param wild Supposedly valid response. * @return void * @task response */ private function validateControllerResponse( AphrontController $controller, $response) { if ($this->isValidResponseObject($response)) { return; } throw new Exception( pht( 'Controller "%s" returned an invalid response from call to "%s". '. 'This method must return an object of class "%s", or an object '. 'which implements the "%s" interface.', get_class($controller), 'handleRequest()', 'AphrontResponse', 'AphrontResponseProducerInterface')); } /** * Verifies that the return value from an * @{class:AphrontResponseProducerInterface} is of an allowed type. * * @param AphrontResponseProducerInterface Object which produced * this response. * @param wild Supposedly valid response. * @return void * @task response */ private function validateProducerResponse( AphrontResponseProducerInterface $producer, $response) { if ($this->isValidResponseObject($response)) { return; } throw new Exception( pht( 'Producer "%s" returned an invalid response from call to "%s". '. 'This method must return an object of class "%s", or an object '. 'which implements the "%s" interface.', get_class($producer), 'produceAphrontResponse()', 'AphrontResponse', 'AphrontResponseProducerInterface')); } /** * Verifies that the return value from an * @{class:AphrontRequestExceptionHandler} is of an allowed type. * * @param AphrontRequestExceptionHandler Object which produced this * response. * @param wild Supposedly valid response. * @return void * @task response */ private function validateErrorHandlerResponse( AphrontRequestExceptionHandler $handler, $response) { if ($this->isValidResponseObject($response)) { return; } throw new Exception( pht( 'Exception handler "%s" returned an invalid response from call to '. '"%s". This method must return an object of class "%s", or an object '. 'which implements the "%s" interface.', get_class($handler), 'handleRequestException()', 'AphrontResponse', 'AphrontResponseProducerInterface')); } /** * Resolves a response object into an @{class:AphrontResponse}. * * Controllers are permitted to return actual responses of class * @{class:AphrontResponse}, or other objects which implement * @{interface:AphrontResponseProducerInterface} and can produce a response. * * If a controller returns a response producer, invoke it now and produce * the real response. * * @param AphrontRequest Request being handled. * @param AphrontResponse|AphrontResponseProducerInterface Response, or * response producer. * @return AphrontResponse Response after any required production. * @task response */ private function produceResponse(AphrontRequest $request, $response) { $original = $response; // Detect cycles on the exact same objects. It's still possible to produce // infinite responses as long as they're all unique, but we can only // reasonably detect cycles, not guarantee that response production halts. $seen = array(); while (true) { // NOTE: It is permissible for an object to be both a response and a // response producer. If so, being a producer is "stronger". This is // used by AphrontProxyResponse. // If this response is a valid response, hand over the request first. if ($response instanceof AphrontResponse) { $response->setRequest($request); } // If this isn't a producer, we're all done. if (!($response instanceof AphrontResponseProducerInterface)) { break; } $hash = spl_object_hash($response); if (isset($seen[$hash])) { throw new Exception( pht( 'Failure while producing response for object of class "%s": '. 'encountered production cycle (identical object, of class "%s", '. 'was produced twice).', get_class($original), get_class($response))); } $seen[$hash] = true; $new_response = $response->produceAphrontResponse(); $this->validateProducerResponse($response, $new_response); $response = $new_response; } return $response; } /* -( Error Handling )----------------------------------------------------- */ /** * Convert an exception which has escaped the controller into a response. * * This method delegates exception handling to available subclasses of * @{class:AphrontRequestExceptionHandler}. * - * @param Exception Exception which needs to be handled. + * @param Throwable Exception which needs to be handled. * @return wild Response or response producer, or null if no available * handler can produce a response. * @task exception */ - private function handleException(Exception $ex) { + private function handleThrowable($throwable) { $handlers = AphrontRequestExceptionHandler::getAllHandlers(); $request = $this->getRequest(); foreach ($handlers as $handler) { - if ($handler->canHandleRequestException($request, $ex)) { - $response = $handler->handleRequestException($request, $ex); + if ($handler->canHandleRequestThrowable($request, $throwable)) { + $response = $handler->handleRequestThrowable($request, $throwable); $this->validateErrorHandlerResponse($handler, $response); return $response; } } - throw $ex; + throw $throwable; } private static function newSelfCheckResponse() { $path = idx($_REQUEST, '__path__', ''); $query = idx($_SERVER, 'QUERY_STRING', ''); $pairs = id(new PhutilQueryStringParser()) ->parseQueryStringToPairList($query); $params = array(); foreach ($pairs as $v) { $params[] = array( 'name' => $v[0], 'value' => $v[1], ); } $result = array( 'path' => $path, 'params' => $params, 'user' => idx($_SERVER, 'PHP_AUTH_USER'), 'pass' => idx($_SERVER, 'PHP_AUTH_PW'), // This just makes sure that the response compresses well, so reasonable // algorithms should want to gzip or deflate it. 'filler' => str_repeat('Q', 1024 * 16), ); return id(new AphrontJSONResponse()) ->setAddJSONShield(false) ->setContent($result); } } diff --git a/src/aphront/handler/AphrontRequestExceptionHandler.php b/src/aphront/handler/AphrontRequestExceptionHandler.php index 694071e1ba..e626f53cc6 100644 --- a/src/aphront/handler/AphrontRequestExceptionHandler.php +++ b/src/aphront/handler/AphrontRequestExceptionHandler.php @@ -1,36 +1,30 @@ setAncestorClass(__CLASS__) ->setSortMethod('getRequestExceptionHandlerPriority') ->execute(); } } diff --git a/src/aphront/handler/PhabricatorAjaxRequestExceptionHandler.php b/src/aphront/handler/PhabricatorAjaxRequestExceptionHandler.php index 06023e02de..d519c83fb5 100644 --- a/src/aphront/handler/PhabricatorAjaxRequestExceptionHandler.php +++ b/src/aphront/handler/PhabricatorAjaxRequestExceptionHandler.php @@ -1,38 +1,39 @@ isAjax() && !$request->isWorkflow()); } - public function handleRequestException( + public function handleRequestThrowable( AphrontRequest $request, - Exception $ex) { + $throwable) { // Log these; they don't get shown on the client and can be difficult // to debug. - phlog($ex); + phlog($throwable); $response = new AphrontAjaxResponse(); $response->setError( array( - 'code' => get_class($ex), - 'info' => $ex->getMessage(), + 'code' => get_class($throwable), + 'info' => $throwable->getMessage(), )); + return $response; } } diff --git a/src/aphront/handler/PhabricatorConduitRequestExceptionHandler.php b/src/aphront/handler/PhabricatorConduitRequestExceptionHandler.php index 367f607f83..db8a5d5ecc 100644 --- a/src/aphront/handler/PhabricatorConduitRequestExceptionHandler.php +++ b/src/aphront/handler/PhabricatorConduitRequestExceptionHandler.php @@ -1,33 +1,33 @@ isConduit(); } - public function handleRequestException( + public function handleRequestThrowable( AphrontRequest $request, - Exception $ex) { + $throwable) { $response = id(new ConduitAPIResponse()) - ->setErrorCode(get_class($ex)) - ->setErrorInfo($ex->getMessage()); + ->setErrorCode(get_class($throwable)) + ->setErrorInfo($throwable->getMessage()); return id(new AphrontJSONResponse()) ->setAddJSONShield(false) ->setContent($response->toDictionary()); } } diff --git a/src/aphront/handler/PhabricatorDefaultRequestExceptionHandler.php b/src/aphront/handler/PhabricatorDefaultRequestExceptionHandler.php index d330cd5f2c..b13100b05d 100644 --- a/src/aphront/handler/PhabricatorDefaultRequestExceptionHandler.php +++ b/src/aphront/handler/PhabricatorDefaultRequestExceptionHandler.php @@ -1,86 +1,86 @@ isPhabricatorSite($request)) { return false; } return true; } - public function handleRequestException( + public function handleRequestThrowable( AphrontRequest $request, - Exception $ex) { + $throwable) { $viewer = $this->getViewer($request); // Some types of uninteresting request exceptions don't get logged, usually // because they are caused by the background radiation of bot traffic on // the internet. These include requests with bad CSRF tokens and // questionable "Host" headers. $should_log = true; - if ($ex instanceof AphrontMalformedRequestException) { - $should_log = !$ex->getIsUnlogged(); + if ($throwable instanceof AphrontMalformedRequestException) { + $should_log = !$throwable->getIsUnlogged(); } if ($should_log) { - phlog($ex); + phlog($throwable); } - $class = get_class($ex); - $message = $ex->getMessage(); + $class = get_class($throwable); + $message = $throwable->getMessage(); - if ($ex instanceof AphrontSchemaQueryException) { + if ($throwable instanceof AphrontSchemaQueryException) { $message .= "\n\n".pht( "NOTE: This usually indicates that the MySQL schema has not been ". "properly upgraded. Run '%s' to ensure your schema is up to date.", 'bin/storage upgrade'); } if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) { $trace = id(new AphrontStackTraceView()) ->setUser($viewer) - ->setTrace($ex->getTrace()); + ->setTrace($throwable->getTrace()); } else { $trace = null; } $content = phutil_tag( 'div', array('class' => 'aphront-unhandled-exception'), array( phutil_tag('div', array('class' => 'exception-message'), $message), $trace, )); $dialog = new AphrontDialogView(); $dialog ->setTitle(pht('Unhandled Exception ("%s")', $class)) ->setClass('aphront-exception-dialog') ->setUser($viewer) ->appendChild($content); if ($request->isAjax()) { $dialog->addCancelButton('/', pht('Close')); } return id(new AphrontDialogResponse()) ->setDialog($dialog) ->setHTTPResponseCode(500); } } diff --git a/src/aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php b/src/aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php index ff4ace2e4b..f8d522711f 100644 --- a/src/aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php +++ b/src/aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php @@ -1,76 +1,76 @@ isPhabricatorSite($request)) { return false; } - return ($ex instanceof PhabricatorAuthHighSecurityRequiredException); + return ($throwable instanceof PhabricatorAuthHighSecurityRequiredException); } - public function handleRequestException( + public function handleRequestThrowable( AphrontRequest $request, - Exception $ex) { + $throwable) { $viewer = $this->getViewer($request); $form = id(new PhabricatorAuthSessionEngine())->renderHighSecurityForm( - $ex->getFactors(), - $ex->getFactorValidationResults(), + $throwable->getFactors(), + $throwable->getFactorValidationResults(), $viewer, $request); $dialog = id(new AphrontDialogView()) ->setUser($viewer) ->setTitle(pht('Entering High Security')) ->setShortTitle(pht('Security Checkpoint')) ->setWidth(AphrontDialogView::WIDTH_FORM) ->addHiddenInput(AphrontRequest::TYPE_HISEC, true) ->setErrors( array( pht( 'You are taking an action which requires you to enter '. 'high security.'), )) ->appendParagraph( pht( 'High security mode helps protect your account from security '. 'threats, like session theft or someone messing with your stuff '. 'while you\'re grabbing a coffee. To enter high security mode, '. 'confirm your credentials.')) ->appendChild($form->buildLayoutView()) ->appendParagraph( pht( 'Your account will remain in high security mode for a short '. 'period of time. When you are finished taking sensitive '. 'actions, you should leave high security.')) ->setSubmitURI($request->getPath()) - ->addCancelButton($ex->getCancelURI()) + ->addCancelButton($throwable->getCancelURI()) ->addSubmitButton(pht('Enter High Security')); $request_parameters = $request->getPassthroughRequestParameters( $respect_quicksand = true); foreach ($request_parameters as $key => $value) { $dialog->addHiddenInput($key, $value); } return $dialog; } } diff --git a/src/aphront/handler/PhabricatorPolicyRequestExceptionHandler.php b/src/aphront/handler/PhabricatorPolicyRequestExceptionHandler.php index 1c84e90fd1..cb1dea3533 100644 --- a/src/aphront/handler/PhabricatorPolicyRequestExceptionHandler.php +++ b/src/aphront/handler/PhabricatorPolicyRequestExceptionHandler.php @@ -1,93 +1,95 @@ isPhabricatorSite($request)) { return false; } - return ($ex instanceof PhabricatorPolicyException); + return ($throwable instanceof PhabricatorPolicyException); } - public function handleRequestException( + public function handleRequestThrowable( AphrontRequest $request, - Exception $ex) { + $throwable) { $viewer = $this->getViewer($request); if (!$viewer->isLoggedIn()) { // If the user isn't logged in, just give them a login form. This is // probably a generally more useful response than a policy dialog that // they have to click through to get a login form. // // Possibly we should add a header here like "you need to login to see // the thing you are trying to look at". $auth_app_class = 'PhabricatorAuthApplication'; $auth_app = PhabricatorApplication::getByClass($auth_app_class); return id(new PhabricatorAuthStartController()) ->setRequest($request) ->setCurrentApplication($auth_app) ->handleRequest($request); } $content = array( phutil_tag( 'div', array( 'class' => 'aphront-policy-rejection', ), - $ex->getRejection()), + $throwable->getRejection()), ); $list = null; - if ($ex->getCapabilityName()) { - $list = $ex->getMoreInfo(); + if ($throwable->getCapabilityName()) { + $list = $throwable->getMoreInfo(); foreach ($list as $key => $item) { $list[$key] = $item; } $content[] = phutil_tag( 'div', array( 'class' => 'aphront-capability-details', ), - pht('Users with the "%s" capability:', $ex->getCapabilityName())); + pht( + 'Users with the "%s" capability:', + $throwable->getCapabilityName())); } $dialog = id(new AphrontDialogView()) - ->setTitle($ex->getTitle()) + ->setTitle($throwable->getTitle()) ->setClass('aphront-access-dialog') ->setUser($viewer) ->appendChild($content); if ($list) { $dialog->appendList($list); } if ($request->isAjax()) { $dialog->addCancelButton('/', pht('Close')); } else { $dialog->addCancelButton('/', pht('OK')); } return $dialog; } } diff --git a/src/aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php b/src/aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php index 3fb549c29f..78dad564b4 100644 --- a/src/aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php +++ b/src/aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php @@ -1,42 +1,42 @@ isPhabricatorSite($request)) { return false; } - return ($ex instanceof PhabricatorSystemActionRateLimitException); + return ($throwable instanceof PhabricatorSystemActionRateLimitException); } - public function handleRequestException( + public function handleRequestThrowable( AphrontRequest $request, - Exception $ex) { + $throwable) { $viewer = $this->getViewer($request); return id(new AphrontDialogView()) ->setTitle(pht('Slow Down!')) ->setUser($viewer) ->setErrors(array(pht('You are being rate limited.'))) - ->appendParagraph($ex->getMessage()) - ->appendParagraph($ex->getRateExplanation()) + ->appendParagraph($throwable->getMessage()) + ->appendParagraph($throwable->getRateExplanation()) ->addCancelButton('/', pht('Okaaaaaaaaaaaaaay...')); } } diff --git a/src/infrastructure/cluster/exception/PhabricatorClusterExceptionHandler.php b/src/infrastructure/cluster/exception/PhabricatorClusterExceptionHandler.php index 2abda20b8f..ed0e0cc605 100644 --- a/src/infrastructure/cluster/exception/PhabricatorClusterExceptionHandler.php +++ b/src/infrastructure/cluster/exception/PhabricatorClusterExceptionHandler.php @@ -1,39 +1,39 @@ getViewer($request); - $title = $ex->getExceptionTitle(); + $title = $throwable->getExceptionTitle(); $dialog = id(new AphrontDialogView()) ->setTitle($title) ->setUser($viewer) - ->appendParagraph($ex->getMessage()) + ->appendParagraph($throwable->getMessage()) ->addCancelButton('/', pht('Proceed With Caution')); return id(new AphrontDialogResponse()) ->setDialog($dialog) ->setHTTPResponseCode(500); } }