不明なContentTypeや406はOGPにフォールバックする

This commit is contained in:
unarist 2019-02-11 01:43:07 +09:00
parent 5750eeb3a5
commit 1ba4999a83
1 changed files with 59 additions and 22 deletions

View File

@ -2,6 +2,9 @@
namespace App\MetadataResolver;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
class MetadataResolver implements Resolver
{
public $rules = [
@ -23,9 +26,12 @@ class MetadataResolver implements Resolver
public $mimeTypes = [
'application/activity+json' => ActivityPubResolver::class,
'application/ld+json' => ActivityPubResolver::class,
'text/html' => OGPResolver::class
'text/html' => OGPResolver::class,
'*/*' => OGPResolver::class
];
public $defaultResolver = OGPResolver::class;
public function resolve(string $url): Metadata
{
foreach ($this->rules as $pattern => $class) {
@ -36,27 +42,58 @@ class MetadataResolver implements Resolver
}
}
$client = new \GuzzleHttp\Client();
$res = $client->request('GET', $url, [
'headers' => [
'Accept' => implode(', ', array_keys($this->mimeTypes))
]
]);
if ($res->getStatusCode() === 200) {
preg_match('/^[^;\s]+/', $res->getHeaderLine('Content-Type'), $matches);
$mimeType = $matches[0];
if (isset($this->mimeTypes[$mimeType])) {
$class = $this->mimeTypes[$mimeType];
$parser = new $class();
return $parser->parse($res->getBody());
} else {
throw new \UnexpectedValueException('URL not matched.');
}
} else {
throw new \RuntimeException("{$res->getStatusCode()}: $url");
$result = $this->resolveWithAcceptHeader($url);
if ($result !== null) {
return $result;
}
if (isset($this->defaultResolver)) {
$resolver = new $this->defaultResolver();
return $resolver->resolve($url);
}
throw new \UnexpectedValueException('URL not matched.');
}
public function resolveWithAcceptHeader(string $url): ?Metadata
{
try {
$client = new \GuzzleHttp\Client();
$res = $client->request('GET', $url, [
'headers' => [
'Accept' => implode(', ', array_keys($this->mimeTypes))
]
]);
if ($res->getStatusCode() === 200) {
preg_match('/^[^;\s]+/', $res->getHeaderLine('Content-Type'), $matches);
$mimeType = $matches[0];
if (isset($this->mimeTypes[$mimeType])) {
$class = $this->mimeTypes[$mimeType];
$parser = new $class();
return $parser->parse($res->getBody());
}
if (isset($this->mimeTypes['*/*'])) {
$class = $this->mimeTypes['*/*'];
$parser = new $class();
return $parser->parse($res->getBody());
}
} else {
// code < 400 && code !== 200 => fallback
}
} catch (ClientException $e) {
// 406 Not Acceptable は多分Acceptが原因なので無視してフォールバック
if ($e->getResponse()->getStatusCode() !== 406) {
throw $e;
}
} catch (ServerException $e) {
// 5xx は変なAcceptが原因かもしれないので無視してフォールバック
}
return null;
}
}