diff --git a/lib/HttpClient/HttpClient.php b/lib/HttpClient/HttpClient.php index f5ceb00..6a10022 100644 --- a/lib/HttpClient/HttpClient.php +++ b/lib/HttpClient/HttpClient.php @@ -14,6 +14,8 @@ use Psr\Http\Client\ClientInterface; class HttpClient implements RequestFactoryInterface, ClientInterface { public const ACCEPT_FEED = "application/atom+xml, application/rss+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, */*;q=0.1"; + public const ACCEPT_IMAGE = "image/*"; + public const ACCEPT_ICON = "image/svg+xml, image/png;q=0.9, image/*;q=0.1"; /** @var string $userAgent The User-Agent to identify as */ public $userAgent = ""; @@ -30,6 +32,12 @@ class HttpClient implements RequestFactoryInterface, ClientInterface { $this->requestFactory = $requestFactory; } + /** Sends an HTTP request and returns a response + * + * Redirects are followed up to the configured threshold. If credentials + * are supplied in the URL, these only apply to the original request; + * credentials are not sent to redirecr URLs, even for the same origin. + */ public function sendRequest(RequestInterface $request): ResponseInterface { $stop = $this->maxRedirects; for ($a = 0; $a <= $stop; $a++) { @@ -42,7 +50,7 @@ class HttpClient implements RequestFactoryInterface, ClientInterface { } else { $loc = $response->getHeader("Location"); for ($b = 0; $b < sizeof($loc); $b++) { - if ($url = Url::fromString($loc[$b], (string) $request->getUri())) { + if ($url = Url::fromString($loc[$b], (string) $request->getUri()->withUserInfo("", ""))) { $request = $request->withUri($url); if ($code === 303 && !in_array($request->getMethod(), ["GET", "HEAD"])) { $request = $request->withMethod("GET"); @@ -56,7 +64,40 @@ class HttpClient implements RequestFactoryInterface, ClientInterface { throw new Exception("tooManyRedirects"); } - public function createRequest(string $method, $uri): RequestInterface { - return $this->requestFactory->createRequest($method, $uri); + public function createRequest(string $method, $uri, array $headers = []): RequestInterface { + $req = $this->requestFactory->createRequest($method, $uri); + if (strlen($this->userAgent)) { + $req = $req->withHeader("User-Agent", $this->userAgent); + } + foreach ($headers as $k => $v) { + if (!is_array($v)) { + $v = [$v]; + } else { + $v = array_values($v); + } + foreach ($v as $kk => $vv) { + if ($vv instanceof \DateTimeImmutable) { + $vv = $vv->setTimezone(new \DateTimeZone("UTC"))->format(\DateTimeInterface::RFC7231); + } elseif ($vv instanceof \DateTime) { + $vv = clone $vv; + $vv->setTimezone(new \DateTimeZone("UTC")); + $v = $vv->format(\DateTimeInterface::RFC7231); + } + $m = $kk === 0 ? "withHeader" : "withAddedHeader"; + $req->$m($k, (string) $vv); + } + } + return $req; + } + + public function fetch($uri, string $accept = "*/*", string $etag = "", ?\DateTimeInterface $lastModified = null): ResponseInterface { + $headers = ['Accept' => $accept]; + if (strlen($etag)) { + $headers['ETag'] = $etag; + } + if ($lastModified) { + $headers['Last-Modified'] = $lastModified; + } + return $this->sendRequest($this->createRequest("GET", $uri, $headers)); } }