1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-20 20:40:56 +01:00

When an install is instanced, include the instance identifier in the URI for file data

Summary:
This allows us to CDN the cluster.

General problem is that we can't easily give each instance its own CDN URI (`giraffe.phcdn.net`) in Cloudfront, because it requires that you enumerate all aliases (and there's a limit of 100) and depends on SNI (a newish feature of SSL which allows one server to serve multiple certificates, but which doesn't have full support everywhere yet).

It's //possible// that we could eventually work around this, or use Cloudflare instead (which has a different model that seems like a slightly easier fit for CDN-domain-per-instance), but I don't want to sink a ton of work into this and want to keep things on AWS insofar as we reasonably can.

The easiest way to fix this is just to put the instance identity into URIs, then read it out when handling CDN requests. This has no effect on installs without cluster instance configuration, which is all of them except ours.

It's also slightly desirable to share this stuff, since we get to share the cache for static resources, which are always identical across instances.

So requests go from the Cloudfront gateway ("xyz.cloudfront.com") to the LB with a hard-coded instance name ("cdn.phacility.com"), which gets them routed to a balanced web machine. The web machine picks the correct instance name out of the URI, acts as that instance, and does the correct thing.

The messiest part of this is that we need "cdn.phacility.com" to be a real instance so it can serve static resources, but that's not a big deal. We have a few other hard-codes which have to be real resources for now, like we must have a merchant named "Phacility".

Test Plan:
  - Viewed files with `security.alternate-file-domain` off (i.e., no file tokens).
  - Viewed pages and files with `security.alternate-file-domain` on. Saw correct resource behavior, @isntance generation of URIs, and correct token redirect behavior for files.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Differential Revision: https://secure.phabricator.com/D11668
This commit is contained in:
epriestley 2015-02-03 14:55:46 -08:00
parent da1531f219
commit e6fb1dc1e9
2 changed files with 47 additions and 24 deletions

View file

@ -76,9 +76,12 @@ final class PhabricatorFilesApplication extends PhabricatorApplication {
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController', 'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorFileEditController', 'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorFileEditController',
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController', 'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
'data/(?P<key>[^/]+)/(?P<phid>[^/]+)/(?P<token>[^/]+)/.*' 'data/'.
=> 'PhabricatorFileDataController', '(?:@(?P<instance>[^/]+)/)?'.
'data/(?P<key>[^/]+)/(?P<phid>[^/]+)/.*' '(?P<key>[^/]+)/'.
'(?P<phid>[^/]+)/'.
'(?:(?P<token>[^/]+)/)?'.
'.*'
=> 'PhabricatorFileDataController', => 'PhabricatorFileDataController',
'proxy/' => 'PhabricatorFileProxyController', 'proxy/' => 'PhabricatorFileProxyController',
'xform/(?P<transform>[^/]+)/(?P<phid>[^/]+)/(?P<key>[^/]+)/' 'xform/(?P<transform>[^/]+)/(?P<phid>[^/]+)/(?P<key>[^/]+)/'

View file

@ -556,12 +556,52 @@ final class PhabricatorFile extends PhabricatorFileDAO
'You must save a file before you can generate a view URI.'); 'You must save a file before you can generate a view URI.');
} }
return $this->getCDNURI(null);
}
private function getCDNURI($token) {
$name = phutil_escape_uri($this->getName()); $name = phutil_escape_uri($this->getName());
$path = '/file/data/'.$this->getSecretKey().'/'.$this->getPHID().'/'.$name; $parts = array();
$parts[] = 'file';
$parts[] = 'data';
// If this is an instanced install, add the instance identifier to the URI.
// Instanced configurations behind a CDN may not be able to control the
// request domain used by the CDN (as with AWS CloudFront). Embedding the
// instance identity in the path allows us to distinguish between requests
// originating from different instances but served through the same CDN.
$instance = PhabricatorEnv::getEnvConfig('cluster.instance');
if (strlen($instance)) {
$parts[] = '@'.$instance;
}
$parts[] = $this->getSecretKey();
$parts[] = $this->getPHID();
if ($token) {
$parts[] = $token;
}
$parts[] = $name;
$path = implode('/', $parts);
return PhabricatorEnv::getCDNURI($path); return PhabricatorEnv::getCDNURI($path);
} }
/**
* Get the CDN URI for this file, including a one-time-use security token.
*
*/
public function getCDNURIWithToken() {
if (!$this->getPHID()) {
throw new Exception(
'You must save a file before you can generate a CDN URI.');
}
return $this->getCDNURI($this->generateOneTimeToken());
}
public function getInfoURI() { public function getInfoURI() {
return '/'.$this->getMonogram(); return '/'.$this->getMonogram();
} }
@ -963,26 +1003,6 @@ final class PhabricatorFile extends PhabricatorFileDAO
return $token; return $token;
} }
/** Get the CDN uri for this file
* This will generate a one-time-use token if
* security.alternate_file_domain is set in the config.
*/
public function getCDNURIWithToken() {
if (!$this->getPHID()) {
throw new Exception(
'You must save a file before you can generate a CDN URI.');
}
$name = phutil_escape_uri($this->getName());
$path = '/file/data'
.'/'.$this->getSecretKey()
.'/'.$this->getPHID()
.'/'.$this->generateOneTimeToken()
.'/'.$name;
return PhabricatorEnv::getCDNURI($path);
}
/** /**
* Write the policy edge between this file and some object. * Write the policy edge between this file and some object.