w:@CziO7h/?)FNLt=ڈ{c:&]Kd}nXU6psӛ+ Y[(uxhk.Qo)Ȉ:ԍLyE#z?fy0t $« @|gj\oekQ4;$qHD΄Pةg2s=7i9ۼ= Je@Q ճߌRqp|/3X ռ *Ϯ|kV#G!A/xRNzRYOucm= TڥYHR@4Hw/wgFN5K]O>Jk/ѤL 6 b )7VHNIf32iGY@"'V@9/Y&õ u,c#4ƒcK߬pVΥwgFN5K]Om6Kۀ+ iFSju  `8 K#=|xcзkDudJRY|^>>)`.FuUN !nb,tMvȠ|s819xy/ip:5vн.Cr8N ${k ֟3/@F(x[~fuhaL}jCl ܭ?7UȠVvuyAȌxEˆ/%7"DG89poA ]y qAĪ]6`ړ:3I+=ga n5(ݴBE %]JLa©w%^)lV &_\ ̼XmGCZʽu{ 26r_mcSh6 /0# Q2DdQ>e< ⭷Zc H"X/qִ:xz?QND)f,I)`Mc'7;':AVd` hyظaI5 ~|OXec3a@x\=t%zÈy@{e̿z|frG&LH'dc[,;-C֨o?^֓CmȹM4D2VB}b''-+r?JIӌ*)\+Tª:8H5<_FIS:JXzu'BJ@Hbp:PIĺ)kWAyMkr# 7R¹l`|wVs&8hqex2Tt%M:5mzbtϨ5@暃un%cm5\:һ2]_܄/Ʀ$ż(~/ _h5h4R\Mm YN1XjH1-)5axyU}(Գ#LYMO^>{fG)OGQ$ක0kI6/aB s V6Wp2@|+kJk|҆M[SV48vpԋF^jDQ7<1Q-|P¨7UPݒ7@n™1Nspr6 M.%Z`\‘NpNg ]]3[ɃmMiA(!(L!<_<#ħo"~>3['T(IADgnj "C`8=$jq˛ =8]4!i@{,_Ζm]>ޯ%1E~ovHf7rq\}ИH"5h'_`ekN,^(}{/njpqH\-jѫD]D=։!ٚ'(7nħo"~>3[ɃmMiA(!(L!<_<#ħo"~>3['T(IADgnj "C`8=$jq˛ =8]4!Y4%b×8!8KeV\`W3AЧ ^SMjjQ$`S3m!yt>ޯ%"NBu|j]Qf mTxLX2ZeQ ,^(}{/njpqH\-jC= Q#ǽʎ:3XEMR.r VQAZga#ǽʎ:E#.3^M0jL0`Wg9[`5c4Kf>t'[x-׎("YZ~V&eBwgFN5K]Oo"K„T@:O,x]9`cj7mqYY% (zL1b"@=x[гXH7 ͗\,fZ7ޯwgFN5K]O]e]u;o}nԘ8l;èFSR$domain)); } ); } } public function clearSessionCookies(): void { $this->cookies = \array_filter( $this->cookies, static function (SetCookie $cookie): bool { return !$cookie->getDiscard() && $cookie->getExpires(); } ); } public function setCookie(SetCookie $cookie): bool { // If the name string is empty (but not 0), ignore the set-cookie // string entirely. $name = $cookie->getName(); if (!$name && $name !== '0') { return false; } // Only allow cookies with set and valid domain, name, value $result = $cookie->validate(); if ($result !== true) { if ($this->strictMode) { throw new \RuntimeException('Invalid cookie: '.$result); } $this->removeCookieIfEmpty($cookie); return false; } // Resolve conflicts with previously set cookies foreach ($this->cookies as $i => $c) { // Two cookies are identical, when their path, and domain are // identical. if ($c->getPath() != $cookie->getPath() || $c->getDomain() != $cookie->getDomain() || $c->getName() != $cookie->getName() ) { continue; } // The previously set cookie is a discard cookie and this one is // not so allow the new cookie to be set if (!$cookie->getDiscard() && $c->getDiscard()) { unset($this->cookies[$i]); continue; } // If the new cookie's expiration is further into the future, then // replace the old cookie if ($cookie->getExpires() > $c->getExpires()) { unset($this->cookies[$i]); continue; } // If the value has changed, we better change it if ($cookie->getValue() !== $c->getValue()) { unset($this->cookies[$i]); continue; } // The cookie exists, so no need to continue return false; } $this->cookies[] = $cookie; return true; } public function count(): int { return \count($this->cookies); } /** * @return \ArrayIterator */ public function getIterator(): \ArrayIterator { return new \ArrayIterator(\array_values($this->cookies)); } public function extractCookies(RequestInterface $request, ResponseInterface $response): void { if ($cookieHeader = $response->getHeader('Set-Cookie')) { foreach ($cookieHeader as $cookie) { $sc = SetCookie::fromString($cookie); if (!$sc->getDomain()) { $sc->setDomain($request->getUri()->getHost()); } if (0 !== \strpos($sc->getPath(), '/')) { $sc->setPath($this->getCookiePathFromRequest($request)); } if (!$sc->matchesDomain($request->getUri()->getHost())) { continue; } // Note: At this point `$sc->getDomain()` being a public suffix should // be rejected, but we don't want to pull in the full PSL dependency. $this->setCookie($sc); } } } /** * Computes cookie path following RFC 6265 section 5.1.4 * * @see https://tools.ietf.org/html/rfc6265#section-5.1.4 */ private function getCookiePathFromRequest(RequestInterface $request): string { $uriPath = $request->getUri()->getPath(); if ('' === $uriPath) { return '/'; } if (0 !== \strpos($uriPath, '/')) { return '/'; } if ('/' === $uriPath) { return '/'; } $lastSlashPos = \strrpos($uriPath, '/'); if (0 === $lastSlashPos || false === $lastSlashPos) { return '/'; } return \substr($uriPath, 0, $lastSlashPos); } public function withCookieHeader(RequestInterface $request): RequestInterface { $values = []; $uri = $request->getUri(); $scheme = $uri->getScheme(); $host = $uri->getHost(); $path = $uri->getPath() ?: '/'; foreach ($this->cookies as $cookie) { if ($cookie->matchesPath($path) && $cookie->matchesDomain($host) && !$cookie->isExpired() && (!$cookie->getSecure() || $scheme === 'https') ) { $values[] = $cookie->getName().'=' .$cookie->getValue(); } } return $values ? $request->withHeader('Cookie', \implode('; ', $values)) : $request; } /** * If a cookie already exists and the server asks to set it again with a * null value, the cookie must be deleted. */ private function removeCookieIfEmpty(SetCookie $cookie): void { $cookieValue = $cookie->getValue(); if ($cookieValue === null || $cookieValue === '') { $this->clear( $cookie->getDomain(), $cookie->getPath(), $cookie->getName() ); } } }