Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14034361
D11126.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
23 KB
Referenced Files
None
Subscribers
None
D11126.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -45,6 +45,7 @@
'rsrc/css/application/config/config-template.css' => '25d446d6',
'rsrc/css/application/config/config-welcome.css' => 'b0d16200',
'rsrc/css/application/config/setup-issue.css' => '8f852bc0',
+ 'rsrc/css/application/config/unhandled-exception.css' => '38f08073',
'rsrc/css/application/conpherence/menu.css' => 'e1e0fdf1',
'rsrc/css/application/conpherence/message-pane.css' => '042886d1',
'rsrc/css/application/conpherence/notification.css' => '04a6e10a',
@@ -816,6 +817,7 @@
'sprite-tokens-css' => '1706b943',
'syntax-highlighting-css' => '56c1ba38',
'tokens-css' => '3d0f239e',
+ 'unhandled-exception-css' => '38f08073',
),
'requires' => array(
'00861799' => array(
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
@@ -161,12 +161,14 @@
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php',
+ 'AphrontStandaloneHTMLResponse' => 'aphront/response/AphrontStandaloneHTMLResponse.php',
'AphrontTableView' => 'view/control/AphrontTableView.php',
'AphrontTagView' => 'view/AphrontTagView.php',
'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php',
'AphrontTwoColumnView' => 'view/layout/AphrontTwoColumnView.php',
'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php',
'AphrontURIMapper' => 'aphront/AphrontURIMapper.php',
+ 'AphrontUnhandledExceptionResponse' => 'aphront/response/AphrontUnhandledExceptionResponse.php',
'AphrontUsageException' => 'aphront/exception/AphrontUsageException.php',
'AphrontView' => 'view/AphrontView.php',
'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php',
@@ -3217,11 +3219,13 @@
'AphrontRequestTestCase' => 'PhabricatorTestCase',
'AphrontSideNavFilterView' => 'AphrontView',
'AphrontStackTraceView' => 'AphrontView',
+ 'AphrontStandaloneHTMLResponse' => 'AphrontHTMLResponse',
'AphrontTableView' => 'AphrontView',
'AphrontTagView' => 'AphrontView',
'AphrontTokenizerTemplateView' => 'AphrontView',
'AphrontTwoColumnView' => 'AphrontView',
'AphrontTypeaheadTemplateView' => 'AphrontView',
+ 'AphrontUnhandledExceptionResponse' => 'AphrontStandaloneHTMLResponse',
'AphrontUsageException' => 'AphrontException',
'AphrontView' => array(
'Phobject',
@@ -4669,7 +4673,7 @@
'PhabricatorMarkupInterface',
),
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
- 'PhabricatorConfigResponse' => 'AphrontHTMLResponse',
+ 'PhabricatorConfigResponse' => 'AphrontStandaloneHTMLResponse',
'PhabricatorConfigSchemaQuery' => 'Phobject',
'PhabricatorConfigSchemaSpec' => 'Phobject',
'PhabricatorConfigServerSchema' => 'PhabricatorConfigStorageSchema',
diff --git a/src/__tests__/PhabricatorCelerityTestCase.php b/src/__tests__/PhabricatorCelerityTestCase.php
--- a/src/__tests__/PhabricatorCelerityTestCase.php
+++ b/src/__tests__/PhabricatorCelerityTestCase.php
@@ -15,18 +15,20 @@
$new_map = id(new CelerityResourceMapGenerator($resources))
->generate();
- $this->assertEqual(
- $new_map->getNameMap(),
- $old_map->getNameMap());
- $this->assertEqual(
- $new_map->getSymbolMap(),
- $old_map->getSymbolMap());
- $this->assertEqual(
- $new_map->getRequiresMap(),
- $old_map->getRequiresMap());
- $this->assertEqual(
- $new_map->getPackageMap(),
- $old_map->getPackageMap());
+ // Don't actually compare these values with assertEqual(), since the diff
+ // isn't helpful and is often enormously huge.
+
+ $maps_are_identical =
+ ($new_map->getNameMap() === $old_map->getNameMap()) &&
+ ($new_map->getSymbolMap() === $old_map->getSymbolMap()) &&
+ ($new_map->getRequiresMap() === $old_map->getRequiresMap()) &&
+ ($new_map->getPackageMap() === $old_map->getPackageMap());
+
+ $this->assertTrue(
+ $maps_are_identical,
+ pht(
+ 'When this test fails, it means the Celerity resource map is out '.
+ 'of date. Run `bin/celerity map` to rebuild it.'));
}
}
diff --git a/src/aphront/configuration/AphrontApplicationConfiguration.php b/src/aphront/configuration/AphrontApplicationConfiguration.php
--- a/src/aphront/configuration/AphrontApplicationConfiguration.php
+++ b/src/aphront/configuration/AphrontApplicationConfiguration.php
@@ -54,6 +54,192 @@
public function willBuildRequest() {}
+ /**
+ * @phutil-external-symbol class PhabricatorStartup
+ */
+ public static function runHTTPRequest(AphrontHTTPSink $sink) {
+ PhabricatorEnv::initializeWebEnvironment();
+
+ $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.
+ PhabricatorAccessLog::init();
+ $access_log = PhabricatorAccessLog::getLog();
+ PhabricatorStartup::setGlobal('log.access', $access_log);
+ $access_log->setData(
+ array(
+ 'R' => AphrontRequest::getHTTPHeader('Referer', '-'),
+ 'r' => idx($_SERVER, 'REMOTE_ADDR', '-'),
+ 'M' => idx($_SERVER, 'REQUEST_METHOD', '-'),
+ ));
+
+ DarkConsoleXHProfPluginAPI::hookProfiler();
+ DarkConsoleErrorLogPluginAPI::registerErrorHandler();
+
+ $response = PhabricatorSetupCheck::willProcessRequest();
+ if ($response) {
+ PhabricatorStartup::endOutputCapture();
+ $sink->writeResponse($response);
+ return;
+ }
+
+ $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();
+
+ // 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(),
+ ));
+
+ $write_guard = new AphrontWriteGuard(array($request, 'validateCSRF'));
+
+ $processing_exception = null;
+ try {
+ $response = $application->processRequest($request, $access_log, $sink);
+ $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(),
+ ));
+
+ $access_log->write();
+
+ DarkConsoleXHProfPluginAPI::saveProfilerSample($access_log);
+
+ // Add points to the rate limits for this request.
+ if (isset($_SERVER['REMOTE_ADDR'])) {
+ $user_ip = $_SERVER['REMOTE_ADDR'];
+
+ // 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($user_ip, $score);
+ }
+
+ if ($processing_exception) {
+ throw $processing_exception;
+ }
+ }
+
+
+ public function processRequest(
+ AphrontRequest $request,
+ PhutilDeferredLog $access_log,
+ AphrontHTTPSink $sink) {
+
+ $this->setRequest($request);
+
+ list($controller, $uri_data) = $this->buildController();
+
+ $access_log->setData(
+ array(
+ 'C' => get_class($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(),
+ ));
+ }
+
+ if (!$response) {
+ $controller->willProcessRequest($uri_data);
+ $response = $controller->handleRequest($request);
+ }
+ } catch (Exception $ex) {
+ $original_exception = $ex;
+ $response = $this->handleException($ex);
+ }
+
+ try {
+ $response = $controller->didProcessRequest($response);
+ $response = $this->willSendResponse($response, $controller);
+ $response->setRequest($request);
+
+ $unexpected_output = PhabricatorStartup::endOutputCapture();
+ if ($unexpected_output) {
+ $unexpected_output = pht(
+ "Unexpected output:\n\n%s",
+ $unexpected_output);
+
+ phlog($unexpected_output);
+
+ if ($response instanceof AphrontWebpageResponse) {
+ echo phutil_tag(
+ 'div',
+ array('style' =>
+ 'background: #eeddff;'.
+ 'white-space: pre-wrap;'.
+ 'z-index: 200000;'.
+ 'position: relative;'.
+ 'padding: 8px;'.
+ 'font-family: monospace',
+ ),
+ $unexpected_output);
+ }
+ }
+
+ $sink->writeResponse($response);
+ } catch (Exception $ex) {
+ if ($original_exception) {
+ throw $original_exception;
+ }
+ throw $ex;
+ }
+
+ return $response;
+ }
+
+
/* -( URI Routing )-------------------------------------------------------- */
diff --git a/src/aphront/response/AphrontStandaloneHTMLResponse.php b/src/aphront/response/AphrontStandaloneHTMLResponse.php
new file mode 100644
--- /dev/null
+++ b/src/aphront/response/AphrontStandaloneHTMLResponse.php
@@ -0,0 +1,63 @@
+<?php
+
+abstract class AphrontStandaloneHTMLResponse
+ extends AphrontHTMLResponse {
+
+ abstract protected function getResources();
+ abstract protected function getResponseTitle();
+ abstract protected function getResponseBodyClass();
+ abstract protected function getResponseBody();
+ abstract protected function buildPlainTextResponseString();
+
+ final public function buildResponseString() {
+ // Check to make sure we aren't requesting this via Ajax or Conduit.
+ if (isset($_REQUEST['__ajax__']) || isset($_REQUEST['__conduit__'])) {
+ return (string)hsprintf('%s', $this->buildPlainTextResponseString());
+ }
+
+ $title = $this->getResponseTitle();
+ $resources = $this->buildResources();
+ $body_class = $this->getResponseBodyClass();
+ $body = $this->getResponseBody();
+
+ return (string)hsprintf(
+<<<EOTEMPLATE
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <title>%s</title>
+ %s
+ </head>
+ %s
+</html>
+EOTEMPLATE
+ ,
+ $title,
+ $resources,
+ phutil_tag(
+ 'body',
+ array(
+ 'class' => $body_class,
+ ),
+ $body));
+ }
+
+ private function buildResources() {
+ $paths = $this->getResources();
+
+ $webroot = dirname(phutil_get_library_root('phabricator')).'/webroot/';
+
+ $resources = array();
+ foreach ($paths as $path) {
+ $resources[] = phutil_tag(
+ 'style',
+ array('type' => 'text/css'),
+ phutil_safe_html(Filesystem::readFile($webroot.'/rsrc/'.$path)));
+ }
+
+ return phutil_implode_html("\n", $resources);
+ }
+
+
+}
diff --git a/src/aphront/response/AphrontUnhandledExceptionResponse.php b/src/aphront/response/AphrontUnhandledExceptionResponse.php
new file mode 100644
--- /dev/null
+++ b/src/aphront/response/AphrontUnhandledExceptionResponse.php
@@ -0,0 +1,74 @@
+<?php
+
+final class AphrontUnhandledExceptionResponse
+ extends AphrontStandaloneHTMLResponse {
+
+ private $exception;
+
+ public function setException(Exception $exception) {
+ $this->exception = $exception;
+ return $this;
+ }
+
+ public function getHTTPResponseCode() {
+ return 500;
+ }
+
+ protected function getResources() {
+ return array(
+ 'css/application/config/config-template.css',
+ 'css/application/config/unhandled-exception.css',
+ );
+ }
+
+ protected function getResponseTitle() {
+ return pht('Unhandled Exception');
+ }
+
+ protected function getResponseBodyClass() {
+ return 'unhandled-exception';
+ }
+
+ protected function getResponseBody() {
+ $ex = $this->exception;
+
+ if ($ex instanceof AphrontUsageException) {
+ $title = $ex->getTitle();
+ } else {
+ $title = get_class($ex);
+ }
+
+ $body = $ex->getMessage();
+ $body = phutil_escape_html_newlines($body);
+
+ return phutil_tag(
+ 'div',
+ array(
+ 'class' => 'unhandled-exception-detail',
+ ),
+ array(
+ phutil_tag(
+ 'h1',
+ array(
+ 'class' => 'unhandled-exception-title',
+ ),
+ $title),
+ phutil_tag(
+ 'div',
+ array(
+ 'class' => 'unhandled-exception-body',
+ ),
+ $body),
+ ));
+ }
+
+ protected function buildPlainTextResponseString() {
+ $ex = $this->exception;
+
+ return pht(
+ '%s: %s',
+ get_class($ex),
+ $ex->getMessage());
+ }
+
+}
diff --git a/src/applications/config/response/PhabricatorConfigResponse.php b/src/applications/config/response/PhabricatorConfigResponse.php
--- a/src/applications/config/response/PhabricatorConfigResponse.php
+++ b/src/applications/config/response/PhabricatorConfigResponse.php
@@ -1,6 +1,6 @@
<?php
-final class PhabricatorConfigResponse extends AphrontHTMLResponse {
+final class PhabricatorConfigResponse extends AphrontStandaloneHTMLResponse {
private $view;
@@ -9,51 +9,33 @@
return $this;
}
- public function buildResponseString() {
- // Check to make sure we aren't requesting this via ajax or conduit
- if (isset($_REQUEST['__ajax__']) || isset($_REQUEST['__conduit__'])) {
- // We don't want to flood the console with html, just return a simple
- // message for now.
- return pht(
- 'This install has a fatal setup error, access the internet web '.
- 'version to view details and resolve it.');
- }
-
- $resources = $this->buildResources();
-
- $view = $this->view->render();
-
- return hsprintf(
- '<!DOCTYPE html>'.
- '<html>'.
- '<head>'.
- '<meta charset="UTF-8" />'.
- '<title>Phabricator Setup</title>'.
- '%s'.
- '</head>'.
- '<body class="setup-fatal">%s</body>'.
- '</html>',
- $resources,
- $view);
+ public function getHTTPResponseCode() {
+ return 500;
}
- private function buildResources() {
- $css = array(
- 'application/config/config-template.css',
- 'application/config/setup-issue.css',
+ protected function getResources() {
+ return array(
+ 'css/application/config/config-template.css',
+ 'css/application/config/setup-issue.css',
);
+ }
- $webroot = dirname(phutil_get_library_root('phabricator')).'/webroot/';
+ protected function getResponseTitle() {
+ return pht('Phabricator Setup Error');
+ }
- $resources = array();
- foreach ($css as $path) {
- $resources[] = phutil_tag(
- 'style',
- array('type' => 'text/css'),
- phutil_safe_html(Filesystem::readFile($webroot.'/rsrc/css/'.$path)));
- }
- return phutil_implode_html("\n", $resources);
+ protected function getResponseBodyClass() {
+ return 'setup-fatal';
}
+ protected function getResponseBody() {
+ return $this->view->render();
+ }
+
+ protected function buildPlainTextResponseString() {
+ return pht(
+ 'This install has a fatal setup error, access the internet web '.
+ 'version to view details and resolve it.');
+ }
}
diff --git a/support/PhabricatorStartup.php b/support/PhabricatorStartup.php
--- a/support/PhabricatorStartup.php
+++ b/support/PhabricatorStartup.php
@@ -122,6 +122,10 @@
self::setupPHP();
self::verifyPHP();
+ // If we've made it this far, the environment isn't completely broken so
+ // we can switch over to relying on our own exception recovery mechanisms.
+ ini_set('display_errors', 0);
+
if (isset($_SERVER['REMOTE_ADDR'])) {
self::rateLimitRequest($_SERVER['REMOTE_ADDR']);
}
diff --git a/webroot/index.php b/webroot/index.php
--- a/webroot/index.php
+++ b/webroot/index.php
@@ -11,174 +11,27 @@
PhabricatorStartup::didStartup();
-$show_unexpected_traces = false;
try {
PhabricatorStartup::loadCoreLibraries();
-
- PhabricatorEnv::initializeWebEnvironment();
-
- $debug_time_limit = PhabricatorEnv::getEnvConfig('debug.time-limit');
- if ($debug_time_limit) {
- PhabricatorStartup::setDebugTimeLimit($debug_time_limit);
- }
-
- $show_unexpected_traces = PhabricatorEnv::getEnvConfig(
- 'phabricator.developer-mode');
-
- // This is the earliest we can get away with this, we need env config first.
- PhabricatorAccessLog::init();
- $access_log = PhabricatorAccessLog::getLog();
- PhabricatorStartup::setGlobal('log.access', $access_log);
- $access_log->setData(
- array(
- 'R' => AphrontRequest::getHTTPHeader('Referer', '-'),
- 'r' => idx($_SERVER, 'REMOTE_ADDR', '-'),
- 'M' => idx($_SERVER, 'REQUEST_METHOD', '-'),
- ));
-
- DarkConsoleXHProfPluginAPI::hookProfiler();
- DarkConsoleErrorLogPluginAPI::registerErrorHandler();
-
$sink = new AphrontPHPHTTPSink();
- $response = PhabricatorSetupCheck::willProcessRequest();
- if ($response) {
- PhabricatorStartup::endOutputCapture();
- $sink->writeResponse($response);
- return;
- }
-
- $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();
-
- // Until an administrator sets "phabricator.base-uri", assume it is the same
- // as the request URI. This will work fine in most cases, it just breaks down
- // when daemons need to do things.
- $request_protocol = ($request->isHTTPS() ? 'https' : 'http');
- $request_base_uri = "{$request_protocol}://{$host}/";
- PhabricatorEnv::setRequestBaseURI($request_base_uri);
-
- $write_guard = new AphrontWriteGuard(array($request, 'validateCSRF'));
-
- $application->setRequest($request);
- list($controller, $uri_data) = $application->buildController();
- $request->setURIMap($uri_data);
- $controller->setRequest($request);
-
- $access_log->setData(
- array(
- 'U' => (string)$request->getRequestURI()->getPath(),
- 'C' => get_class($controller),
- ));
-
- // 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(),
- ));
- }
-
- if (!$response) {
- $controller->willProcessRequest($uri_data);
- $response = $controller->handleRequest($request);
- }
- } catch (Exception $ex) {
- $original_exception = $ex;
- $response = $application->handleException($ex);
- }
-
try {
- $response = $controller->didProcessRequest($response);
- $response = $application->willSendResponse($response, $controller);
- $response->setRequest($request);
-
- $unexpected_output = PhabricatorStartup::endOutputCapture();
- if ($unexpected_output) {
- $unexpected_output = "Unexpected output:\n\n{$unexpected_output}";
- phlog($unexpected_output);
-
- if ($response instanceof AphrontWebpageResponse) {
- echo phutil_tag(
- 'div',
- array('style' =>
- 'background: #eeddff;'.
- 'white-space: pre-wrap;'.
- 'z-index: 200000;'.
- 'position: relative;'.
- 'padding: 8px;'.
- 'font-family: monospace',
- ),
- $unexpected_output);
- }
- }
-
- $sink->writeResponse($response);
+ AphrontApplicationConfiguration::runHTTPRequest($sink);
} catch (Exception $ex) {
- $write_guard->dispose();
- $access_log->write();
- if ($original_exception) {
- $ex = new PhutilAggregateException(
- 'Multiple exceptions during processing and rendering.',
- array(
- $original_exception,
- $ex,
- ));
+ try {
+ $response = new AphrontUnhandledExceptionResponse();
+ $response->setException($ex);
+
+ PhabricatorStartup::endOutputCapture();
+ $sink->writeResponse($response);
+ } catch (Exception $response_exception) {
+ // If we hit a rendering exception, ignore it and throw the original
+ // exception. It is generally more interesting and more likely to be
+ // the root cause.
+ throw $ex;
}
- PhabricatorStartup::didEncounterFatalException(
- 'Rendering Exception',
- $ex,
- $show_unexpected_traces);
- }
-
- $write_guard->dispose();
-
- $access_log->setData(
- array(
- 'c' => $response->getHTTPResponseCode(),
- 'T' => PhabricatorStartup::getMicrosecondsSinceStart(),
- ));
-
- DarkConsoleXHProfPluginAPI::saveProfilerSample($access_log);
-
- // Add points to the rate limits for this request.
- if (isset($_SERVER['REMOTE_ADDR'])) {
- $user_ip = $_SERVER['REMOTE_ADDR'];
-
- // 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($user_ip, $score);
}
} catch (Exception $ex) {
- PhabricatorStartup::didEncounterFatalException(
- 'Core Exception',
- $ex,
- $show_unexpected_traces);
+ PhabricatorStartup::didEncounterFatalException('Core Exception', $ex, false);
}
diff --git a/webroot/rsrc/css/application/config/unhandled-exception.css b/webroot/rsrc/css/application/config/unhandled-exception.css
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/css/application/config/unhandled-exception.css
@@ -0,0 +1,27 @@
+/**
+ * @provides unhandled-exception-css
+ */
+
+.unhandled-exception {
+ background: #222228;
+}
+
+.unhandled-exception-detail {
+ max-width: 760px;
+ margin: 16px auto;
+ background: #f7f7f7;
+ border: 2px solid #ffffff;
+}
+
+.unhandled-exception-detail .unhandled-exception-title {
+ font-size: 15px;
+ font-weight: bold;
+ margin: 0;
+ padding: 16px;
+ background: #DFE0E2;
+}
+
+.unhandled-exception-detail .unhandled-exception-body {
+ padding: 16px;
+ color: #4B4D51;
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 10, 11:49 PM (2 d, 32 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6733735
Default Alt Text
D11126.diff (23 KB)
Attached To
Mode
D11126: Improve top-level exception handling
Attached
Detach File
Event Timeline
Log In to Comment