@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Read "$_POST" before hooking the profiler, and remove "aphront.default-application-configuration-class"

Summary:
Ref T4369. Ref T12297. Ref T13242. Ref PHI1010. I want to take a quick look at `transaction.search` and see if there's anything quick and obvious we can do to improve performance.

On `secure`, the `__profile__` flag does not survive POST like it's supposed to: when you profile a page and then submit a form on the page, the result is supposed to be profiled. The intent is to make it easier to profile Conduit calls.

I believe this is because we're hooking the profiler, then rebuilding POST data a little later -- so `$_POST['__profile__']` isn't set yet when the profiler checks.

Move the POST rebuild a little earlier to fix this.

Also, remove the very ancient "aphront.default-application-configuration-class". I believe this was only used by Facebook to do CIDR checks against corpnet or something like that. It is poorly named and long-obsolete now, and `AphrontSite` does everything we might reasonably have wanted it to do.

Test Plan: Poked around locally without any issues. Will check if this fixes the issue on `secure`.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13242, T12297, T4369

Differential Revision: https://secure.phabricator.com/D20046

+129 -154
-2
src/__phutil_library_map__.php
··· 183 183 'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php', 184 184 'AphrontController' => 'aphront/AphrontController.php', 185 185 'AphrontCursorPagerView' => 'view/control/AphrontCursorPagerView.php', 186 - 'AphrontDefaultApplicationConfiguration' => 'aphront/configuration/AphrontDefaultApplicationConfiguration.php', 187 186 'AphrontDialogResponse' => 'aphront/response/AphrontDialogResponse.php', 188 187 'AphrontDialogView' => 'view/AphrontDialogView.php', 189 188 'AphrontEpochHTTPParameterType' => 'aphront/httpparametertype/AphrontEpochHTTPParameterType.php', ··· 5631 5630 'AphrontCalendarEventView' => 'AphrontView', 5632 5631 'AphrontController' => 'Phobject', 5633 5632 'AphrontCursorPagerView' => 'AphrontView', 5634 - 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 5635 5633 'AphrontDialogResponse' => 'AphrontResponse', 5636 5634 'AphrontDialogView' => array( 5637 5635 'AphrontView',
+124 -22
src/aphront/configuration/AphrontApplicationConfiguration.php
··· 5 5 * @task response Response Handling 6 6 * @task exception Exception Handling 7 7 */ 8 - abstract class AphrontApplicationConfiguration extends Phobject { 8 + final class AphrontApplicationConfiguration 9 + extends Phobject { 9 10 10 11 private $request; 11 12 private $host; 12 13 private $path; 13 14 private $console; 14 15 15 - abstract public function buildRequest(); 16 - abstract public function build404Controller(); 17 - abstract public function buildRedirectController($uri, $external); 16 + public function buildRequest() { 17 + $parser = new PhutilQueryStringParser(); 18 + 19 + $data = array(); 20 + $data += $_POST; 21 + $data += $parser->parseQueryString(idx($_SERVER, 'QUERY_STRING', '')); 22 + 23 + $cookie_prefix = PhabricatorEnv::getEnvConfig('phabricator.cookie-prefix'); 24 + 25 + $request = new AphrontRequest($this->getHost(), $this->getPath()); 26 + $request->setRequestData($data); 27 + $request->setApplicationConfiguration($this); 28 + $request->setCookiePrefix($cookie_prefix); 29 + 30 + return $request; 31 + } 18 32 19 - final public function setRequest(AphrontRequest $request) { 33 + public function build404Controller() { 34 + return array(new Phabricator404Controller(), array()); 35 + } 36 + 37 + public function buildRedirectController($uri, $external) { 38 + return array( 39 + new PhabricatorRedirectController(), 40 + array( 41 + 'uri' => $uri, 42 + 'external' => $external, 43 + ), 44 + ); 45 + } 46 + 47 + public function setRequest(AphrontRequest $request) { 20 48 $this->request = $request; 21 49 return $this; 22 50 } 23 51 24 - final public function getRequest() { 52 + public function getRequest() { 25 53 return $this->request; 26 54 } 27 55 28 - final public function getConsole() { 56 + public function getConsole() { 29 57 return $this->console; 30 58 } 31 59 32 - final public function setConsole($console) { 60 + public function setConsole($console) { 33 61 $this->console = $console; 34 62 return $this; 35 63 } 36 64 37 - final public function setHost($host) { 65 + public function setHost($host) { 38 66 $this->host = $host; 39 67 return $this; 40 68 } 41 69 42 - final public function getHost() { 70 + public function getHost() { 43 71 return $this->host; 44 72 } 45 73 46 - final public function setPath($path) { 74 + public function setPath($path) { 47 75 $this->path = $path; 48 76 return $this; 49 77 } 50 78 51 - final public function getPath() { 79 + public function getPath() { 52 80 return $this->path; 53 81 } 54 - 55 - public function willBuildRequest() {} 56 82 57 83 58 84 /** ··· 126 152 'M' => idx($_SERVER, 'REQUEST_METHOD', '-'), 127 153 )); 128 154 155 + self::readHTTPPOSTData(); 156 + 129 157 DarkConsoleXHProfPluginAPI::hookProfiler(); 130 158 131 159 // We just activated the profiler, so we don't need to keep track of ··· 142 170 $host = AphrontRequest::getHTTPHeader('Host'); 143 171 $path = $_REQUEST['__path__']; 144 172 145 - switch ($host) { 146 - default: 147 - $config_key = 'aphront.default-application-configuration-class'; 148 - $application = PhabricatorEnv::newObjectFromConfig($config_key); 149 - break; 150 - } 173 + $application = new self(); 151 174 152 175 $application->setHost($host); 153 176 $application->setPath($path); 154 - $application->willBuildRequest(); 155 177 $request = $application->buildRequest(); 156 178 157 179 // Now that we have a request, convert the write guard into one which ··· 313 335 * parameters. 314 336 * @task routing 315 337 */ 316 - final private function buildController() { 338 + private function buildController() { 317 339 $request = $this->getRequest(); 318 340 319 341 // If we're configured to operate in cluster mode, reject requests which ··· 706 728 return id(new AphrontJSONResponse()) 707 729 ->setAddJSONShield(false) 708 730 ->setContent($result); 731 + } 732 + 733 + private static function readHTTPPOSTData() { 734 + $request_method = idx($_SERVER, 'REQUEST_METHOD'); 735 + if ($request_method === 'PUT') { 736 + // For PUT requests, do nothing: in particular, do NOT read input. This 737 + // allows us to stream input later and process very large PUT requests, 738 + // like those coming from Git LFS. 739 + return; 740 + } 741 + 742 + 743 + // For POST requests, we're going to read the raw input ourselves here 744 + // if we can. Among other things, this corrects variable names with 745 + // the "." character in them, which PHP normally converts into "_". 746 + 747 + // There are two major considerations here: whether the 748 + // `enable_post_data_reading` option is set, and whether the content 749 + // type is "multipart/form-data" or not. 750 + 751 + // If `enable_post_data_reading` is off, we're free to read the entire 752 + // raw request body and parse it -- and we must, because $_POST and 753 + // $_FILES are not built for us. If `enable_post_data_reading` is on, 754 + // which is the default, we may not be able to read the body (the 755 + // documentation says we can't, but empirically we can at least some 756 + // of the time). 757 + 758 + // If the content type is "multipart/form-data", we need to build both 759 + // $_POST and $_FILES, which is involved. The body itself is also more 760 + // difficult to parse than other requests. 761 + $raw_input = PhabricatorStartup::getRawInput(); 762 + $parser = new PhutilQueryStringParser(); 763 + 764 + if (strlen($raw_input)) { 765 + $content_type = idx($_SERVER, 'CONTENT_TYPE'); 766 + $is_multipart = preg_match('@^multipart/form-data@i', $content_type); 767 + if ($is_multipart && !ini_get('enable_post_data_reading')) { 768 + $multipart_parser = id(new AphrontMultipartParser()) 769 + ->setContentType($content_type); 770 + 771 + $multipart_parser->beginParse(); 772 + $multipart_parser->continueParse($raw_input); 773 + $parts = $multipart_parser->endParse(); 774 + 775 + $query_string = array(); 776 + foreach ($parts as $part) { 777 + if (!$part->isVariable()) { 778 + continue; 779 + } 780 + 781 + $name = $part->getName(); 782 + $value = $part->getVariableValue(); 783 + 784 + $query_string[] = urlencode($name).'='.urlencode($value); 785 + } 786 + $query_string = implode('&', $query_string); 787 + $post = $parser->parseQueryString($query_string); 788 + 789 + $files = array(); 790 + foreach ($parts as $part) { 791 + if ($part->isVariable()) { 792 + continue; 793 + } 794 + 795 + $files[$part->getName()] = $part->getPHPFileDictionary(); 796 + } 797 + $_FILES = $files; 798 + } else { 799 + $post = $parser->parseQueryString($raw_input); 800 + } 801 + 802 + $_POST = $post; 803 + PhabricatorStartup::rebuildRequest(); 804 + } else if ($_POST) { 805 + $post = filter_input_array(INPUT_POST, FILTER_UNSAFE_RAW); 806 + if (is_array($post)) { 807 + $_POST = $post; 808 + PhabricatorStartup::rebuildRequest(); 809 + } 810 + } 709 811 } 710 812 711 813 }
-121
src/aphront/configuration/AphrontDefaultApplicationConfiguration.php
··· 1 - <?php 2 - 3 - /** 4 - * NOTE: Do not extend this! 5 - * 6 - * @concrete-extensible 7 - */ 8 - class AphrontDefaultApplicationConfiguration 9 - extends AphrontApplicationConfiguration { 10 - 11 - /** 12 - * @phutil-external-symbol class PhabricatorStartup 13 - */ 14 - public function buildRequest() { 15 - $parser = new PhutilQueryStringParser(); 16 - $data = array(); 17 - 18 - $request_method = idx($_SERVER, 'REQUEST_METHOD'); 19 - if ($request_method === 'PUT') { 20 - // For PUT requests, do nothing: in particular, do NOT read input. This 21 - // allows us to stream input later and process very large PUT requests, 22 - // like those coming from Git LFS. 23 - } else { 24 - // For POST requests, we're going to read the raw input ourselves here 25 - // if we can. Among other things, this corrects variable names with 26 - // the "." character in them, which PHP normally converts into "_". 27 - 28 - // There are two major considerations here: whether the 29 - // `enable_post_data_reading` option is set, and whether the content 30 - // type is "multipart/form-data" or not. 31 - 32 - // If `enable_post_data_reading` is off, we're free to read the entire 33 - // raw request body and parse it -- and we must, because $_POST and 34 - // $_FILES are not built for us. If `enable_post_data_reading` is on, 35 - // which is the default, we may not be able to read the body (the 36 - // documentation says we can't, but empirically we can at least some 37 - // of the time). 38 - 39 - // If the content type is "multipart/form-data", we need to build both 40 - // $_POST and $_FILES, which is involved. The body itself is also more 41 - // difficult to parse than other requests. 42 - $raw_input = PhabricatorStartup::getRawInput(); 43 - if (strlen($raw_input)) { 44 - $content_type = idx($_SERVER, 'CONTENT_TYPE'); 45 - $is_multipart = preg_match('@^multipart/form-data@i', $content_type); 46 - if ($is_multipart && !ini_get('enable_post_data_reading')) { 47 - $multipart_parser = id(new AphrontMultipartParser()) 48 - ->setContentType($content_type); 49 - 50 - $multipart_parser->beginParse(); 51 - $multipart_parser->continueParse($raw_input); 52 - $parts = $multipart_parser->endParse(); 53 - 54 - $query_string = array(); 55 - foreach ($parts as $part) { 56 - if (!$part->isVariable()) { 57 - continue; 58 - } 59 - 60 - $name = $part->getName(); 61 - $value = $part->getVariableValue(); 62 - 63 - $query_string[] = urlencode($name).'='.urlencode($value); 64 - } 65 - $query_string = implode('&', $query_string); 66 - $post = $parser->parseQueryString($query_string); 67 - 68 - $files = array(); 69 - foreach ($parts as $part) { 70 - if ($part->isVariable()) { 71 - continue; 72 - } 73 - 74 - $files[$part->getName()] = $part->getPHPFileDictionary(); 75 - } 76 - $_FILES = $files; 77 - } else { 78 - $post = $parser->parseQueryString($raw_input); 79 - } 80 - 81 - $_POST = $post; 82 - PhabricatorStartup::rebuildRequest(); 83 - 84 - $data += $post; 85 - } else if ($_POST) { 86 - $post = filter_input_array(INPUT_POST, FILTER_UNSAFE_RAW); 87 - if (is_array($post)) { 88 - $_POST = $post; 89 - PhabricatorStartup::rebuildRequest(); 90 - } 91 - $data += $_POST; 92 - } 93 - } 94 - 95 - $data += $parser->parseQueryString(idx($_SERVER, 'QUERY_STRING', '')); 96 - 97 - $cookie_prefix = PhabricatorEnv::getEnvConfig('phabricator.cookie-prefix'); 98 - 99 - $request = new AphrontRequest($this->getHost(), $this->getPath()); 100 - $request->setRequestData($data); 101 - $request->setApplicationConfiguration($this); 102 - $request->setCookiePrefix($cookie_prefix); 103 - 104 - return $request; 105 - } 106 - 107 - public function build404Controller() { 108 - return array(new Phabricator404Controller(), array()); 109 - } 110 - 111 - public function buildRedirectController($uri, $external) { 112 - return array( 113 - new PhabricatorRedirectController(), 114 - array( 115 - 'uri' => $uri, 116 - 'external' => $external, 117 - ), 118 - ); 119 - } 120 - 121 - }
+1 -1
src/applications/base/controller/__tests__/PhabricatorAccessControlTestCase.php
··· 12 12 $root = dirname(phutil_get_library_root('phabricator')); 13 13 require_once $root.'/support/startup/PhabricatorStartup.php'; 14 14 15 - $application_configuration = new AphrontDefaultApplicationConfiguration(); 15 + $application_configuration = new AphrontApplicationConfiguration(); 16 16 17 17 $host = 'meow.example.com'; 18 18
+4
src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
··· 416 416 'metamta.pholio.subject-prefix' => $prefix_reason, 417 417 'metamta.phriction.subject-prefix' => $prefix_reason, 418 418 419 + 'aphront.default-application-configuration-class' => pht( 420 + 'This ancient extension point has been replaced with other '. 421 + 'mechanisms, including "AphrontSite".'), 422 + 419 423 ); 420 424 421 425 return $ancient_config;
-8
src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php
··· 36 36 'occur. Specify a list of classes which extend '. 37 37 'PhabricatorEventListener here.')) 38 38 ->addExample('MyEventListener', pht('Valid Setting')), 39 - $this->newOption( 40 - 'aphront.default-application-configuration-class', 41 - 'class', 42 - 'AphrontDefaultApplicationConfiguration') 43 - ->setLocked(true) 44 - ->setBaseClass('AphrontApplicationConfiguration') 45 - // TODO: This could probably use some better documentation. 46 - ->setDescription(pht('Application configuration class.')), 47 39 ); 48 40 } 49 41