Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2893466
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
24 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/aphront/console/plugin/DarkConsoleXHProfPlugin.php b/src/aphront/console/plugin/DarkConsoleXHProfPlugin.php
index 4574056deb..0cae8541d2 100644
--- a/src/aphront/console/plugin/DarkConsoleXHProfPlugin.php
+++ b/src/aphront/console/plugin/DarkConsoleXHProfPlugin.php
@@ -1,106 +1,105 @@
<?php
/**
* @group console
*/
final class DarkConsoleXHProfPlugin extends DarkConsolePlugin {
protected $xhprofID;
public function getName() {
return 'XHProf';
}
public function getColor() {
$data = $this->getData();
if ($data['xhprofID']) {
return '#ff00ff';
}
return null;
}
public function getDescription() {
return 'Provides detailed PHP profiling information through XHProf.';
}
public function generateData() {
return array(
'xhprofID' => $this->xhprofID,
'profileURI' => (string)$this
->getRequestURI()
->alter('__profile__', 'page'),
);
}
public function getXHProfRunID() {
return $this->xhprofID;
}
public function renderPanel() {
$data = $this->getData();
$run = $data['xhprofID'];
$profile_uri = $data['profileURI'];
if (!DarkConsoleXHProfPluginAPI::isProfilerAvailable()) {
$href = PhabricatorEnv::getDoclink('article/Installation_Guide.html');
$install_guide = phutil_tag(
'a',
array(
'href' => $href,
'class' => 'bright-link',
),
'Installation Guide');
return
'<div class="dark-console-no-content">'.
'The "xhprof" PHP extension is not available. Install xhprof '.
'to enable the XHProf console plugin. You can find instructions in '.
'the '.$install_guide.'.'.
'</div>';
}
$result = array();
$header =
'<div class="dark-console-panel-header">'.
phutil_tag(
'a',
array(
'href' => $profile_uri,
'class' => $run
? 'disabled button'
: 'green button',
),
'Profile Page').
'<h1>XHProf Profiler</h1>'.
'</div>';
$result[] = $header;
if ($run) {
$result[] =
'<a href="/xhprof/profile/'.$run.'/" '.
'class="bright-link" '.
'style="float: right; margin: 1em 2em 0 0;'.
'font-weight: bold;" '.
'target="_blank">Profile Permalink</a>'.
'<iframe src="/xhprof/profile/'.$run.'/?frame=true"></iframe>';
} else {
$result[] =
'<div class="dark-console-no-content">'.
'Profiling was not enabled for this page. Use the button above '.
'to enable it.'.
'</div>';
}
return implode("\n", $result);
}
public function willShutdown() {
- if (DarkConsoleXHProfPluginAPI::isProfilerRequested() &&
- (DarkConsoleXHProfPluginAPI::isProfilerRequested() !== 'all')) {
+ if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) {
$this->xhprofID = DarkConsoleXHProfPluginAPI::stopProfiler();
}
}
}
diff --git a/src/aphront/console/plugin/xhprof/DarkConsoleXHProfPluginAPI.php b/src/aphront/console/plugin/xhprof/DarkConsoleXHProfPluginAPI.php
index e2f9cad21d..afad7f1b8e 100644
--- a/src/aphront/console/plugin/xhprof/DarkConsoleXHProfPluginAPI.php
+++ b/src/aphront/console/plugin/xhprof/DarkConsoleXHProfPluginAPI.php
@@ -1,127 +1,171 @@
<?php
/**
* @group console
* @phutil-external-symbol function xhprof_enable
* @phutil-external-symbol function xhprof_disable
*/
final class DarkConsoleXHProfPluginAPI {
private static $profilerStarted;
public static function isProfilerAvailable() {
return extension_loaded('xhprof');
}
public static function getProfilerHeader() {
return 'X-Phabricator-Profiler';
}
public static function isProfilerRequested() {
if (!empty($_REQUEST['__profile__'])) {
return $_REQUEST['__profile__'];
}
$header = AphrontRequest::getHTTPHeader(self::getProfilerHeader());
if ($header) {
return $header;
}
- static $profilerRequested = null;
+ return false;
+ }
+
+ public static function shouldStartProfiler() {
+ if (self::isProfilerRequested()) {
+ return true;
+ }
- if (!isset($profilerRequested)) {
+ static $sample_request = null;
+
+ if ($sample_request === null) {
if (PhabricatorEnv::getEnvConfig('debug.profile-rate')) {
$rate = PhabricatorEnv::getEnvConfig('debug.profile-rate');
if (mt_rand(1, $rate) == 1) {
- $profilerRequested = true;
+ $sample_request = true;
} else {
- $profilerRequested = false;
+ $sample_request = false;
}
}
}
- return $profilerRequested;
+ return $sample_request;
+ }
+
+ public static function isProfilerStarted() {
+ return self::$profilerStarted;
}
public static function includeXHProfLib() {
// TODO: this is incredibly stupid, but we may not have Phutil metamodule
// stuff loaded yet so we can't just phutil_get_library_root() our way
// to victory.
$root = __FILE__;
for ($ii = 0; $ii < 6; $ii++) {
$root = dirname($root);
}
require_once $root.'/externals/xhprof/xhprof_lib.php';
}
+ public static function saveProfilerSample(
+ AphrontRequest $request,
+ $access_log) {
+
+ if (!self::isProfilerStarted()) {
+ return;
+ }
+
+ $profile = DarkConsoleXHProfPluginAPI::stopProfiler();
+ $profile_sample = id(new PhabricatorXHProfSample())
+ ->setFilePHID($profile);
+
+ if (self::isProfilerRequested()) {
+ $sample_rate = 0;
+ } else {
+ $sample_rate = PhabricatorEnv::getEnvConfig('debug.profile-rate');
+ }
+
+ $profile_sample->setSampleRate($sample_rate);
+
+ if ($access_log) {
+ $profile_sample
+ ->setUsTotal($access_log->getData('T'))
+ ->setHostname($access_log->getData('h'))
+ ->setRequestPath($access_log->getData('U'))
+ ->setController($access_log->getData('C'))
+ ->setUserPHID($request->getUser()->getPHID());
+ }
+
+ $profile_sample->save();
+ }
+
public static function hookProfiler() {
- if (!self::isProfilerRequested()) {
+ if (!self::shouldStartProfiler()) {
return;
}
if (!self::isProfilerAvailable()) {
return;
}
if (self::$profilerStarted) {
return;
}
self::startProfiler();
self::$profilerStarted = true;
}
public static function startProfiler() {
self::includeXHProfLib();
xhprof_enable();
}
public static function stopProfiler() {
- if (self::$profilerStarted) {
- $data = xhprof_disable();
- $data = serialize($data);
- $file_class = 'PhabricatorFile';
-
- // Since these happen on GET we can't do guarded writes. These also
- // sometimes happen after we've disposed of the write guard; in this
- // case we need to disable the whole mechanism.
-
- $use_scope = AphrontWriteGuard::isGuardActive();
- if ($use_scope) {
- $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
- } else {
- AphrontWriteGuard::allowDangerousUnguardedWrites(true);
- }
+ if (!self::isProfilerStarted()) {
+ return null;
+ }
- $caught = null;
- try {
- $file = call_user_func(
- array($file_class, 'newFromFileData'),
- $data,
- array(
- 'mime-type' => 'application/xhprof',
- 'name' => 'profile.xhprof',
- ));
- } catch (Exception $ex) {
- $caught = $ex;
- }
+ $data = xhprof_disable();
+ $data = serialize($data);
+ $file_class = 'PhabricatorFile';
- if ($use_scope) {
- unset($unguarded);
- } else {
- AphrontWriteGuard::allowDangerousUnguardedWrites(false);
- }
+ // Since these happen on GET we can't do guarded writes. These also
+ // sometimes happen after we've disposed of the write guard; in this
+ // case we need to disable the whole mechanism.
- if ($caught) {
- throw $caught;
- } else {
- return $file->getPHID();
- }
+ $use_scope = AphrontWriteGuard::isGuardActive();
+ if ($use_scope) {
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
} else {
- return null;
+ AphrontWriteGuard::allowDangerousUnguardedWrites(true);
+ }
+
+ $caught = null;
+ try {
+ $file = call_user_func(
+ array($file_class, 'newFromFileData'),
+ $data,
+ array(
+ 'mime-type' => 'application/xhprof',
+ 'name' => 'profile.xhprof',
+ ));
+ } catch (Exception $ex) {
+ $caught = $ex;
+ }
+
+ if ($use_scope) {
+ unset($unguarded);
+ } else {
+ AphrontWriteGuard::allowDangerousUnguardedWrites(false);
+ }
+
+ if ($caught) {
+ throw $caught;
+ } else {
+ return $file->getPHID();
}
}
}
diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php
index ea9cc314da..80c7a37f5d 100644
--- a/src/view/page/PhabricatorStandardPageView.php
+++ b/src/view/page/PhabricatorStandardPageView.php
@@ -1,393 +1,393 @@
<?php
/**
* This is a standard Phabricator page with menus, Javelin, DarkConsole, and
* basic styles.
*
*/
final class PhabricatorStandardPageView extends PhabricatorBarePageView {
private $baseURI;
private $applicationName;
private $glyph;
private $menuContent;
private $showChrome = true;
private $disableConsole;
private $searchDefaultScope;
private $pageObjects = array();
private $applicationMenu;
public function setApplicationMenu(PhabricatorMenuView $application_menu) {
$this->applicationMenu = $application_menu;
return $this;
}
public function getApplicationMenu() {
return $this->applicationMenu;
}
public function setApplicationName($application_name) {
$this->applicationName = $application_name;
return $this;
}
public function setDisableConsole($disable) {
$this->disableConsole = $disable;
return $this;
}
public function getApplicationName() {
return $this->applicationName;
}
public function setBaseURI($base_uri) {
$this->baseURI = $base_uri;
return $this;
}
public function getBaseURI() {
return $this->baseURI;
}
public function setShowChrome($show_chrome) {
$this->showChrome = $show_chrome;
return $this;
}
public function getShowChrome() {
return $this->showChrome;
}
public function setSearchDefaultScope($search_default_scope) {
$this->searchDefaultScope = $search_default_scope;
return $this;
}
public function getSearchDefaultScope() {
return $this->searchDefaultScope;
}
public function appendPageObjects(array $objs) {
foreach ($objs as $obj) {
$this->pageObjects[] = $obj;
}
}
public function getTitle() {
$use_glyph = true;
$request = $this->getRequest();
if ($request) {
$user = $request->getUser();
if ($user && $user->loadPreferences()->getPreference(
PhabricatorUserPreferences::PREFERENCE_TITLES) !== 'glyph') {
$use_glyph = false;
}
}
return ($use_glyph ?
$this->getGlyph() : '['.$this->getApplicationName().']').
' '.parent::getTitle();
}
protected function willRenderPage() {
parent::willRenderPage();
if (!$this->getRequest()) {
throw new Exception(
"You must set the Request to render a PhabricatorStandardPageView.");
}
$console = $this->getConsole();
require_celerity_resource('phabricator-core-css');
require_celerity_resource('phabricator-zindex-css');
require_celerity_resource('phabricator-core-buttons-css');
require_celerity_resource('sprite-gradient-css');
require_celerity_resource('phabricator-standard-page-view');
Javelin::initBehavior('workflow', array());
$request = $this->getRequest();
$user = null;
if ($request) {
$user = $request->getUser();
}
if ($user) {
$default_img_uri =
PhabricatorEnv::getCDNURI(
'/rsrc/image/icon/fatcow/document_black.png'
);
$download_form = phabricator_form(
$user,
array(
'action' => '#',
'method' => 'POST',
'class' => 'lightbox-download-form',
'sigil' => 'download',
),
phutil_tag(
'button',
array(),
pht('Download')));
Javelin::initBehavior(
'lightbox-attachments',
array(
'defaultImageUri' => $default_img_uri,
'downloadForm' => $download_form,
));
}
Javelin::initBehavior('aphront-form-disable-on-submit');
Javelin::initBehavior('toggle-class', array());
Javelin::initBehavior('konami', array());
$current_token = null;
if ($user) {
$current_token = $user->getCSRFToken();
}
Javelin::initBehavior(
'refresh-csrf',
array(
'tokenName' => AphrontRequest::getCSRFTokenName(),
'header' => AphrontRequest::getCSRFHeaderName(),
'current' => $current_token,
));
Javelin::initBehavior('device');
if ($console) {
require_celerity_resource('aphront-dark-console-css');
$headers = array();
- if (DarkConsoleXHProfPluginAPI::isProfilerRequested()) {
+ if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) {
$headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page';
}
Javelin::initBehavior(
'dark-console',
array(
'uri' => $request ? (string)$request->getRequestURI() : '?',
'selected' => $user ? $user->getConsoleTab() : null,
'visible' => $user ? (int)$user->getConsoleVisible() : true,
'headers' => $headers,
));
// Change this to initBehavior when there is some behavior to initialize
require_celerity_resource('javelin-behavior-error-log');
}
$menu = id(new PhabricatorMainMenuView())
->setUser($request->getUser())
->setDefaultSearchScope($this->getSearchDefaultScope());
if ($this->getController()) {
$menu->setController($this->getController());
}
if ($this->getApplicationMenu()) {
$menu->setApplicationMenu($this->getApplicationMenu());
}
$this->menuContent = $menu->render();
}
protected function getHead() {
$monospaced = PhabricatorEnv::getEnvConfig('style.monospace');
$request = $this->getRequest();
if ($request) {
$user = $request->getUser();
if ($user) {
$monospaced = nonempty(
$user->loadPreferences()->getPreference(
PhabricatorUserPreferences::PREFERENCE_MONOSPACED),
$monospaced);
}
}
$response = CelerityAPI::getStaticResourceResponse();
$head = array(
parent::getHead(),
'<style type="text/css">'.
'.PhabricatorMonospaced { font: '.$monospaced.'; }'.
'</style>',
$response->renderSingleResource('javelin-magical-init'),
);
return implode("\n", $head);
}
public function setGlyph($glyph) {
$this->glyph = $glyph;
return $this;
}
public function getGlyph() {
return $this->glyph;
}
protected function willSendResponse($response) {
$request = $this->getRequest();
$response = parent::willSendResponse($response);
$console = $request->getApplicationConfiguration()->getConsole();
if ($console) {
$response = str_replace(
'<darkconsole />',
$console->render($request),
$response);
}
return $response;
}
protected function getBody() {
$console = $this->getConsole();
$user = null;
$request = $this->getRequest();
if ($request) {
$user = $request->getUser();
}
$header_chrome = null;
if ($this->getShowChrome()) {
$header_chrome = $this->menuContent;
}
$developer_warning = null;
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode') &&
DarkConsoleErrorLogPluginAPI::getErrors()) {
$developer_warning = phutil_tag(
'div',
array(
'class' => 'aphront-developer-error-callout',
),
pht(
'This page raised PHP errors. Find them in DarkConsole '.
'or the error log.'));
}
// Render the "you have unresolved setup issues..." warning.
$setup_warning = null;
if ($user && $user->getIsAdmin()) {
$open = PhabricatorSetupCheck::getOpenSetupIssueCount();
if ($open) {
$setup_warning = phutil_tag(
'div',
array(
'class' => 'setup-warning-callout',
),
phutil_tag(
'a',
array(
'href' => '/config/issue/',
),
pht('You have %d unresolved setup issue(s)...', $open)));
}
}
return
phutil_render_tag(
'div',
array(
'id' => 'base-page',
'class' => 'phabricator-standard-page',
),
$developer_warning.
$setup_warning.
$header_chrome.
'<div class="phabricator-standard-page-body">'.
($console ? '<darkconsole />' : null).
parent::getBody().
'<div style="clear: both;"></div>'.
'</div>');
}
protected function getTail() {
$request = $this->getRequest();
$user = $request->getUser();
$container = null;
if ($user->isLoggedIn()) {
$aphlict_object_id = celerity_generate_unique_node_id();
$aphlict_container_id = celerity_generate_unique_node_id();
$client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
$client_uri = new PhutilURI($client_uri);
if ($client_uri->getDomain() == 'localhost') {
$this_host = $this->getRequest()->getHost();
$this_host = new PhutilURI('http://'.$this_host.'/');
$client_uri->setDomain($this_host->getDomain());
}
$enable_debug = PhabricatorEnv::getEnvConfig('notification.debug');
Javelin::initBehavior(
'aphlict-listen',
array(
'id' => $aphlict_object_id,
'containerID' => $aphlict_container_id,
'server' => $client_uri->getDomain(),
'port' => $client_uri->getPort(),
'debug' => $enable_debug,
'pageObjects' => array_fill_keys($this->pageObjects, true),
));
$container = phutil_tag(
'div',
array(
'id' => $aphlict_container_id,
'style' => 'position: absolute; width: 0; height: 0;',
),
'');
}
$response = CelerityAPI::getStaticResourceResponse();
$tail = array(
parent::getTail(),
$container,
$response->renderHTMLFooter(),
);
return implode("\n", $tail);
}
protected function getBodyClasses() {
$classes = array();
if (!$this->getShowChrome()) {
$classes[] = 'phabricator-chromeless-page';
}
$agent = AphrontRequest::getHTTPHeader('User-Agent');
// Try to guess the device resolution based on UA strings to avoid a flash
// of incorrectly-styled content.
$device_guess = 'device-desktop';
if (preg_match('@iPhone|iPod|(Android.*Chrome/[.0-9]* Mobile)@', $agent)) {
$device_guess = 'device-phone device';
} else if (preg_match('@iPad|(Android.*Chrome/)@', $agent)) {
$device_guess = 'device-tablet device';
}
$classes[] = $device_guess;
return implode(' ', $classes);
}
private function getConsole() {
if ($this->disableConsole) {
return null;
}
return $this->getRequest()->getApplicationConfiguration()->getConsole();
}
}
diff --git a/webroot/index.php b/webroot/index.php
index 38e776f241..c6af0494f7 100644
--- a/webroot/index.php
+++ b/webroot/index.php
@@ -1,158 +1,140 @@
<?php
require_once dirname(dirname(__FILE__)).'/support/PhabricatorStartup.php';
PhabricatorStartup::didStartup();
try {
PhabricatorStartup::loadCoreLibraries();
PhabricatorEnv::initializeWebEnvironment();
// This is the earliest we can get away with this, we need env config first.
PhabricatorAccessLog::init();
$access_log = PhabricatorAccessLog::getLog();
if ($access_log) {
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();
PhutilErrorHandler::setErrorListener(
array('DarkConsoleErrorLogPluginAPI', 'handleErrors'));
$sink = new AphrontPHPHTTPSink();
$response = PhabricatorSetupCheck::willProcessRequest();
if ($response) {
$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();
if ($access_log) {
$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 ($access_log) {
if ($request->getUser() && $request->getUser()->getPHID()) {
$access_log->setData(
array(
'u' => $request->getUser()->getUserName(),
));
}
}
if (!$response) {
$controller->willProcessRequest($uri_data);
$response = $controller->processRequest();
}
} catch (AphrontRedirectException $ex) {
$response = id(new AphrontRedirectResponse())
->setURI($ex->getURI());
} catch (Exception $ex) {
$original_exception = $ex;
$response = $application->handleException($ex);
}
try {
$response = $controller->didProcessRequest($response);
$response = $application->willSendResponse($response, $controller);
$response->setRequest($request);
$sink->writeResponse($response);
} catch (Exception $ex) {
$write_guard->dispose();
if ($access_log) {
$access_log->write();
}
if ($original_exception) {
$ex = new PhutilAggregateException(
"Multiple exceptions during processing and rendering.",
array(
$original_exception,
$ex,
));
}
PhabricatorStartup::didFatal('[Rendering Exception] '.$ex->getMessage());
}
$write_guard->dispose();
if ($access_log) {
$request_start = PhabricatorStartup::getStartTime();
$access_log->setData(
array(
'c' => $response->getHTTPResponseCode(),
'T' => (int)(1000000 * (microtime(true) - $request_start)),
));
$access_log->write();
}
- if (DarkConsoleXHProfPluginAPI::isProfilerRequested()) {
- $profile = DarkConsoleXHProfPluginAPI::stopProfiler();
- $profile_sample = id(new PhabricatorXHProfSample())
- ->setFilePHID($profile);
- if (empty($_REQUEST['__profile__'])) {
- $sample_rate = PhabricatorEnv::getEnvConfig('debug.profile-rate');
- } else {
- $sample_rate = 0;
- }
- $profile_sample->setSampleRate($sample_rate);
- if ($access_log) {
- $profile_sample->setUsTotal($access_log->getData('T'))
- ->setHostname($access_log->getData('h'))
- ->setRequestPath($access_log->getData('U'))
- ->setController($access_log->getData('C'))
- ->setUserPHID($request->getUser()->getPHID());
- }
- $profile_sample->save();
- }
+ DarkConsoleXHProfPluginAPI::saveProfilerSample($request, $access_log);
} catch (Exception $ex) {
PhabricatorStartup::didFatal("[Exception] ".$ex->getMessage());
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 18:28 (2 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1127424
Default Alt Text
(24 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment