[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/aphront/configuration/ -> AphrontApplicationConfiguration.php (source)

   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  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1