Changeset View
Changeset View
Standalone View
Standalone View
src/applications/config/check/PhabricatorWebServerSetupCheck.php
Show All 10 Lines | protected function executeChecks() { | ||||
// are entirely reliable in practice. | // are entirely reliable in practice. | ||||
if (isset($_SERVER['HTTP_X_MOD_PAGESPEED']) || | if (isset($_SERVER['HTTP_X_MOD_PAGESPEED']) || | ||||
isset($_SERVER['HTTP_X_PAGE_SPEED'])) { | isset($_SERVER['HTTP_X_PAGE_SPEED'])) { | ||||
$this->newIssue('webserver.pagespeed') | $this->newIssue('webserver.pagespeed') | ||||
->setName(pht('Disable Pagespeed')) | ->setName(pht('Disable Pagespeed')) | ||||
->setSummary(pht('Pagespeed is enabled, but should be disabled.')) | ->setSummary(pht('Pagespeed is enabled, but should be disabled.')) | ||||
->setMessage( | ->setMessage( | ||||
pht( | pht( | ||||
'Phabricator received an "X-Mod-Pagespeed" or "X-Page-Speed" '. | '%s received an "X-Mod-Pagespeed" or "X-Page-Speed" '. | ||||
'HTTP header on this request, which indicates that you have '. | 'HTTP header on this request, which indicates that you have '. | ||||
'enabled "mod_pagespeed" on this server. This module is not '. | 'enabled "mod_pagespeed" on this server. This module is not '. | ||||
'compatible with Phabricator. You should disable it.')); | 'compatible with %s. You should disable it.', | ||||
PhabricatorPlatformSite::getName(), | |||||
PhabricatorPlatformSite::getName())); | |||||
} | } | ||||
$base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); | $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); | ||||
if (!strlen($base_uri)) { | if (!strlen($base_uri)) { | ||||
// If `phabricator.base-uri` is not set then we can't really do | // If `phabricator.base-uri` is not set then we can't really do | ||||
// anything. | // anything. | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | foreach ($futures as $future) { | ||||
// Just resolve the futures here. | // Just resolve the futures here. | ||||
} | } | ||||
try { | try { | ||||
list($body) = $ec2_future->resolvex(); | list($body) = $ec2_future->resolvex(); | ||||
$body = trim($body); | $body = trim($body); | ||||
if (preg_match('/^t2/', $body)) { | if (preg_match('/^t2/', $body)) { | ||||
$message = pht( | $message = pht( | ||||
'Phabricator appears to be installed on a very small EC2 instance '. | '%s appears to be installed on a very small EC2 instance '. | ||||
'(of class "%s") with burstable CPU. This is strongly discouraged. '. | '(of class "%s") with burstable CPU. This is strongly discouraged. '. | ||||
'Phabricator regularly needs CPU, and these instances are often '. | '%s regularly needs CPU, and these instances are often '. | ||||
'choked to death by CPU throttling. Use an instance with a normal '. | 'choked to death by CPU throttling. Use an instance with a normal '. | ||||
'CPU instead.', | 'CPU instead.', | ||||
$body); | PhabricatorPlatformSite::getName(), | ||||
$body, | |||||
PhabricatorPlatformSite::getName()); | |||||
$this->newIssue('ec2.burstable') | $this->newIssue('ec2.burstable') | ||||
->setName(pht('Installed on Burstable CPU Instance')) | ->setName(pht('Installed on Burstable CPU Instance')) | ||||
->setSummary( | ->setSummary( | ||||
pht( | pht( | ||||
'Do not install Phabricator on an instance class with '. | 'Do not install %s on an instance class with '. | ||||
'burstable CPU.')) | 'burstable CPU.', | ||||
PhabricatorPlatformSite::getName())) | |||||
->setMessage($message); | ->setMessage($message); | ||||
} | } | ||||
} catch (Exception $ex) { | } catch (Exception $ex) { | ||||
// If this fails, just continue. We're probably not running in EC2. | // If this fails, just continue. We're probably not running in EC2. | ||||
} | } | ||||
try { | try { | ||||
list($body, $headers) = $self_future->resolvex(); | list($body, $headers) = $self_future->resolvex(); | ||||
} catch (Exception $ex) { | } catch (Exception $ex) { | ||||
// If this fails for whatever reason, just ignore it. Hopefully, the | // If this fails for whatever reason, just ignore it. Hopefully, the | ||||
// error is obvious and the user can correct it on their own, but we | // error is obvious and the user can correct it on their own, but we | ||||
// can't do much to offer diagnostic advice. | // can't do much to offer diagnostic advice. | ||||
return; | return; | ||||
} | } | ||||
if (BaseHTTPFuture::getHeader($headers, 'Content-Encoding') != 'gzip') { | if (BaseHTTPFuture::getHeader($headers, 'Content-Encoding') != 'gzip') { | ||||
$message = pht( | $message = pht( | ||||
'Phabricator sent itself a request with "Accept-Encoding: gzip", '. | '%s sent itself a request with "Accept-Encoding: gzip", '. | ||||
'but received an uncompressed response.'. | 'but received an uncompressed response.'. | ||||
"\n\n". | "\n\n". | ||||
'This may indicate that your webserver is not configured to '. | 'This may indicate that your webserver is not configured to '. | ||||
'compress responses. If so, you should enable compression. '. | 'compress responses. If so, you should enable compression. '. | ||||
'Compression can dramatically improve performance, especially '. | 'Compression can dramatically improve performance, especially '. | ||||
'for clients with less bandwidth.'); | 'for clients with less bandwidth.', | ||||
PhabricatorPlatformSite::getName()); | |||||
$this->newIssue('webserver.gzip') | $this->newIssue('webserver.gzip') | ||||
->setName(pht('GZip Compression May Not Be Enabled')) | ->setName(pht('GZip Compression May Not Be Enabled')) | ||||
->setSummary(pht('Your webserver may have compression disabled.')) | ->setSummary(pht('Your webserver may have compression disabled.')) | ||||
->setMessage($message); | ->setMessage($message); | ||||
} else { | } else { | ||||
if (function_exists('gzdecode')) { | if (function_exists('gzdecode')) { | ||||
$body = @gzdecode($body); | $body = @gzdecode($body); | ||||
Show All 19 Lines | protected function executeChecks() { | ||||
if (!$structure || $extra_whitespace) { | if (!$structure || $extra_whitespace) { | ||||
if (!$structure) { | if (!$structure) { | ||||
$short = id(new PhutilUTF8StringTruncator()) | $short = id(new PhutilUTF8StringTruncator()) | ||||
->setMaximumGlyphs(1024) | ->setMaximumGlyphs(1024) | ||||
->truncateString($body); | ->truncateString($body); | ||||
$message = pht( | $message = pht( | ||||
'Phabricator sent itself a test request with the '. | '%s sent itself a test request with the '. | ||||
'"X-Phabricator-SelfCheck" header and expected to get a valid JSON '. | '"X-Phabricator-SelfCheck" header and expected to get a valid JSON '. | ||||
'response back. Instead, the response begins:'. | 'response back. Instead, the response begins:'. | ||||
"\n\n". | "\n\n". | ||||
'%s'. | '%s'. | ||||
"\n\n". | "\n\n". | ||||
'Something is misconfigured or otherwise mangling responses.', | 'Something is misconfigured or otherwise mangling responses.', | ||||
PhabricatorPlatformSite::getName(), | |||||
phutil_tag('pre', array(), $short)); | phutil_tag('pre', array(), $short)); | ||||
} else { | } else { | ||||
$message = pht( | $message = pht( | ||||
'Phabricator sent itself a test request and expected to get a bare '. | '%s sent itself a test request and expected to get a bare '. | ||||
'JSON response back. It received a JSON response, but the response '. | 'JSON response back. It received a JSON response, but the response '. | ||||
'had extra whitespace at the beginning or end.'. | 'had extra whitespace at the beginning or end.'. | ||||
"\n\n". | "\n\n". | ||||
'This usually means you have edited a file and left whitespace '. | 'This usually means you have edited a file and left whitespace '. | ||||
'characters before the opening %s tag, or after a closing %s tag. '. | 'characters before the opening %s tag, or after a closing %s tag. '. | ||||
'Remove any leading whitespace, and prefer to omit closing tags.', | 'Remove any leading whitespace, and prefer to omit closing tags.', | ||||
PhabricatorPlatformSite::getName(), | |||||
phutil_tag('tt', array(), '<?php'), | phutil_tag('tt', array(), '<?php'), | ||||
phutil_tag('tt', array(), '?>')); | phutil_tag('tt', array(), '?>')); | ||||
} | } | ||||
$this->newIssue('webserver.mangle') | $this->newIssue('webserver.mangle') | ||||
->setName(pht('Mangled Webserver Response')) | ->setName(pht('Mangled Webserver Response')) | ||||
->setSummary(pht('Your webserver produced an unexpected response.')) | ->setSummary(pht('Your webserver produced an unexpected response.')) | ||||
->setMessage($message); | ->setMessage($message); | ||||
// We can't run the other checks if we could not decode the response. | // We can't run the other checks if we could not decode the response. | ||||
if (!$structure) { | if (!$structure) { | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
$actual_user = idx($structure, 'user'); | $actual_user = idx($structure, 'user'); | ||||
$actual_pass = idx($structure, 'pass'); | $actual_pass = idx($structure, 'pass'); | ||||
if (($expect_user != $actual_user) || ($actual_pass != $expect_pass)) { | if (($expect_user != $actual_user) || ($actual_pass != $expect_pass)) { | ||||
$message = pht( | $message = pht( | ||||
'Phabricator sent itself a test request with an "Authorization" HTTP '. | '%s sent itself a test request with an "Authorization" HTTP '. | ||||
'header, and expected those credentials to be transmitted. However, '. | 'header, and expected those credentials to be transmitted. However, '. | ||||
'they were absent or incorrect when received. Phabricator sent '. | 'they were absent or incorrect when received. %s sent '. | ||||
'username "%s" with password "%s"; received username "%s" and '. | 'username "%s" with password "%s"; received username "%s" and '. | ||||
'password "%s".'. | 'password "%s".'. | ||||
"\n\n". | "\n\n". | ||||
'Your webserver may not be configured to forward HTTP basic '. | 'Your webserver may not be configured to forward HTTP basic '. | ||||
'authentication. If you plan to use basic authentication (for '. | 'authentication. If you plan to use basic authentication (for '. | ||||
'example, to access repositories) you should reconfigure it.', | 'example, to access repositories) you should reconfigure it.', | ||||
PhabricatorPlatformSite::getName(), | |||||
PhabricatorPlatformSite::getName(), | |||||
$expect_user, | $expect_user, | ||||
$expect_pass, | $expect_pass, | ||||
$actual_user, | $actual_user, | ||||
$actual_pass); | $actual_pass); | ||||
$this->newIssue('webserver.basic-auth') | $this->newIssue('webserver.basic-auth') | ||||
->setName(pht('HTTP Basic Auth Not Configured')) | ->setName(pht('HTTP Basic Auth Not Configured')) | ||||
->setSummary(pht('Your webserver is not forwarding credentials.')) | ->setSummary(pht('Your webserver is not forwarding credentials.')) | ||||
->setMessage($message); | ->setMessage($message); | ||||
} | } | ||||
$actual_path = idx($structure, 'path'); | $actual_path = idx($structure, 'path'); | ||||
if ($expect_path != $actual_path) { | if ($expect_path != $actual_path) { | ||||
$message = pht( | $message = pht( | ||||
'Phabricator sent itself a test request with an unusual path, to '. | '%s sent itself a test request with an unusual path, to '. | ||||
'test if your webserver is rewriting paths correctly. The path was '. | 'test if your webserver is rewriting paths correctly. The path was '. | ||||
'not transmitted correctly.'. | 'not transmitted correctly.'. | ||||
"\n\n". | "\n\n". | ||||
'Phabricator sent a request to path "%s", and expected the webserver '. | '%s sent a request to path "%s", and expected the webserver '. | ||||
'to decode and rewrite that path so that it received a request for '. | 'to decode and rewrite that path so that it received a request for '. | ||||
'"%s". However, it received a request for "%s" instead.'. | '"%s". However, it received a request for "%s" instead.'. | ||||
"\n\n". | "\n\n". | ||||
'Verify that your rewrite rules are configured correctly, following '. | 'Verify that your rewrite rules are configured correctly, following '. | ||||
'the instructions in the documentation. If path encoding is not '. | 'the instructions in the documentation. If path encoding is not '. | ||||
'working properly you will be unable to access files with unusual '. | 'working properly you will be unable to access files with unusual '. | ||||
'names in repositories, among other issues.'. | 'names in repositories, among other issues.'. | ||||
"\n\n". | "\n\n". | ||||
'(This problem can be caused by a missing "B" in your RewriteRule.)', | '(This problem can be caused by a missing "B" in your RewriteRule.)', | ||||
PhabricatorPlatformSite::getName(), | |||||
PhabricatorPlatformSite::getName(), | |||||
$send_path, | $send_path, | ||||
$expect_path, | $expect_path, | ||||
$actual_path); | $actual_path); | ||||
$this->newIssue('webserver.rewrites') | $this->newIssue('webserver.rewrites') | ||||
->setName(pht('HTTP Path Rewriting Incorrect')) | ->setName(pht('HTTP Path Rewriting Incorrect')) | ||||
->setSummary(pht('Your webserver is rewriting paths improperly.')) | ->setSummary(pht('Your webserver is rewriting paths improperly.')) | ||||
->setMessage($message); | ->setMessage($message); | ||||
} | } | ||||
$actual_key = pht('<none>'); | $actual_key = pht('<none>'); | ||||
$actual_value = pht('<none>'); | $actual_value = pht('<none>'); | ||||
foreach (idx($structure, 'params', array()) as $pair) { | foreach (idx($structure, 'params', array()) as $pair) { | ||||
if (idx($pair, 'name') == $expect_key) { | if (idx($pair, 'name') == $expect_key) { | ||||
$actual_key = idx($pair, 'name'); | $actual_key = idx($pair, 'name'); | ||||
$actual_value = idx($pair, 'value'); | $actual_value = idx($pair, 'value'); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (($expect_key !== $actual_key) || ($expect_value !== $actual_value)) { | if (($expect_key !== $actual_key) || ($expect_value !== $actual_value)) { | ||||
$message = pht( | $message = pht( | ||||
'Phabricator sent itself a test request with an HTTP GET parameter, '. | '%s sent itself a test request with an HTTP GET parameter, '. | ||||
'but the parameter was not transmitted. Sent "%s" with value "%s", '. | 'but the parameter was not transmitted. Sent "%s" with value "%s", '. | ||||
'got "%s" with value "%s".'. | 'got "%s" with value "%s".'. | ||||
"\n\n". | "\n\n". | ||||
'Your webserver is configured incorrectly and large parts of '. | 'Your webserver is configured incorrectly and large parts of '. | ||||
'Phabricator will not work until this issue is corrected.'. | '%s will not work until this issue is corrected.'. | ||||
"\n\n". | "\n\n". | ||||
'(This problem can be caused by a missing "QSA" in your RewriteRule.)', | '(This problem can be caused by a missing "QSA" in your RewriteRule.)', | ||||
PhabricatorPlatformSite::getName(), | |||||
$expect_key, | $expect_key, | ||||
$expect_value, | $expect_value, | ||||
$actual_key, | $actual_key, | ||||
$actual_value); | $actual_value, | ||||
PhabricatorPlatformSite::getName()); | |||||
$this->newIssue('webserver.parameters') | $this->newIssue('webserver.parameters') | ||||
->setName(pht('HTTP Parameters Not Transmitting')) | ->setName(pht('HTTP Parameters Not Transmitting')) | ||||
->setSummary( | ->setSummary( | ||||
pht('Your webserver is not handling GET parameters properly.')) | pht('Your webserver is not handling GET parameters properly.')) | ||||
->setMessage($message); | ->setMessage($message); | ||||
} | } | ||||
Show All 34 Lines | private function checkGzipResponse( | ||||
// If the server received a prefix of the raw uncompressed string, it | // If the server received a prefix of the raw uncompressed string, it | ||||
// is almost certainly configured to decompress responses inline. Guide | // is almost certainly configured to decompress responses inline. Guide | ||||
// users to this problem narrowly. | // users to this problem narrowly. | ||||
// Otherwise, something is wrong but we don't have much of a clue what. | // Otherwise, something is wrong but we don't have much of a clue what. | ||||
$message = array(); | $message = array(); | ||||
$message[] = pht( | $message[] = pht( | ||||
'Phabricator sent itself a test request that was compressed with '. | '%s sent itself a test request that was compressed with '. | ||||
'"Content-Encoding: gzip", but received different bytes than it '. | '"Content-Encoding: gzip", but received different bytes than it '. | ||||
'sent.'); | 'sent.', | ||||
PhabricatorPlatformSite::getName()); | |||||
$prefix_len = min(strlen($raw_body), strlen($uncompressed)); | $prefix_len = min(strlen($raw_body), strlen($uncompressed)); | ||||
if ($prefix_len > 16 && !strncmp($raw_body, $uncompressed, $prefix_len)) { | if ($prefix_len > 16 && !strncmp($raw_body, $uncompressed, $prefix_len)) { | ||||
$message[] = pht( | $message[] = pht( | ||||
'The request body that the server received had already been '. | 'The request body that the server received had already been '. | ||||
'decompressed. This strongly suggests your webserver is configured '. | 'decompressed. This strongly suggests your webserver is configured '. | ||||
'to decompress requests inline, before they reach PHP.'); | 'to decompress requests inline, before they reach PHP.'); | ||||
$message[] = pht( | $message[] = pht( | ||||
'If you are using Apache, your server may be configured with '. | 'If you are using Apache, your server may be configured with '. | ||||
'"SetInputFilter DEFLATE". This directive destructively mangles '. | '"SetInputFilter DEFLATE". This directive destructively mangles '. | ||||
'requests and emits them with "Content-Length" and '. | 'requests and emits them with "Content-Length" and '. | ||||
'"Content-Encoding" headers that no longer match the data in the '. | '"Content-Encoding" headers that no longer match the data in the '. | ||||
'request body.'); | 'request body.'); | ||||
} else { | } else { | ||||
$message[] = pht( | $message[] = pht( | ||||
'This suggests your webserver is configured to decompress or mangle '. | 'This suggests your webserver is configured to decompress or mangle '. | ||||
'compressed requests.'); | 'compressed requests.'); | ||||
$message[] = pht( | $message[] = pht( | ||||
'The request body Phabricator sent began:'); | 'The request body %s sent began:', | ||||
PhabricatorPlatformSite::getName()); | |||||
$message[] = $this->snipBytes($compressed); | $message[] = $this->snipBytes($compressed); | ||||
$message[] = pht( | $message[] = pht( | ||||
'The request body Phabricator received began:'); | 'The request body %s received began:', | ||||
PhabricatorPlatformSite::getName()); | |||||
$message[] = $this->snipBytes($raw_body); | $message[] = $this->snipBytes($raw_body); | ||||
} | } | ||||
$message[] = pht( | $message[] = pht( | ||||
'Identify the component in your webserver configuration which is '. | 'Identify the component in your webserver configuration which is '. | ||||
'decompressing or mangling requests and disable it. Phabricator '. | 'decompressing or mangling requests and disable it. %s '. | ||||
'will not work properly until you do.'); | 'will not work properly until you do.', | ||||
PhabricatorPlatformSite::getName()); | |||||
$message = phutil_implode_html("\n\n", $message); | $message = phutil_implode_html("\n\n", $message); | ||||
$this->newIssue('webserver.accept-gzip') | $this->newIssue('webserver.accept-gzip') | ||||
->setName(pht('Compressed Requests Not Received Properly')) | ->setName(pht('Compressed Requests Not Received Properly')) | ||||
->setSummary( | ->setSummary( | ||||
pht( | pht( | ||||
'Your webserver is not handling compressed request bodies '. | 'Your webserver is not handling compressed request bodies '. | ||||
Show All 20 Lines |
Content licensed under Creative Commons Attribution-ShareAlike 4.0 (CC-BY-SA) unless otherwise noted; code licensed under Apache 2.0 or other open source licenses. · CC BY-SA 4.0 · Apache 2.0