Page MenuHomePhabricator

D14008.diff
No OneTemporary

D14008.diff

diff --git a/scripts/aphront/aphrontpath.php b/scripts/aphront/aphrontpath.php
deleted file mode 100755
--- a/scripts/aphront/aphrontpath.php
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env php
-<?php
-
-$root = dirname(dirname(dirname(__FILE__)));
-require_once $root.'/scripts/__init_script__.php';
-
-if ($argc !== 2 || $argv[1] === '--help') {
- echo pht('Usage: %s', 'aphrontpath.php <url>')."\n";
- echo pht(
- "Purpose: Print controller which will process passed %s.\n",
- '<url>');
- exit(1);
-}
-
-$url = parse_url($argv[1]);
-$path = '/'.(isset($url['path']) ? ltrim($url['path'], '/') : '');
-
-$config_key = 'aphront.default-application-configuration-class';
-$application = PhabricatorEnv::newObjectFromConfig($config_key);
-$application->setRequest(new AphrontRequest('', $path));
-
-list($controller) = $application->buildControllerForPath($path);
-if (!$controller && substr($path, -1) !== '/') {
- list($controller) = $application->buildControllerForPath($path.'/');
-}
-if ($controller) {
- echo get_class($controller)."\n";
-}
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
@@ -158,6 +158,8 @@
'AphrontRequest' => 'aphront/AphrontRequest.php',
'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php',
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
+ 'AphrontRoutingMap' => 'aphront/site/AphrontRoutingMap.php',
+ 'AphrontRoutingResult' => 'aphront/site/AphrontRoutingResult.php',
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
'AphrontSite' => 'aphront/site/AphrontSite.php',
'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php',
@@ -166,7 +168,6 @@
'AphrontTagView' => 'view/AphrontTagView.php',
'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php',
'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php',
- 'AphrontURIMapper' => 'aphront/AphrontURIMapper.php',
'AphrontUnhandledExceptionResponse' => 'aphront/response/AphrontUnhandledExceptionResponse.php',
'AphrontUsageException' => 'aphront/exception/AphrontUsageException.php',
'AphrontView' => 'view/AphrontView.php',
@@ -3126,7 +3127,6 @@
'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php',
'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php',
'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php',
- 'PhameBlogResourceSite' => 'applications/phame/site/PhameBlogResourceSite.php',
'PhameBlogSearchEngine' => 'applications/phame/query/PhameBlogSearchEngine.php',
'PhameBlogSite' => 'applications/phame/site/PhameBlogSite.php',
'PhameBlogSkin' => 'applications/phame/skins/PhameBlogSkin.php',
@@ -3777,6 +3777,8 @@
'AphrontRequest' => 'Phobject',
'AphrontRequestTestCase' => 'PhabricatorTestCase',
'AphrontResponse' => 'Phobject',
+ 'AphrontRoutingMap' => 'Phobject',
+ 'AphrontRoutingResult' => 'Phobject',
'AphrontSideNavFilterView' => 'AphrontView',
'AphrontSite' => 'Phobject',
'AphrontStackTraceView' => 'AphrontView',
@@ -3785,7 +3787,6 @@
'AphrontTagView' => 'AphrontView',
'AphrontTokenizerTemplateView' => 'AphrontView',
'AphrontTypeaheadTemplateView' => 'AphrontView',
- 'AphrontURIMapper' => 'Phobject',
'AphrontUnhandledExceptionResponse' => 'AphrontStandaloneHTMLResponse',
'AphrontUsageException' => 'AphrontException',
'AphrontView' => array(
@@ -7238,7 +7239,6 @@
'PhameBlogListController' => 'PhameController',
'PhameBlogLiveController' => 'PhameController',
'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
- 'PhameBlogResourceSite' => 'PhameSite',
'PhameBlogSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhameBlogSite' => 'PhameSite',
'PhameBlogSkin' => 'PhabricatorController',
diff --git a/src/aphront/AphrontRequest.php b/src/aphront/AphrontRequest.php
--- a/src/aphront/AphrontRequest.php
+++ b/src/aphront/AphrontRequest.php
@@ -26,6 +26,8 @@
private $requestData;
private $user;
private $applicationConfiguration;
+ private $site;
+ private $controller;
private $uriData;
private $cookiePrefix;
@@ -77,6 +79,24 @@
return $uri->getDomain();
}
+ public function setSite(AphrontSite $site) {
+ $this->site = $site;
+ return $this;
+ }
+
+ public function getSite() {
+ return $this->site;
+ }
+
+ public function setController(AphrontController $controller) {
+ $this->controller = $controller;
+ return $this;
+ }
+
+ public function getController() {
+ return $this->controller;
+ }
+
/* -( Accessing Request Data )--------------------------------------------- */
diff --git a/src/aphront/AphrontURIMapper.php b/src/aphront/AphrontURIMapper.php
deleted file mode 100644
--- a/src/aphront/AphrontURIMapper.php
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-
-final class AphrontURIMapper extends Phobject {
-
- private $map;
-
- public function __construct(array $map) {
- $this->map = $map;
- }
-
- public function mapPath($path) {
- $map = $this->map;
- foreach ($map as $rule => $value) {
- list($controller, $data) = $this->tryRule($rule, $value, $path);
- if ($controller) {
- foreach ($data as $k => $v) {
- if (is_numeric($k)) {
- unset($data[$k]);
- }
- }
- return array($controller, $data);
- }
- }
-
- return array(null, null);
- }
-
- private function tryRule($rule, $value, $path) {
- $match = null;
- $pattern = '#^'.$rule.(is_array($value) ? '' : '$').'#';
- if (!preg_match($pattern, $path, $match)) {
- return array(null, null);
- }
-
- if (!is_array($value)) {
- return array($value, $match);
- }
-
- $path = substr($path, strlen($match[0]));
- foreach ($value as $srule => $sval) {
- list($controller, $data) = $this->tryRule($srule, $sval, $path);
- if ($controller) {
- return array($controller, $data + $match);
- }
- }
-
- return array(null, null);
- }
-
-}
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
@@ -210,7 +210,9 @@
));
$multimeter->setEventContext('web.'.$controller_class);
+ $request->setController($controller);
$request->setURIMap($uri_data);
+
$controller->setRequest($request);
// If execution throws an exception and then trying to render that
@@ -283,35 +285,13 @@
/**
- * Using builtin and application routes, build the appropriate
- * @{class:AphrontController} class for the request. To route a request, we
- * first test if the HTTP_HOST is configured as a valid Phabricator URI. If
- * it isn't, we do a special check to see if it's a custom domain for a blog
- * in the Phame application and if that fails we error. Otherwise, we test
- * against all application routes from installed
- * @{class:PhabricatorApplication}s.
- *
- * If we match a route, we construct the controller it points at, build it,
- * and return it.
- *
- * If we fail to match a route, but the current path is missing a trailing
- * "/", we try routing the same path with a trailing "/" and do a redirect
- * if that has a valid route. The idea is to canoncalize URIs for consistency,
- * but avoid breaking noncanonical URIs that we can easily salvage.
- *
- * NOTE: We only redirect on GET. On POST, we'd drop parameters and most
- * likely mutate the request implicitly, and a bad POST usually indicates a
- * programming error rather than a sloppy typist.
- *
- * If the failing path already has a trailing "/", or we can't route the
- * version with a "/", we call @{method:build404Controller}, which build a
- * fallback @{class:AphrontController}.
+ * Build a controller to respond to the request.
*
* @return pair<AphrontController,dict> Controller and dictionary of request
* parameters.
* @task routing
*/
- final public function buildController() {
+ final private function buildController() {
$request = $this->getRequest();
// If we're configured to operate in cluster mode, reject requests which
@@ -373,78 +353,48 @@
}
}
- // TODO: Really, the Site should get more control here and be able to
- // do its own routing logic if it wants, but we don't need that for now.
- $path = $site->getPathForRouting($request);
-
- list($controller, $uri_data) = $this->buildControllerForPath($path);
- if (!$controller) {
- if (!preg_match('@/$@', $path)) {
- // If we failed to match anything but don't have a trailing slash, try
- // to add a trailing slash and issue a redirect if that resolves.
- list($controller, $uri_data) = $this->buildControllerForPath($path.'/');
-
- // NOTE: For POST, just 404 instead of redirecting, since the redirect
- // will be a GET without parameters.
+ $maps = $site->getRoutingMaps();
+ $path = $request->getPath();
- if ($controller && !$request->isHTTPPost()) {
- $slash_uri = $request->getRequestURI()->setPath($path.'/');
+ $result = $this->routePath($maps, $path);
+ if ($result) {
+ return $result;
+ }
- $external = strlen($request->getRequestURI()->getDomain());
- return $this->buildRedirectController($slash_uri, $external);
- }
+ // If we failed to match anything but don't have a trailing slash, try
+ // to add a trailing slash and issue a redirect if that resolves.
+
+ // NOTE: We only do this for GET, since redirects switch to GET and drop
+ // data like POST parameters.
+ if (!preg_match('@/$@', $path) && $request->isHTTPGet()) {
+ $result = $this->routePath($maps, $path.'/');
+ if ($result) {
+ $slash_uri = $request->getRequestURI()->setPath($path.'/');
+ $external = strlen($request->getRequestURI()->getDomain());
+ return $this->buildRedirectController($slash_uri, $external);
}
- return $this->build404Controller();
}
- return array($controller, $uri_data);
+ return $this->build404Controller();
}
-
/**
* Map a specific path to the corresponding controller. For a description
* of routing, see @{method:buildController}.
*
+ * @param list<AphrontRoutingMap> List of routing maps.
+ * @param string Path to route.
* @return pair<AphrontController,dict> Controller and dictionary of request
* parameters.
* @task routing
*/
- final public function buildControllerForPath($path) {
- $maps = array();
-
- $applications = PhabricatorApplication::getAllInstalledApplications();
- foreach ($applications as $application) {
- $maps[] = array($application, $application->getRoutes());
- }
-
- $current_application = null;
- $controller_class = null;
- foreach ($maps as $map_info) {
- list($application, $map) = $map_info;
-
- $mapper = new AphrontURIMapper($map);
- list($controller_class, $uri_data) = $mapper->mapPath($path);
-
- if ($controller_class) {
- if ($application) {
- $current_application = $application;
- }
- break;
+ private function routePath(array $maps, $path) {
+ foreach ($maps as $map) {
+ $result = $map->routePath($path);
+ if ($result) {
+ return array($result->getController(), $result->getURIData());
}
}
-
- if (!$controller_class) {
- return array(null, null);
- }
-
- $request = $this->getRequest();
-
- $controller = newv($controller_class, array());
- if ($current_application) {
- $controller->setCurrentApplication($current_application);
- }
-
- return array($controller, $uri_data);
}
private function buildSiteForRequest(AphrontRequest $request) {
@@ -469,6 +419,8 @@
$host));
}
+ $request->setSite($site);
+
return $site;
}
diff --git a/src/aphront/site/AphrontRoutingMap.php b/src/aphront/site/AphrontRoutingMap.php
new file mode 100644
--- /dev/null
+++ b/src/aphront/site/AphrontRoutingMap.php
@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * Collection of routes on a site for an application.
+ *
+ * @task info Map Information
+ * @task routing Routing
+ */
+final class AphrontRoutingMap extends Phobject {
+
+ private $site;
+ private $application;
+ private $routes = array();
+
+
+/* -( Map Info )----------------------------------------------------------- */
+
+
+ public function setSite(AphrontSite $site) {
+ $this->site = $site;
+ return $this;
+ }
+
+ public function getSite() {
+ return $this->site;
+ }
+
+ public function setApplication(PhabricatorApplication $application) {
+ $this->application = $application;
+ return $this;
+ }
+
+ public function getApplication() {
+ return $this->application;
+ }
+
+ public function setRoutes(array $routes) {
+ $this->routes = $routes;
+ return $this;
+ }
+
+ public function getRoutes() {
+ return $this->routes;
+ }
+
+
+/* -( Routing )------------------------------------------------------------ */
+
+
+ /**
+ * Find the route matching a path, if one exists.
+ *
+ * @param string Path to route.
+ * @return AphrontRoutingResult|null Routing result, if path matches map.
+ * @task routing
+ */
+ public function routePath($path) {
+ $map = $this->getRoutes();
+
+ foreach ($map as $route => $value) {
+ $match = $this->tryRoute($route, $value, $path);
+ if (!$match) {
+ continue;
+ }
+
+ $result = $this->newRoutingResult();
+ $application = $result->getApplication();
+
+ $controller_class = $match['class'];
+ $controller = newv($controller_class, array());
+ $controller->setCurrentApplication($application);
+
+ $result
+ ->setController($controller)
+ ->setURIData($match['data']);
+
+ return $result;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Test a sub-map to see if any routes match a path.
+ *
+ * @param string Path to route.
+ * @param string Pattern from the map.
+ * @param string Value from the map.
+ * @return dict<string, wild>|null Match details, if path matches sub-map.
+ * @task routing
+ */
+ private function tryRoute($route, $value, $path) {
+ $has_submap = is_array($value);
+
+ if (!$has_submap) {
+ // If the value is a controller rather than a sub-map, any matching
+ // route must completely consume the path.
+ $pattern = '(^'.$route.'\z)';
+ } else {
+ $pattern = '(^'.$route.')';
+ }
+
+ $data = null;
+ $ok = preg_match($pattern, $path, $data);
+ if ($ok === false) {
+ throw new Exception(
+ pht(
+ 'Routing fragment "%s" is not a valid regular expression.',
+ $route));
+ }
+
+ if (!$ok) {
+ return null;
+ }
+
+ $path_match = $data[0];
+
+ // Clean up the data. We only want to retain named capturing groups, not
+ // the duplicated numeric captures.
+ foreach ($data as $k => $v) {
+ if (is_numeric($k)) {
+ unset($data[$k]);
+ }
+ }
+
+ if (!$has_submap) {
+ return array(
+ 'class' => $value,
+ 'data' => $data,
+ );
+ }
+
+ $sub_path = substr($path, strlen($path_match));
+ foreach ($value as $sub_route => $sub_value) {
+ $result = $this->tryRoute($sub_route, $sub_value, $sub_path);
+ if ($result) {
+ $result['data'] += $data;
+ return $result;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Build a new routing result for this map.
+ *
+ * @return AphrontRoutingResult New, empty routing result.
+ * @task routing
+ */
+ private function newRoutingResult() {
+ return id(new AphrontRoutingResult())
+ ->setSite($this->getSite())
+ ->setApplication($this->getApplication());
+ }
+
+}
diff --git a/src/aphront/site/AphrontRoutingResult.php b/src/aphront/site/AphrontRoutingResult.php
new file mode 100644
--- /dev/null
+++ b/src/aphront/site/AphrontRoutingResult.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * Details about a routing map match for a path.
+ *
+ * @param info Result Information
+ */
+final class AphrontRoutingResult extends Phobject {
+
+ private $site;
+ private $application;
+ private $controller;
+ private $uriData;
+
+
+/* -( Result Information )------------------------------------------------- */
+
+
+ public function setSite(AphrontSite $site) {
+ $this->site = $site;
+ return $this;
+ }
+
+ public function getSite() {
+ return $this->site;
+ }
+
+ public function setApplication(PhabricatorApplication $application) {
+ $this->application = $application;
+ return $this;
+ }
+
+ public function getApplication() {
+ return $this->application;
+ }
+
+ public function setController(AphrontController $controller) {
+ $this->controller = $controller;
+ return $this;
+ }
+
+ public function getController() {
+ return $this->controller;
+ }
+
+ public function setURIData(array $uri_data) {
+ $this->uriData = $uri_data;
+ return $this;
+ }
+
+ public function getURIData() {
+ return $this->uriData;
+ }
+
+}
diff --git a/src/aphront/site/AphrontSite.php b/src/aphront/site/AphrontSite.php
--- a/src/aphront/site/AphrontSite.php
+++ b/src/aphront/site/AphrontSite.php
@@ -7,14 +7,7 @@
abstract public function shouldRequireHTTPS();
abstract public function newSiteForRequest(AphrontRequest $request);
-
- /**
- * NOTE: This is temporary glue; eventually, sites will return an entire
- * route map.
- */
- public function getPathForRouting(AphrontRequest $request) {
- return $request->getPath();
- }
+ abstract public function getRoutingMaps();
protected function isHostMatch($host, array $uris) {
foreach ($uris as $uri) {
@@ -32,14 +25,9 @@
return false;
}
- protected function isPathPrefixMatch($path, array $paths) {
- foreach ($paths as $candidate) {
- if (strncmp($path, $candidate, strlen($candidate)) === 0) {
- return true;
- }
- }
-
- return false;
+ protected function newRoutingMap() {
+ return id(new AphrontRoutingMap())
+ ->setSite($this);
}
final public static function getAllSites() {
diff --git a/src/aphront/site/PhabricatorPlatformSite.php b/src/aphront/site/PhabricatorPlatformSite.php
--- a/src/aphront/site/PhabricatorPlatformSite.php
+++ b/src/aphront/site/PhabricatorPlatformSite.php
@@ -37,4 +37,17 @@
return null;
}
+ public function getRoutingMaps() {
+ $applications = PhabricatorApplication::getAllInstalledApplications();
+
+ $maps = array();
+ foreach ($applications as $application) {
+ $maps[] = $this->newRoutingMap()
+ ->setApplication($application)
+ ->setRoutes($application->getRoutes());
+ }
+
+ return $maps;
+ }
+
}
diff --git a/src/aphront/site/PhabricatorResourceSite.php b/src/aphront/site/PhabricatorResourceSite.php
--- a/src/aphront/site/PhabricatorResourceSite.php
+++ b/src/aphront/site/PhabricatorResourceSite.php
@@ -22,20 +22,20 @@
return new PhabricatorResourceSite();
}
- // These are CDN routes, so we let them through even if the "Host" header
- // doesn't match anything we recognize. The
- $whitelist = array(
- '/res/',
- '/file/data/',
- '/file/xform/',
- );
-
- $path = $request->getPath();
- if ($this->isPathPrefixMatch($path, $whitelist)) {
- return new PhabricatorResourceSite();
+ return null;
+ }
+
+ public function getRoutingMaps() {
+ $applications = PhabricatorApplication::getAllInstalledApplications();
+
+ $maps = array();
+ foreach ($applications as $application) {
+ $maps[] = $this->newRoutingMap()
+ ->setApplication($application)
+ ->setRoutes($application->getResourceRoutes());
}
- return null;
+ return $maps;
}
}
diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php
--- a/src/applications/base/PhabricatorApplication.php
+++ b/src/applications/base/PhabricatorApplication.php
@@ -243,6 +243,10 @@
return array();
}
+ public function getResourceRoutes() {
+ return array();
+ }
+
/* -( Email Integration )-------------------------------------------------- */
diff --git a/src/applications/celerity/application/PhabricatorCelerityApplication.php b/src/applications/celerity/application/PhabricatorCelerityApplication.php
--- a/src/applications/celerity/application/PhabricatorCelerityApplication.php
+++ b/src/applications/celerity/application/PhabricatorCelerityApplication.php
@@ -15,6 +15,17 @@
}
public function getRoutes() {
+ // We serve resources from both the platform site and the resource site.
+ // This is safe because the user doesn't have any direct control over
+ // resources.
+
+ // The advantage of serving resources from the resource site (if possible)
+ // is that we can use a CDN there if one is configured, but there is no
+ // particular security concern.
+ return $this->getResourceRoutes();
+ }
+
+ public function getResourceRoutes() {
$extensions = CelerityResourceController::getSupportedResourceTypes();
$extensions = array_keys($extensions);
$extensions = implode('|', $extensions);
diff --git a/src/applications/console/plugin/DarkConsoleRequestPlugin.php b/src/applications/console/plugin/DarkConsoleRequestPlugin.php
--- a/src/applications/console/plugin/DarkConsoleRequestPlugin.php
+++ b/src/applications/console/plugin/DarkConsoleRequestPlugin.php
@@ -14,66 +14,121 @@
}
public function generateData() {
+ $addr = idx($_SERVER, 'SERVER_ADDR');
+ if ($addr) {
+ $hostname = @gethostbyaddr($addr);
+ } else {
+ $hostname = null;
+ }
+
+ $controller = $this->getRequest()->getController();
+ if ($controller) {
+ $controller_class = get_class($controller);
+ } else {
+ $controller_class = null;
+ }
+
+ $site = $this->getRequest()->getSite();
+ if ($site) {
+ $site_class = get_class($site);
+ } else {
+ $site_class = null;
+ }
+
return array(
- 'Request' => $_REQUEST,
- 'Server' => $_SERVER,
+ 'request' => $_REQUEST,
+ 'server' => $_SERVER,
+ 'special' => array(
+ 'site' => $site_class,
+ 'controller' => $controller_class,
+ 'machine' => php_uname('n'),
+ 'host' => $addr,
+ 'hostname' => $hostname,
+ ),
);
}
public function renderPanel() {
$data = $this->getData();
- $sections = array(
- 'Basics' => array(
- 'Machine' => php_uname('n'),
- ),
+ $special_map = array(
+ 'site' => pht('Site'),
+ 'controller' => pht('Controller'),
+ 'machine' => pht('Machine'),
+ 'host' => pht('Host'),
+ 'hostname' => pht('Hostname'),
);
- // NOTE: This may not be present for some SAPIs, like php-fpm.
- if (!empty($data['Server']['SERVER_ADDR'])) {
- $addr = $data['Server']['SERVER_ADDR'];
- $sections['Basics']['Host'] = $addr;
- $sections['Basics']['Hostname'] = @gethostbyaddr($addr);
+ $special = idx($data, 'special', array());
+
+ $rows = array();
+ foreach ($special_map as $key => $label) {
+ $rows[] = array(
+ $label,
+ idx($special, $key),
+ );
}
- $sections = array_merge($sections, $data);
+ $sections = array();
+ $sections[] = array(
+ 'name' => pht('Basics'),
+ 'rows' => $rows,
+ );
$mask = array(
'HTTP_COOKIE' => true,
'HTTP_X_PHABRICATOR_CSRF' => true,
);
- $out = array();
- foreach ($sections as $header => $map) {
+ $maps = array(
+ array(
+ 'name' => pht('Request'),
+ 'data' => idx($data, 'request', array()),
+ ),
+ array(
+ 'name' => pht('Server'),
+ 'data' => idx($data, 'server', array()),
+ ),
+ );
+
+ foreach ($maps as $map) {
+ $data = $map['data'];
$rows = array();
- foreach ($map as $key => $value) {
+ foreach ($data as $key => $value) {
if (isset($mask[$key])) {
- $rows[] = array(
- $key,
- phutil_tag('em', array(), pht('(Masked)')),
- );
+ $value = phutil_tag('em', array(), pht('(Masked)'));
+ } else if (is_array($value)) {
+ $value = @json_encode($value);
} else {
- $rows[] = array(
- $key,
- (is_array($value) ? json_encode($value) : $value),
- );
+ $value = $value;
}
+
+ $rows[] = array(
+ $key,
+ $value,
+ );
}
- $table = new AphrontTableView($rows);
- $table->setHeaders(
- array(
- $header,
- null,
- ));
- $table->setColumnClasses(
- array(
- 'header',
- 'wide wrap',
- ));
- $out[] = $table->render();
+ $sections[] = array(
+ 'name' => $map['name'],
+ 'rows' => $rows,
+ );
}
- return phutil_implode_html("\n", $out);
+ $out = array();
+ foreach ($sections as $section) {
+ $out[] = id(new AphrontTableView($section['rows']))
+ ->setHeaders(
+ array(
+ $section['name'],
+ null,
+ ))
+ ->setColumnClasses(
+ array(
+ 'header',
+ 'wide wrap',
+ ));
+ }
+ return $out;
}
}
diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php
--- a/src/applications/files/application/PhabricatorFilesApplication.php
+++ b/src/applications/files/application/PhabricatorFilesApplication.php
@@ -78,25 +78,36 @@
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorFileEditController',
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
- 'data/'.
- '(?:@(?P<instance>[^/]+)/)?'.
- '(?P<key>[^/]+)/'.
- '(?P<phid>[^/]+)/'.
- '(?:(?P<token>[^/]+)/)?'.
- '.*'
- => 'PhabricatorFileDataController',
'proxy/' => 'PhabricatorFileProxyController',
- 'xform/'.
- '(?:@(?P<instance>[^/]+)/)?'.
- '(?P<transform>[^/]+)/'.
- '(?P<phid>[^/]+)/'.
- '(?P<key>[^/]+)/'
- => 'PhabricatorFileTransformController',
'transforms/(?P<id>[1-9]\d*)/' =>
'PhabricatorFileTransformListController',
'uploaddialog/' => 'PhabricatorFileUploadDialogController',
'download/(?P<phid>[^/]+)/' => 'PhabricatorFileDialogController',
- ),
+ ) + $this->getResourceSubroutes(),
+ );
+ }
+
+ public function getResourceRoutes() {
+ return array(
+ '/file/' => $this->getResourceSubroutes(),
+ );
+ }
+
+ private function getResourceSubroutes() {
+ return array(
+ 'data/'.
+ '(?:@(?P<instance>[^/]+)/)?'.
+ '(?P<key>[^/]+)/'.
+ '(?P<phid>[^/]+)/'.
+ '(?:(?P<token>[^/]+)/)?'.
+ '.*'
+ => 'PhabricatorFileDataController',
+ 'xform/'.
+ '(?:@(?P<instance>[^/]+)/)?'.
+ '(?P<transform>[^/]+)/'.
+ '(?P<phid>[^/]+)/'.
+ '(?P<key>[^/]+)/'
+ => 'PhabricatorFileTransformController',
);
}
diff --git a/src/applications/phame/application/PhabricatorPhameApplication.php b/src/applications/phame/application/PhabricatorPhameApplication.php
--- a/src/applications/phame/application/PhabricatorPhameApplication.php
+++ b/src/applications/phame/application/PhabricatorPhameApplication.php
@@ -39,9 +39,6 @@
return array(
'/phame/' => array(
'' => 'PhamePostListController',
- 'r/(?P<id>\d+)/(?P<hash>[^/]+)/(?P<name>.*)'
- => 'PhameResourceController',
-
'live/(?P<id>[^/]+)/(?P<more>.*)' => 'PhameBlogLiveController',
'post/' => array(
'(?:(?P<filter>draft|all)/)?' => 'PhamePostListController',
@@ -65,6 +62,34 @@
'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController',
'new/' => 'PhameBlogEditController',
),
+ ) + $this->getResourceSubroutes(),
+ );
+ }
+
+ public function getResourceRoutes() {
+ return array(
+ '/phame/' => $this->getResourceSubroutes(),
+ );
+ }
+
+ private function getResourceSubroutes() {
+ return array(
+ 'r/(?P<id>\d+)/(?P<hash>[^/]+)/(?P<name>.*)' =>
+ 'PhameResourceController',
+ );
+ }
+
+ public function getBlogRoutes() {
+ return array(
+ '/(?P<more>.*)' => 'PhameBlogLiveController',
+ );
+ }
+
+ public function getBlogCDNRoutes() {
+ return array(
+ '/phame/' => array(
+ 'r/(?P<id>\d+)/(?P<hash>[^/]+)/(?P<name>.*)' =>
+ 'PhameResourceController',
),
);
}
diff --git a/src/applications/phame/controller/blog/PhameBlogLiveController.php b/src/applications/phame/controller/blog/PhameBlogLiveController.php
--- a/src/applications/phame/controller/blog/PhameBlogLiveController.php
+++ b/src/applications/phame/controller/blog/PhameBlogLiveController.php
@@ -8,14 +8,20 @@
public function handleRequest(AphrontRequest $request) {
$user = $request->getUser();
- $id = $request->getURIData('id');
- $blog = id(new PhameBlogQuery())
- ->setViewer($user)
- ->withIDs(array($id))
- ->executeOne();
- if (!$blog) {
- return new Aphront404Response();
+ $site = $request->getSite();
+ if ($site instanceof PhameBlogSite) {
+ $blog = $site->getBlog();
+ } else {
+ $id = $request->getURIData('id');
+
+ $blog = id(new PhameBlogQuery())
+ ->setViewer($user)
+ ->withIDs(array($id))
+ ->executeOne();
+ if (!$blog) {
+ return new Aphront404Response();
+ }
}
if ($blog->getDomain() && ($request->getHost() != $blog->getDomain())) {
diff --git a/src/applications/phame/site/PhameBlogResourceSite.php b/src/applications/phame/site/PhameBlogResourceSite.php
deleted file mode 100644
--- a/src/applications/phame/site/PhameBlogResourceSite.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-final class PhameBlogResourceSite extends PhameSite {
-
- public function getDescription() {
- return pht('Serves static resources for blogs.');
- }
-
- public function getPriority() {
- return 3000;
- }
-
- public function newSiteForRequest(AphrontRequest $request) {
- if (!$this->isPhameActive()) {
- return null;
- }
-
- $whitelist = array(
- '/phame/r/',
- );
-
- $path = $request->getPath();
- if (!$this->isPathPrefixMatch($path, $whitelist)) {
- return null;
- }
-
- return new PhameBlogResourceSite();
- }
-
-}
diff --git a/src/applications/phame/site/PhameBlogSite.php b/src/applications/phame/site/PhameBlogSite.php
--- a/src/applications/phame/site/PhameBlogSite.php
+++ b/src/applications/phame/site/PhameBlogSite.php
@@ -24,7 +24,7 @@
}
public function getPriority() {
- return 4000;
+ return 3000;
}
public function newSiteForRequest(AphrontRequest $request) {
@@ -53,11 +53,14 @@
return id(new PhameBlogSite())->setBlog($blog);
}
- public function getPathForRouting(AphrontRequest $request) {
- $path = $request->getPath();
- $id = $this->getBlog()->getID();
+ public function getRoutingMaps() {
+ $app = PhabricatorApplication::getByClass('PhabricatorPhameApplication');
- return "/phame/live/{$id}/{$path}";
+ $maps = array();
+ $maps[] = $this->newRoutingMap()
+ ->setApplication($app)
+ ->setRoutes($app->getBlogRoutes());
+ return $maps;
}
}

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 17, 11:55 AM (2 d, 23 h ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/fi/uw/j2n2fxq5kyf5mko7
Default Alt Text
D14008.diff (31 KB)

Event Timeline