Page MenuHomePhabricator

D11126.diff
No OneTemporary

D11126.diff

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

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)

Event Timeline