-
Notifications
You must be signed in to change notification settings - Fork 31
Description
Issue
When calling a function like getProject() or getOwner() on a Subscription object, the call fails with the following error:
GuzzleHttp\Psr7\Exception\MalformedUriException: A relative URI must not have a path beginning with a segment containing a colon in /app/vendor/guzzlehttp/psr7/src/Uri.php:741
Stack trace:
#0 /app/vendor/guzzlehttp/psr7/src/Uri.php(498): GuzzleHttp\Psr7\Uri->validateState()
#1 /app/vendor/platformsh/client/src/Model/ApiResourceBase.php(580): GuzzleHttp\Psr7\Uri->withPath('https://us.plat...')
#2 /app/vendor/platformsh/client/src/Model/ApiResourceBase.php(442): Platformsh\Client\Model\ApiResourceBase->makeAbsoluteUrl('https://us.plat...')
#3 /app/vendor/platformsh/client/src/Model/Subscription.php(171): Platformsh\Client\Model\ApiResourceBase->getLink('project', false)
#4 /app/vendor/platformsh/client/src/Model/Subscription.php(142): Platformsh\Client\Model\Subscription->getLink('project')
#5 /app/public/index.php(41): Platformsh\Client\Model\Subscription->getProject()
Cause
The Subscription's project link is already a complete URL rather than relative URL, e.g.: https://us.platform.sh/api/projects/PROJECT_ID instead of /api/projects/PROJECT_ID
When the logic reaches the makeAbsoluteUrl() function of the client ApiResourceBase class, it tries to pass the project's absolute URL as a relative path for the $target value, resulting in something that looks like: $base->withPath("https://us.platform.sh/api/projects/PROJECT_ID")
As a result, Guzzle's URI validation rejects it as not a valid path.
$base object inspection:
GuzzleHttp\Psr7\Uri Object
(
[scheme:GuzzleHttp\Psr7\Uri:private] =>
[userInfo:GuzzleHttp\Psr7\Uri:private] =>
[host:GuzzleHttp\Psr7\Uri:private] =>
[port:GuzzleHttp\Psr7\Uri:private] =>
[path:GuzzleHttp\Psr7\Uri:private] => /organizations/ORG_ID/subscriptions
[query:GuzzleHttp\Psr7\Uri:private] =>
[fragment:GuzzleHttp\Psr7\Uri:private] =>
[composedComponents:GuzzleHttp\Psr7\Uri:private] =>
)
$target object inspection:
GuzzleHttp\Psr7\Uri Object
(
[scheme:GuzzleHttp\Psr7\Uri:private] => https
[userInfo:GuzzleHttp\Psr7\Uri:private] =>
[host:GuzzleHttp\Psr7\Uri:private] => us.platform.sh
[port:GuzzleHttp\Psr7\Uri:private] =>
[path:GuzzleHttp\Psr7\Uri:private] => /api/projects/PROJECT_ID
[query:GuzzleHttp\Psr7\Uri:private] =>
[fragment:GuzzleHttp\Psr7\Uri:private] =>
[composedComponents:GuzzleHttp\Psr7\Uri:private] =>
)
Possible fix
Based on the current logic, it seemed like the base URI would always be used (whether a full URL or just a path itself), with the target path providing the new path value.
With some light/specific testing, I have gotten this to behave:
protected function makeAbsoluteUrl(string $relativeUrl, string $baseUrl = null): string
{
$baseUrl = $baseUrl ?: $this->baseUrl;
if (empty($baseUrl)) {
throw new \RuntimeException('No base URL');
}
$base = Utils::uriFor($baseUrl);
$target = Utils::uriFor($relativeUrl);
$url = $base->withPath($target->getPath());
return (string) $url;
}Workaround
In the meantime, calling $client->getProject($projectId) instead of $subscription->getProject() works totally fine!
$projectId = $subscription->project_id;
$project = $client->getProject($projectId);