[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @task routing URI Routing 5 */ 6 abstract class AphrontApplicationConfiguration { 7 8 private $request; 9 private $host; 10 private $path; 11 private $console; 12 13 abstract public function getApplicationName(); 14 abstract public function buildRequest(); 15 abstract public function build404Controller(); 16 abstract public function buildRedirectController($uri, $external); 17 18 final public function setRequest(AphrontRequest $request) { 19 $this->request = $request; 20 return $this; 21 } 22 23 final public function getRequest() { 24 return $this->request; 25 } 26 27 final public function getConsole() { 28 return $this->console; 29 } 30 31 final public function setConsole($console) { 32 $this->console = $console; 33 return $this; 34 } 35 36 final public function setHost($host) { 37 $this->host = $host; 38 return $this; 39 } 40 41 final public function getHost() { 42 return $this->host; 43 } 44 45 final public function setPath($path) { 46 $this->path = $path; 47 return $this; 48 } 49 50 final public function getPath() { 51 return $this->path; 52 } 53 54 public function willBuildRequest() {} 55 56 57 /* -( URI Routing )-------------------------------------------------------- */ 58 59 60 /** 61 * Using builtin and application routes, build the appropriate 62 * @{class:AphrontController} class for the request. To route a request, we 63 * first test if the HTTP_HOST is configured as a valid Phabricator URI. If 64 * it isn't, we do a special check to see if it's a custom domain for a blog 65 * in the Phame application and if that fails we error. Otherwise, we test 66 * against all application routes from installed 67 * @{class:PhabricatorApplication}s. 68 * 69 * If we match a route, we construct the controller it points at, build it, 70 * and return it. 71 * 72 * If we fail to match a route, but the current path is missing a trailing 73 * "/", we try routing the same path with a trailing "/" and do a redirect 74 * if that has a valid route. The idea is to canoncalize URIs for consistency, 75 * but avoid breaking noncanonical URIs that we can easily salvage. 76 * 77 * NOTE: We only redirect on GET. On POST, we'd drop parameters and most 78 * likely mutate the request implicitly, and a bad POST usually indicates a 79 * programming error rather than a sloppy typist. 80 * 81 * If the failing path already has a trailing "/", or we can't route the 82 * version with a "/", we call @{method:build404Controller}, which build a 83 * fallback @{class:AphrontController}. 84 * 85 * @return pair<AphrontController,dict> Controller and dictionary of request 86 * parameters. 87 * @task routing 88 */ 89 final public function buildController() { 90 $request = $this->getRequest(); 91 92 if (PhabricatorEnv::getEnvConfig('security.require-https')) { 93 if (!$request->isHTTPS()) { 94 $https_uri = $request->getRequestURI(); 95 $https_uri->setDomain($request->getHost()); 96 $https_uri->setProtocol('https'); 97 98 // In this scenario, we'll be redirecting to HTTPS using an absolute 99 // URI, so we need to permit an external redirect. 100 return $this->buildRedirectController($https_uri, true); 101 } 102 } 103 104 $path = $request->getPath(); 105 $host = $request->getHost(); 106 $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); 107 $prod_uri = PhabricatorEnv::getEnvConfig('phabricator.production-uri'); 108 $file_uri = PhabricatorEnv::getEnvConfig( 109 'security.alternate-file-domain'); 110 $conduit_uris = PhabricatorEnv::getEnvConfig('conduit.servers'); 111 $allowed_uris = PhabricatorEnv::getEnvConfig('phabricator.allowed-uris'); 112 113 $uris = array_merge( 114 array( 115 $base_uri, 116 $prod_uri, 117 ), 118 $conduit_uris, 119 $allowed_uris); 120 121 $cdn_routes = array( 122 '/res/', 123 '/file/data/', 124 '/file/xform/', 125 '/phame/r/', 126 ); 127 128 $host_match = false; 129 foreach ($uris as $uri) { 130 if ($host === id(new PhutilURI($uri))->getDomain()) { 131 $host_match = true; 132 break; 133 } 134 } 135 136 if (!$host_match) { 137 if ($host === id(new PhutilURI($file_uri))->getDomain()) { 138 foreach ($cdn_routes as $route) { 139 if (strncmp($path, $route, strlen($route)) == 0) { 140 $host_match = true; 141 break; 142 } 143 } 144 } 145 } 146 147 // NOTE: If the base URI isn't defined yet, don't activate alternate 148 // domains. 149 if ($base_uri && !$host_match) { 150 151 try { 152 $blog = id(new PhameBlogQuery()) 153 ->setViewer(new PhabricatorUser()) 154 ->withDomain($host) 155 ->executeOne(); 156 } catch (PhabricatorPolicyException $ex) { 157 throw new Exception( 158 'This blog is not visible to logged out users, so it can not be '. 159 'visited from a custom domain.'); 160 } 161 162 if (!$blog) { 163 if ($prod_uri && $prod_uri != $base_uri) { 164 $prod_str = ' or '.$prod_uri; 165 } else { 166 $prod_str = ''; 167 } 168 throw new Exception( 169 'Specified domain '.$host.' is not configured for Phabricator '. 170 'requests. Please use '.$base_uri.$prod_str.' to visit this instance.' 171 ); 172 } 173 174 // TODO: Make this more flexible and modular so any application can 175 // do crazy stuff here if it wants. 176 177 $path = '/phame/live/'.$blog->getID().'/'.$path; 178 } 179 180 list($controller, $uri_data) = $this->buildControllerForPath($path); 181 if (!$controller) { 182 if (!preg_match('@/$@', $path)) { 183 // If we failed to match anything but don't have a trailing slash, try 184 // to add a trailing slash and issue a redirect if that resolves. 185 list($controller, $uri_data) = $this->buildControllerForPath($path.'/'); 186 187 // NOTE: For POST, just 404 instead of redirecting, since the redirect 188 // will be a GET without parameters. 189 190 if ($controller && !$request->isHTTPPost()) { 191 $slash_uri = $request->getRequestURI()->setPath($path.'/'); 192 193 $external = strlen($request->getRequestURI()->getDomain()); 194 return $this->buildRedirectController($slash_uri, $external); 195 } 196 } 197 return $this->build404Controller(); 198 } 199 200 return array($controller, $uri_data); 201 } 202 203 204 /** 205 * Map a specific path to the corresponding controller. For a description 206 * of routing, see @{method:buildController}. 207 * 208 * @return pair<AphrontController,dict> Controller and dictionary of request 209 * parameters. 210 * @task routing 211 */ 212 final public function buildControllerForPath($path) { 213 $maps = array(); 214 215 $applications = PhabricatorApplication::getAllInstalledApplications(); 216 foreach ($applications as $application) { 217 $maps[] = array($application, $application->getRoutes()); 218 } 219 220 $current_application = null; 221 $controller_class = null; 222 foreach ($maps as $map_info) { 223 list($application, $map) = $map_info; 224 225 $mapper = new AphrontURIMapper($map); 226 list($controller_class, $uri_data) = $mapper->mapPath($path); 227 228 if ($controller_class) { 229 if ($application) { 230 $current_application = $application; 231 } 232 break; 233 } 234 } 235 236 if (!$controller_class) { 237 return array(null, null); 238 } 239 240 $request = $this->getRequest(); 241 242 $controller = newv($controller_class, array()); 243 if ($current_application) { 244 $controller->setCurrentApplication($current_application); 245 } 246 247 return array($controller, $uri_data); 248 } 249 250 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |