Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14027452
D14008.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
31 KB
Referenced Files
None
Subscribers
None
D14008.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 9, 7:14 AM (1 w, 4 d 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)
Attached To
Mode
D14008: Push construction of routing maps into Sites
Attached
Detach File
Event Timeline
Log In to Comment