diff --git a/psalm.xml b/psalm.xml index 600edad..a78abc8 100644 --- a/psalm.xml +++ b/psalm.xml @@ -15,6 +15,11 @@ + + + + + diff --git a/src/Clients/SiteHttpClient.php b/src/Clients/SiteHttpClient.php index 845acd0..bf9b0bc 100644 --- a/src/Clients/SiteHttpClient.php +++ b/src/Clients/SiteHttpClient.php @@ -68,7 +68,7 @@ public function withNoAuth(): SiteHttpClient /** * Run a callback payload from a long-runner response. */ - public function runCallbackPayload(string $callbackPayload): HttpResponse + public function runCallbackPayload(string $callbackPayload, array $options = []): HttpResponse { // Clear the default auth header. $response = $this->withNoAuth()->post( @@ -77,10 +77,13 @@ public function runCallbackPayload(string $callbackPayload): HttpResponse [ "content-type" => "application/system+jwt", ], - [ - "timeout" => 25, - "throw" => false, - ], + array_merge( + [ + "timeout" => 30, + "throw" => false, + ], + $options, + ), ); return $response; } diff --git a/src/Orch/OrchSite.php b/src/Orch/OrchSite.php index 2a67f00..c4fb752 100644 --- a/src/Orch/OrchSite.php +++ b/src/Orch/OrchSite.php @@ -6,7 +6,10 @@ namespace Garden\Sites\Orch; -use Garden\Http\HttpHandlerInterface; +use Garden\Http\HttpRequest; +use Garden\Http\HttpResponse; +use Garden\Sites\Clients\SiteHttpClient; +use Garden\Sites\Cluster; use Garden\Sites\Site; use Garden\Sites\SiteRecord; use Garden\Utils\ArrayUtils; @@ -28,6 +31,33 @@ public function __construct(SiteRecord $siteRecord, OrchSiteProvider $siteProvid parent::__construct($siteRecord, $siteProvider); } + /** + * Add additional default cookies to requests. + * + * @return SiteHttpClient + */ + public function httpClient(): SiteHttpClient + { + $httpClient = parent::httpClient(); + $realHostname = $this->getRealHostName(); + $clusterRouterHostname = $this->getClusterRouterHostname(); + if ($clusterRouterHostname) { + $kludgedBaseUrl = $this->replaceHostnameInUrl($this->getBaseUrl()); + $httpClient->setBaseUrl($kludgedBaseUrl); + $httpClient->setDefaultHeader("Host", $realHostname); + + $httpClient->addMiddleware(function (HttpRequest $request, callable $next) use ( + $realHostname + ): HttpResponse { + $request->setUrl($this->replaceHostnameInUrl($request->getUrl())); + $request->setHeader("Host", $realHostname); + return $next($request); + }); + } + + return $httpClient; + } + /** * @inheritDoc */ @@ -42,4 +72,52 @@ protected function loadSiteConfig(): array }); return $mergedConfig; } + + /** + * Given a url, try to replace it's base url so it routes with the cluster router. + * + * @param string $url + * @return string + */ + public function replaceHostnameInUrl(string $url): string + { + $clusterRouterHostname = $this->getClusterRouterHostname(); + if ($clusterRouterHostname === null) { + return $url; + } + + $realHostname = $this->getRealHostName(); + $kludgedUrl = str_replace($realHostname, $clusterRouterHostname, $url); + $kludgedUrl = str_replace("https", "http", $kludgedUrl); + return $kludgedUrl; + } + + /** + * @return string + */ + private function getRealHostName(): string + { + $baseUrl = $this->getBaseUrl(); + $realHostname = parse_url($baseUrl, PHP_URL_HOST); + return $realHostname; + } + + /** + * @return string|null + */ + public function getClusterRouterHostname(): ?string + { + switch ($this->getCluster()->getRegionID()) { + case Cluster::REGION_AMS1_PROD1: + return "haproxy-router.ams1-routing-prod1.vanilladev.com"; + case Cluster::REGION_SJC1_PROD1: + return "haproxy-router.sjc1-routing-prod1.vanilladev.com"; + case Cluster::REGION_YUL1_PROD1: + return "haproxy-router.yul1-routing-prod1.vanilladev.com"; + case Cluster::REGION_YUL1_DEV1: + return "haproxy-router.yul1-routing-dev1.vanilladev.com"; + } + + return null; + } } diff --git a/src/SiteRecord.php b/src/SiteRecord.php index 7726652..5f06074 100644 --- a/src/SiteRecord.php +++ b/src/SiteRecord.php @@ -7,6 +7,8 @@ namespace Garden\Sites; use Garden\Utils\ArrayUtils; +use Psr\Http\Message\UriInterface; +use Slim\Psr7\Factory\UriFactory; /** * Class holding a minimum of amount of data identifying a site. @@ -89,6 +91,15 @@ public function getBaseUrl(): string return $this->baseUrl; } + /** + * @return UriInterface + */ + public function getBaseUri(): UriInterface + { + $uriFactory = new UriFactory(); + return $uriFactory->createUri($this->getBaseUrl()); + } + /** * Set an extra meta value on the site record. * diff --git a/tests/OrchSitesTest.php b/tests/OrchSitesTest.php index 53e1c2b..864b6ab 100644 --- a/tests/OrchSitesTest.php +++ b/tests/OrchSitesTest.php @@ -130,6 +130,33 @@ public function expectedSites(): array ]; } + /** + * Overridden because we use the haproxies. + * @param ExpectedSite $expectedSite + * + * @return void + * @dataProvider provideExpectedSites + */ + public function testSiteClientBaseUrl(ExpectedSite $expectedSite) + { + $provider = $this->siteProvider(); + $provider->setRegionIDs([$expectedSite->expectedRegionID]); + $site = $provider->getSite($expectedSite->getSiteID()); + $siteClient = $site->httpClient(); + $siteClient->setThrowExceptions(false); + + $mockHandler = new MockHttpHandler(); + $siteClient->setHandler($mockHandler); + + // Base URL is added. + $response = $siteClient->get("/hello-world"); + $this->assertEquals( + $site->replaceHostnameInUrl("{$expectedSite->getBaseUrl()}/hello-world"), + $response->getRequest()->getUrl(), + ); + $this->assertEquals($expectedSite->getBaseUri()->getHost(), $response->getRequest()->getHeader("host")); + } + /** * @inheritDoc */