diff -Nru php-guzzlehttp-psr7-2.7.1/debian/changelog php-guzzlehttp-psr7-2.7.1/debian/changelog
--- php-guzzlehttp-psr7-2.7.1/debian/changelog	2025-03-31 12:19:42.000000000 +0200
+++ php-guzzlehttp-psr7-2.7.1/debian/changelog	2026-05-30 13:39:01.000000000 +0200
@@ -1,3 +1,16 @@
+php-guzzlehttp-psr7 (2.7.1-1+deb13u1) trixie; urgency=medium
+
+  * Backport fixes from upstream
+    - Encode plus sign in withQueryValue() and withQueryValues() (#636)
+    - Harden ServerRequest globals handling (#660)
+    - Normalize global header values (#718)
+    - Reject control characters in URI hosts (#715) [CVE-2026-49214]
+    - Reject malformed Host authorities (#717) [CVE-2026-48998]
+    (Closes: #1138265)
+  * Track debian/trixie branch
+
+ -- David Prévot <taffit@debian.org>  Sat, 30 May 2026 13:39:01 +0200
+
 php-guzzlehttp-psr7 (2.7.1-1) unstable; urgency=medium
 
   [ Graham Campbell ]
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/control php-guzzlehttp-psr7-2.7.1/debian/control
--- php-guzzlehttp-psr7-2.7.1/debian/control	2025-03-31 12:19:42.000000000 +0200
+++ php-guzzlehttp-psr7-2.7.1/debian/control	2026-05-30 13:39:01.000000000 +0200
@@ -15,7 +15,7 @@
                psmisc
 Standards-Version: 4.7.2
 Homepage: https://github.com/guzzle/psr7
-Vcs-Git: https://salsa.debian.org/php-team/pear/php-guzzlehttp-psr7.git
+Vcs-Git: https://salsa.debian.org/php-team/pear/php-guzzlehttp-psr7.git -b debian/trixie
 Vcs-Browser: https://salsa.debian.org/php-team/pear/php-guzzlehttp-psr7
 Rules-Requires-Root: no
 
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/gbp.conf php-guzzlehttp-psr7-2.7.1/debian/gbp.conf
--- php-guzzlehttp-psr7-2.7.1/debian/gbp.conf	2024-07-21 02:49:36.000000000 +0200
+++ php-guzzlehttp-psr7-2.7.1/debian/gbp.conf	2026-05-30 13:39:01.000000000 +0200
@@ -1,5 +1,5 @@
 [DEFAULT]
-debian-branch = debian/latest
+debian-branch = debian/trixie
 filter = [ '.gitattributes' ]
 pristine-tar = True
 upstream-vcs-tag = %(version%~%-)s
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/patches/0004-2.8-Encode-plus-sign-in-withQueryValue-and-withQuery.patch php-guzzlehttp-psr7-2.7.1/debian/patches/0004-2.8-Encode-plus-sign-in-withQueryValue-and-withQuery.patch
--- php-guzzlehttp-psr7-2.7.1/debian/patches/0004-2.8-Encode-plus-sign-in-withQueryValue-and-withQuery.patch	1970-01-01 01:00:00.000000000 +0100
+++ php-guzzlehttp-psr7-2.7.1/debian/patches/0004-2.8-Encode-plus-sign-in-withQueryValue-and-withQuery.patch	2026-05-30 13:39:01.000000000 +0200
@@ -0,0 +1,61 @@
+From: =?utf-8?q?Ey=C3=BCp_Can_Akman?= <eyupcanakman@gmail.com>
+Date: Tue, 10 Mar 2026 12:53:17 +0300
+Subject: [2.8] Encode plus sign in withQueryValue() and withQueryValues()
+ (#636)
+
+* Encode plus sign in withQueryValue() and withQueryValues()
+
+* Add plus sign note to Uri query comment
+
+Origin: upstrem, https://github.com/guzzle/psr7/commit/bf5b5784ad30e4d01d7723366977ae54dc1d06ff
+Bug: https://github.com/guzzle/psr7/pull/636
+---
+ src/Uri.php       |  5 +++--
+ tests/UriTest.php | 11 +++++++++++
+ 2 files changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/src/Uri.php b/src/Uri.php
+index a7cdfb0..bef82e2 100644
+--- a/src/Uri.php
++++ b/src/Uri.php
+@@ -51,7 +51,7 @@ class Uri implements UriInterface, \JsonSerializable
+      * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
+      */
+     private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';
+-    private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26'];
++    private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26', '+' => '%2B'];
+ 
+     /** @var string Uri scheme. */
+     private $scheme = '';
+@@ -661,7 +661,8 @@ class Uri implements UriInterface, \JsonSerializable
+ 
+     private static function generateQueryString(string $key, ?string $value): string
+     {
+-        // Query string separators ("=", "&") within the key or value need to be encoded
++        // Query string separators ("=", "&") and literal plus signs ("+") within the
++        // key or value need to be encoded
+         // (while preventing double-encoding) before setting the query string. All other
+         // chars that need percent-encoding will be encoded by withQuery().
+         $queryString = strtr($key, self::QUERY_SEPARATORS_REPLACEMENT);
+diff --git a/tests/UriTest.php b/tests/UriTest.php
+index 185b7f1..3fb0716 100644
+--- a/tests/UriTest.php
++++ b/tests/UriTest.php
+@@ -390,6 +390,17 @@ class UriTest extends TestCase
+         self::assertSame('E%3Dmc%5e2=ein%26stein', $uri->getQuery(), 'Encoded key/value do not get double-encoded');
+     }
+ 
++    public function testWithQueryValueEncodesPlusSign(): void
++    {
++        $uri = new Uri();
++        $uri = Uri::withQueryValue($uri, 'a+b', 'c+d');
++        self::assertSame('a%2Bb=c%2Bd', $uri->getQuery(), 'Plus signs in key and value get encoded to %2B');
++
++        $uri = new Uri();
++        $uri = Uri::withQueryValue($uri, 'query', 'a+b c');
++        self::assertSame('query=a%2Bb%20c', $uri->getQuery(), 'Plus sign is encoded distinctly from space');
++    }
++
+     public function testWithoutQueryValueHandlesEncoding(): void
+     {
+         // It also tests that the case of the percent-encoding does not matter,
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/patches/0004-Modernize-PHPUnit-syntax.patch php-guzzlehttp-psr7-2.7.1/debian/patches/0004-Modernize-PHPUnit-syntax.patch
--- php-guzzlehttp-psr7-2.7.1/debian/patches/0004-Modernize-PHPUnit-syntax.patch	2025-03-31 12:18:24.000000000 +0200
+++ php-guzzlehttp-psr7-2.7.1/debian/patches/0004-Modernize-PHPUnit-syntax.patch	2026-05-30 13:39:01.000000000 +0200
@@ -6,20 +6,21 @@
  tests/AppendStreamTest.php         |  5 ++---
  tests/FnStreamTest.php             |  5 ++---
  tests/HeaderTest.php               | 13 ++++---------
+ tests/MessageTest.php              |  9 +++------
  tests/PumpStreamTest.php           |  5 ++---
  tests/QueryTest.php                |  9 +++------
  tests/RequestTest.php              | 21 ++++++---------------
  tests/ResponseTest.php             | 21 +++++++--------------
- tests/ServerRequestTest.php        |  9 +++------
+ tests/ServerRequestTest.php        | 13 ++++---------
  tests/StreamDecoratorTraitTest.php |  5 ++---
  tests/StreamTest.php               | 12 ++++--------
  tests/UploadedFileTest.php         | 21 ++++++---------------
  tests/UriComparatorTest.php        |  5 ++---
  tests/UriNormalizerTest.php        | 13 ++++---------
  tests/UriResolverTest.php          | 13 ++++---------
- tests/UriTest.php                  | 21 ++++++---------------
+ tests/UriTest.php                  | 25 +++++++------------------
  tests/UtilsTest.php                |  9 ++++-----
- 16 files changed, 61 insertions(+), 126 deletions(-)
+ 17 files changed, 66 insertions(+), 138 deletions(-)
 
 diff --git a/tests/AppendStreamTest.php b/tests/AppendStreamTest.php
 index 302470a..b0c6a2e 100644
@@ -111,6 +112,40 @@
      public function testSplitList($header, $result): void
      {
          self::assertSame($result, Psr7\Header::splitList($header));
+diff --git a/tests/MessageTest.php b/tests/MessageTest.php
+index 42909be..4df397a 100644
+--- a/tests/MessageTest.php
++++ b/tests/MessageTest.php
+@@ -6,6 +6,7 @@ namespace GuzzleHttp\Tests\Psr7;
+ 
+ use GuzzleHttp\Psr7;
+ use GuzzleHttp\Psr7\FnStream;
++use PHPUnit\Framework\Attributes\DataProvider;
+ use PHPUnit\Framework\TestCase;
+ 
+ class MessageTest extends TestCase
+@@ -107,9 +108,7 @@ class MessageTest extends TestCase
+         self::assertSame('http://foo.com/', (string) $request->getUri());
+     }
+ 
+-    /**
+-     * @dataProvider invalidHostHeaderProvider
+-     */
++    #[DataProvider('invalidHostHeaderProvider')]
+     public function testParseRequestRejectsInvalidHostHeader(string $host): void
+     {
+         $this->expectException(\InvalidArgumentException::class);
+@@ -136,9 +135,7 @@ class MessageTest extends TestCase
+         yield 'unexpected closing bracket' => ['foo]bar'];
+     }
+ 
+-    /**
+-     * @dataProvider validHostHeaderProvider
+-     */
++    #[DataProvider('validHostHeaderProvider')]
+     public function testParseRequestAcceptsValidHostHeader(string $host, string $expectedUri): void
+     {
+         $request = Psr7\Message::parseRequest("GET / HTTP/1.1\r\nHost: {$host}\r\n\r\n");
 diff --git a/tests/PumpStreamTest.php b/tests/PumpStreamTest.php
 index a4f3f2c..52ded59 100644
 --- a/tests/PumpStreamTest.php
@@ -169,7 +204,7 @@
      {
          $result = Psr7\Query::parse($input, false);
 diff --git a/tests/RequestTest.php b/tests/RequestTest.php
-index 19d71c3..92c9733 100644
+index 3a62c57..0ea5069 100644
 --- a/tests/RequestTest.php
 +++ b/tests/RequestTest.php
 @@ -7,6 +7,7 @@ namespace GuzzleHttp\Tests\Psr7;
@@ -179,8 +214,8 @@
 +use PHPUnit\Framework\Attributes\DataProvider;
  use PHPUnit\Framework\TestCase;
  use Psr\Http\Message\StreamInterface;
- 
-@@ -95,18 +96,14 @@ class RequestTest extends TestCase
+ use Psr\Http\Message\UriInterface;
+@@ -96,18 +97,14 @@ class RequestTest extends TestCase
          self::assertSame($u1, $r1->getUri());
      }
  
@@ -201,7 +236,7 @@
      public function testWithInvalidMethods($method): void
      {
          $r = new Request('get', '/');
-@@ -197,9 +194,7 @@ class RequestTest extends TestCase
+@@ -198,9 +195,7 @@ class RequestTest extends TestCase
          self::assertSame('', $r->getHeaderLine('Bar'));
      }
  
@@ -212,7 +247,7 @@
      public function testContainsNotAllowedCharsOnHeaderField($header): void
      {
          $this->expectExceptionMessage(
-@@ -222,9 +217,7 @@ class RequestTest extends TestCase
+@@ -223,9 +218,7 @@ class RequestTest extends TestCase
          return [[' key '], ['key '], [' key'], ['key/'], ['key('], ['key\\'], [' ']];
      }
  
@@ -223,8 +258,8 @@
      public function testContainsAllowedCharsOnHeaderField($header): void
      {
          $r = new Request(
-@@ -306,9 +299,7 @@ class RequestTest extends TestCase
-         self::assertSame('foo.com:8125', $r->getHeaderLine('host'));
+@@ -329,9 +322,7 @@ class RequestTest extends TestCase
+         self::assertSame('example.com:8080', $request->getHeaderLine('Host'));
      }
  
 -    /**
@@ -317,7 +352,7 @@
      {
          $response = new Response();
 diff --git a/tests/ServerRequestTest.php b/tests/ServerRequestTest.php
-index f770078..50d173b 100644
+index 914f949..b81b663 100644
 --- a/tests/ServerRequestTest.php
 +++ b/tests/ServerRequestTest.php
 @@ -7,6 +7,7 @@ namespace GuzzleHttp\Tests\Psr7;
@@ -339,7 +374,7 @@
      public function testNormalizeFiles($files, $expected): void
      {
          $result = ServerRequest::normalizeFiles($files);
-@@ -369,9 +368,7 @@ class ServerRequestTest extends TestCase
+@@ -433,9 +432,7 @@ class ServerRequestTest extends TestCase
          ];
      }
  
@@ -350,6 +385,17 @@
      public function testGetUriFromGlobals($expected, $serverParams): void
      {
          $_SERVER = $serverParams;
+@@ -576,9 +573,7 @@ class ServerRequestTest extends TestCase
+         self::assertSame('1.1', $server->getProtocolVersion());
+     }
+ 
+-    /**
+-     * @dataProvider invalidHostHeaderFromGlobalsProvider
+-     */
++    #[DataProvider('invalidHostHeaderFromGlobalsProvider')]
+     public function testFromGlobalsDropsInvalidHostHeaderWhenUriFallsBack(string $host): void
+     {
+         if (!\function_exists('getallheaders')) {
 diff --git a/tests/StreamDecoratorTraitTest.php b/tests/StreamDecoratorTraitTest.php
 index aaa9f28..11e699c 100644
 --- a/tests/StreamDecoratorTraitTest.php
@@ -598,7 +644,7 @@
      {
          $baseUri = new Uri($base);
 diff --git a/tests/UriTest.php b/tests/UriTest.php
-index 185b7f1..b0b39a4 100644
+index da229a7..01d7df5 100644
 --- a/tests/UriTest.php
 +++ b/tests/UriTest.php
 @@ -6,6 +6,7 @@ namespace GuzzleHttp\Tests\Psr7;
@@ -642,7 +688,18 @@
      public function testInvalidUrisThrowException(string $invalidUri): void
      {
          $this->expectException(MalformedUriException::class);
-@@ -205,9 +200,7 @@ class UriTest extends TestCase
+@@ -153,9 +148,7 @@ class UriTest extends TestCase
+         (new Uri())->withHost([]);
+     }
+ 
+-    /**
+-     * @dataProvider getInvalidHostsWithControlCharacters
+-     */
++    #[DataProvider('getInvalidHostsWithControlCharacters')]
+     public function testHostMustRejectControlCharacters(string $host): void
+     {
+         $this->expectException(\InvalidArgumentException::class);
+@@ -231,9 +224,7 @@ class UriTest extends TestCase
          self::assertSame('0://0:0@0/0?0#0', (string) $uri);
      }
  
@@ -653,7 +710,7 @@
      public function testIsDefaultPort(string $scheme, ?int $port, bool $isDefaultPort): void
      {
          $uri = $this->createMock(UriInterface::class);
-@@ -553,9 +546,7 @@ class UriTest extends TestCase
+@@ -590,9 +581,7 @@ class UriTest extends TestCase
          ];
      }
  
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/patches/0005-Harden-ServerRequest-globals-handling-660.patch php-guzzlehttp-psr7-2.7.1/debian/patches/0005-Harden-ServerRequest-globals-handling-660.patch
--- php-guzzlehttp-psr7-2.7.1/debian/patches/0005-Harden-ServerRequest-globals-handling-660.patch	1970-01-01 01:00:00.000000000 +0100
+++ php-guzzlehttp-psr7-2.7.1/debian/patches/0005-Harden-ServerRequest-globals-handling-660.patch	2026-05-30 13:39:01.000000000 +0200
@@ -0,0 +1,181 @@
+From: Graham Campbell <GrahamCampbell@users.noreply.github.com>
+Date: Tue, 19 May 2026 18:20:12 +0100
+Subject: Harden ServerRequest globals handling (#660)
+
+* Harden server request globals
+
+* Document ServerRequest globals hardening
+
+* Move ServerRequest changelog entry
+
+* Reorder ServerRequest changelog entry
+
+Origin: backport, https://github.com/guzzle/psr7/commit/ed659d5c2254b9d2af3a1b77257b91a4899e313c
+Bug: https://github.com/guzzle/psr7/pull/660
+---
+ src/ServerRequest.php       | 46 +++++++++++++++++++++++++++++----------------
+ tests/ServerRequestTest.php | 41 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 71 insertions(+), 16 deletions(-)
+
+diff --git a/src/ServerRequest.php b/src/ServerRequest.php
+index 3cc9534..bc795fc 100644
+--- a/src/ServerRequest.php
++++ b/src/ServerRequest.php
+@@ -165,11 +165,12 @@ class ServerRequest extends Request implements ServerRequestInterface
+      */
+     public static function fromGlobals(): ServerRequestInterface
+     {
+-        $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
++        $method = self::getServerParam('REQUEST_METHOD') ?? 'GET';
+         $headers = getallheaders();
+         $uri = self::getUriFromGlobals();
+         $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
+-        $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
++        $serverProtocol = self::getServerParam('SERVER_PROTOCOL');
++        $protocol = $serverProtocol !== null ? str_replace('HTTP/', '', $serverProtocol) : '1.1';
+ 
+         $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
+ 
+@@ -180,11 +181,19 @@ class ServerRequest extends Request implements ServerRequestInterface
+             ->withUploadedFiles(self::normalizeFiles($_FILES));
+     }
+ 
++    private static function getServerParam(string $key): ?string
++    {
++        return isset($_SERVER[$key]) && is_string($_SERVER[$key]) ? $_SERVER[$key] : null;
++    }
++
++    /**
++     * @return array{0: string|null, 1: int|null}
++     */
+     private static function extractHostAndPortFromAuthority(string $authority): array
+     {
+         $uri = 'http://'.$authority;
+         $parts = parse_url($uri);
+-        if (false === $parts) {
++        if (!is_array($parts)) {
+             return [null, null];
+         }
+ 
+@@ -201,11 +210,13 @@ class ServerRequest extends Request implements ServerRequestInterface
+     {
+         $uri = new Uri('');
+ 
+-        $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
++        $https = self::getServerParam('HTTPS');
++        $uri = $uri->withScheme(!empty($https) && $https !== 'off' ? 'https' : 'http');
+ 
+         $hasPort = false;
+-        if (isset($_SERVER['HTTP_HOST'])) {
+-            [$host, $port] = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
++        $authority = self::getServerParam('HTTP_HOST');
++        if ($authority !== null) {
++            [$host, $port] = self::extractHostAndPortFromAuthority($authority);
+             if ($host !== null) {
+                 $uri = $uri->withHost($host);
+             }
+@@ -214,19 +225,21 @@ class ServerRequest extends Request implements ServerRequestInterface
+                 $hasPort = true;
+                 $uri = $uri->withPort($port);
+             }
+-        } elseif (isset($_SERVER['SERVER_NAME'])) {
+-            $uri = $uri->withHost($_SERVER['SERVER_NAME']);
+-        } elseif (isset($_SERVER['SERVER_ADDR'])) {
+-            $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
++        } elseif (($serverName = self::getServerParam('SERVER_NAME')) !== null) {
++            $uri = $uri->withHost($serverName);
++        } elseif (($serverAddr = self::getServerParam('SERVER_ADDR')) !== null) {
++            $uri = $uri->withHost($serverAddr);
+         }
+ 
+-        if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
+-            $uri = $uri->withPort($_SERVER['SERVER_PORT']);
++        $serverPort = self::getServerParam('SERVER_PORT');
++        if (!$hasPort && $serverPort !== null && preg_match('/^[+-]?\d+$/', $serverPort) === 1) {
++            $uri = $uri->withPort((int) $serverPort);
+         }
+ 
+         $hasQuery = false;
+-        if (isset($_SERVER['REQUEST_URI'])) {
+-            $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
++        $requestUri = self::getServerParam('REQUEST_URI');
++        if ($requestUri !== null) {
++            $requestUriParts = explode('?', $requestUri, 2);
+             $uri = $uri->withPath($requestUriParts[0]);
+             if (isset($requestUriParts[1])) {
+                 $hasQuery = true;
+@@ -234,8 +247,9 @@ class ServerRequest extends Request implements ServerRequestInterface
+             }
+         }
+ 
+-        if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
+-            $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
++        $queryString = self::getServerParam('QUERY_STRING');
++        if (!$hasQuery && $queryString !== null) {
++            $uri = $uri->withQuery($queryString);
+         }
+ 
+         return $uri;
+diff --git a/tests/ServerRequestTest.php b/tests/ServerRequestTest.php
+index f770078..dbd2288 100644
+--- a/tests/ServerRequestTest.php
++++ b/tests/ServerRequestTest.php
+@@ -358,10 +358,34 @@ class ServerRequestTest extends TestCase
+                 'https://www.example.org:8324/blog/article.php?id=10&user=foo',
+                 array_merge($server, ['SERVER_PORT' => '8324']),
+             ],
++            'Invalid SERVER_PORT is ignored instead of coerced to zero' => [
++                'https://www.example.org/blog/article.php?id=10&user=foo',
++                array_merge($server, ['SERVER_PORT' => 'not-a-port']),
++            ],
++            'Non-string SERVER_PORT is ignored' => [
++                'https://www.example.org/blog/article.php?id=10&user=foo',
++                array_merge($server, ['SERVER_PORT' => ['443']]),
++            ],
++            'Non-string HTTP_HOST falls back to SERVER_NAME' => [
++                'https://www.example.org/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => ['www.example.org']]),
++            ],
++            'Non-string SERVER_NAME falls back to SERVER_ADDR' => [
++                'https://217.112.82.20/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => null, 'SERVER_NAME' => ['www.example.org']]),
++            ],
+             'REQUEST_URI missing query string' => [
+                 'https://www.example.org/blog/article.php?id=10&user=foo',
+                 array_merge($server, ['REQUEST_URI' => '/blog/article.php']),
+             ],
++            'Non-string REQUEST_URI is treated as missing' => [
++                'https://www.example.org?id=10&user=foo',
++                array_merge($server, ['REQUEST_URI' => ['bad']]),
++            ],
++            'Non-string QUERY_STRING is treated as missing' => [
++                'https://www.example.org/blog/article.php',
++                array_merge($server, ['REQUEST_URI' => '/blog/article.php', 'QUERY_STRING' => ['bad']]),
++            ],
+             'Empty server variable' => [
+                 'http://localhost',
+                 [],
+@@ -461,6 +485,23 @@ class ServerRequestTest extends TestCase
+         self::assertEquals($expectedFiles, $server->getUploadedFiles());
+     }
+ 
++    public function testFromGlobalsDefaultsNonStringMethodAndProtocol(): void
++    {
++        $_SERVER = [
++            'REQUEST_METHOD' => ['POST'],
++            'SERVER_PROTOCOL' => ['HTTP/1.1'],
++            'REQUEST_URI' => '/',
++            'SERVER_PORT' => '80',
++        ];
++
++        $_COOKIE = $_POST = $_GET = $_FILES = [];
++
++        $server = ServerRequest::fromGlobals();
++
++        self::assertSame('GET', $server->getMethod());
++        self::assertSame('1.1', $server->getProtocolVersion());
++    }
++
+     public function testUploadedFiles(): void
+     {
+         $request1 = new ServerRequest('GET', '/');
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/patches/0006-Normalize-global-header-values-718.patch php-guzzlehttp-psr7-2.7.1/debian/patches/0006-Normalize-global-header-values-718.patch
--- php-guzzlehttp-psr7-2.7.1/debian/patches/0006-Normalize-global-header-values-718.patch	1970-01-01 01:00:00.000000000 +0100
+++ php-guzzlehttp-psr7-2.7.1/debian/patches/0006-Normalize-global-header-values-718.patch	2026-05-30 13:39:01.000000000 +0200
@@ -0,0 +1,102 @@
+From: Graham Campbell <GrahamCampbell@users.noreply.github.com>
+Date: Mon, 25 May 2026 21:50:08 +0100
+Subject: Normalize global header values (#718)
+
+Origin: backport, https://github.com/guzzle/psr7/commit/a0fda818b0f74482925e66e814fe9afb48fd2fa5
+Bug: https://github.com/guzzle/psr7/pull/718
+---
+ src/ServerRequest.php       | 28 +++++++++++++++++++++++++++-
+ tests/ServerRequestTest.php | 34 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 61 insertions(+), 1 deletion(-)
+
+diff --git a/src/ServerRequest.php b/src/ServerRequest.php
+index bc795fc..341af9c 100644
+--- a/src/ServerRequest.php
++++ b/src/ServerRequest.php
+@@ -166,7 +166,7 @@ class ServerRequest extends Request implements ServerRequestInterface
+     public static function fromGlobals(): ServerRequestInterface
+     {
+         $method = self::getServerParam('REQUEST_METHOD') ?? 'GET';
+-        $headers = getallheaders();
++        $headers = self::getAllHeaders();
+         $uri = self::getUriFromGlobals();
+         $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
+         $serverProtocol = self::getServerParam('SERVER_PROTOCOL');
+@@ -181,6 +181,32 @@ class ServerRequest extends Request implements ServerRequestInterface
+             ->withUploadedFiles(self::normalizeFiles($_FILES));
+     }
+ 
++    /**
++     * @return array<array-key, string>
++     */
++    private static function getAllHeaders(): array
++    {
++        return self::normalizeHeaderValues(getallheaders());
++    }
++
++    /**
++     * @param array<array-key, mixed> $headers
++     *
++     * @return array<array-key, string>
++     */
++    private static function normalizeHeaderValues(array $headers): array
++    {
++        $normalized = [];
++
++        foreach ($headers as $name => $value) {
++            if (is_scalar($value) || (is_object($value) && method_exists($value, '__toString'))) {
++                $normalized[$name] = (string) $value;
++            }
++        }
++
++        return $normalized;
++    }
++
+     private static function getServerParam(string $key): ?string
+     {
+         return isset($_SERVER[$key]) && is_string($_SERVER[$key]) ? $_SERVER[$key] : null;
+diff --git a/tests/ServerRequestTest.php b/tests/ServerRequestTest.php
+index dbd2288..939ab19 100644
+--- a/tests/ServerRequestTest.php
++++ b/tests/ServerRequestTest.php
+@@ -485,6 +485,40 @@ class ServerRequestTest extends TestCase
+         self::assertEquals($expectedFiles, $server->getUploadedFiles());
+     }
+ 
++    public function testFromGlobalsNormalizesUnexpectedHeaderValueTypes(): void
++    {
++        $_SERVER = [
++            'REQUEST_URI' => '/',
++            'HTTP_HOST' => 'www.example.org',
++            'HTTP_X_INT' => 123,
++            'HTTP_X_FLOAT' => 1.5,
++            'HTTP_X_FALSE' => false,
++            'HTTP_X_TRUE' => true,
++            'HTTP_X_STRINGABLE' => new class {
++                public function __toString(): string
++                {
++                    return 'stringable';
++                }
++            },
++            'HTTP_X_ARRAY' => ['bad'],
++            'HTTP_X_OBJECT' => new \stdClass(),
++            'HTTP_123' => 'numeric header',
++        ];
++
++        $_COOKIE = $_POST = $_GET = $_FILES = [];
++
++        $server = ServerRequest::fromGlobals();
++
++        self::assertSame('123', $server->getHeaderLine('X-Int'));
++        self::assertSame('1.5', $server->getHeaderLine('X-Float'));
++        self::assertSame([''], $server->getHeader('X-False'));
++        self::assertSame('1', $server->getHeaderLine('X-True'));
++        self::assertSame('stringable', $server->getHeaderLine('X-Stringable'));
++        self::assertSame('numeric header', $server->getHeaderLine('123'));
++        self::assertFalse($server->hasHeader('X-Array'));
++        self::assertFalse($server->hasHeader('X-Object'));
++    }
++
+     public function testFromGlobalsDefaultsNonStringMethodAndProtocol(): void
+     {
+         $_SERVER = [
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/patches/0007-Reject-malformed-Host-authorities-717.patch php-guzzlehttp-psr7-2.7.1/debian/patches/0007-Reject-malformed-Host-authorities-717.patch
--- php-guzzlehttp-psr7-2.7.1/debian/patches/0007-Reject-malformed-Host-authorities-717.patch	1970-01-01 01:00:00.000000000 +0100
+++ php-guzzlehttp-psr7-2.7.1/debian/patches/0007-Reject-malformed-Host-authorities-717.patch	2026-05-30 13:39:01.000000000 +0200
@@ -0,0 +1,476 @@
+From: Graham Campbell <GrahamCampbell@users.noreply.github.com>
+Date: Mon, 25 May 2026 22:42:00 +0100
+Subject: Reject malformed Host authorities (#717)
+
+* Reject malformed Host authorities
+
+* Tighten Host authority validation
+
+* Mark Host authority fix as security
+
+* Remove redundant Host header type check
+
+* Share Host header authority parser
+
+* Move RFC 3986 character classes
+
+* Order RFC 3986 constants by section
+
+* Remove unused Host port flag
+
+* Avoid port zero parseRequest case
+
+Origin: backport, https://github.com/guzzle/psr7/commit/c68fe44ea6b56eb0a7ebdeb9012fb7efbc37c2d3
+Bug: https://github.com/guzzle/psr7/security/advisories/GHSA-34xg-wgjx-8xph
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2026-48998
+---
+ src/Message.php             | 26 +++++++++++---
+ src/Rfc3986.php             | 25 ++++++++++++++
+ src/Rfc7230.php             | 83 +++++++++++++++++++++++++++++++++++++++++++++
+ src/ServerRequest.php       | 31 +++++++++++------
+ src/Uri.php                 | 19 ++---------
+ tests/MessageTest.php       | 56 ++++++++++++++++++++++++++++++
+ tests/ServerRequestTest.php | 78 ++++++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 288 insertions(+), 30 deletions(-)
+ create mode 100644 src/Rfc3986.php
+
+diff --git a/src/Message.php b/src/Message.php
+index 5561a51..d3aafca 100644
+--- a/src/Message.php
++++ b/src/Message.php
+@@ -174,6 +174,23 @@ final class Message
+      * @param array  $headers Array of headers (each value an array).
+      */
+     public static function parseRequestUri(string $path, array $headers): string
++    {
++        $host = self::getHostFromHeaders($headers);
++
++        // If no host is found, then a full URI cannot be constructed.
++        if ($host === null) {
++            return $path;
++        }
++
++        $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
++
++        return $scheme.'://'.$host.'/'.ltrim($path, '/');
++    }
++
++    /**
++     * @param array $headers Array of headers (each value an array).
++     */
++    private static function getHostFromHeaders(array $headers): ?string
+     {
+         $hostKey = array_filter(array_keys($headers), function ($k) {
+             // Numeric array keys are converted to int by PHP.
+@@ -182,15 +199,16 @@ final class Message
+             return strtolower($k) === 'host';
+         });
+ 
+-        // If no host is found, then a full URI cannot be constructed.
+         if (!$hostKey) {
+-            return $path;
++            return null;
+         }
+ 
+         $host = $headers[reset($hostKey)][0];
+-        $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
++        if (!is_string($host) || Rfc7230::parseHostHeader($host) === null) {
++            throw new \InvalidArgumentException('Invalid request string');
++        }
+ 
+-        return $scheme.'://'.$host.'/'.ltrim($path, '/');
++        return $host;
+     }
+ 
+     /**
+diff --git a/src/Rfc3986.php b/src/Rfc3986.php
+new file mode 100644
+index 0000000..6cc2ec0
+--- /dev/null
++++ b/src/Rfc3986.php
+@@ -0,0 +1,25 @@
++<?php
++
++declare(strict_types=1);
++
++namespace GuzzleHttp\Psr7;
++
++/**
++ * @internal
++ */
++final class Rfc3986
++{
++    /**
++     * Sub-delims for use in a regex.
++     *
++     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
++     */
++    public const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';
++
++    /**
++     * Unreserved characters for use in a regex.
++     *
++     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.3
++     */
++    public const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~';
++}
+diff --git a/src/Rfc7230.php b/src/Rfc7230.php
+index 8219dba..9cd4863 100644
+--- a/src/Rfc7230.php
++++ b/src/Rfc7230.php
+@@ -20,4 +20,87 @@ final class Rfc7230
+      */
+     public const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m";
+     public const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
++
++    /**
++     * @return array{0: string, 1: int|null}|null
++     */
++    public static function parseHostHeader(string $authority): ?array
++    {
++        if ($authority === '') {
++            return null;
++        }
++
++        $host = $authority;
++        $port = null;
++
++        if ($authority[0] === '[') {
++            $closingBracket = strpos($authority, ']');
++            if ($closingBracket === false) {
++                return null;
++            }
++
++            $host = substr($authority, 0, $closingBracket + 1);
++            $remainder = substr($authority, $closingBracket + 1);
++            if ($remainder !== '') {
++                if ($remainder[0] !== ':') {
++                    return null;
++                }
++
++                $port = self::parseAuthorityPort(substr($remainder, 1));
++                if ($port === null) {
++                    return null;
++                }
++            }
++        } elseif (false !== ($colon = strpos($authority, ':'))) {
++            $host = substr($authority, 0, $colon);
++            $port = self::parseAuthorityPort(substr($authority, $colon + 1));
++            if ($port === null) {
++                return null;
++            }
++        }
++
++        if ($host === '' || !self::isValidHostHeaderHost($host)) {
++            return null;
++        }
++
++        return [$host, $port];
++    }
++
++    private static function isValidHostHeaderHost(string $host): bool
++    {
++        if (preg_match('/[\x00-\x20\x7F\/\?#@\\\\]/', $host)) {
++            return false;
++        }
++
++        if (strpos($host, '[') !== false || strpos($host, ']') !== false) {
++            if ($host[0] !== '[' || substr($host, -1) !== ']') {
++                return false;
++            }
++
++            $address = substr($host, 1, -1);
++
++            return filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6) !== false
++                || preg_match('/^v[0-9a-f]+\.['.Rfc3986::CHAR_UNRESERVED.Rfc3986::CHAR_SUB_DELIMS.':]+$/iD', $address) === 1;
++        }
++
++        return strpos($host, ':') === false;
++    }
++
++    private static function parseAuthorityPort(string $port): ?int
++    {
++        if ($port === '' || !ctype_digit($port)) {
++            return null;
++        }
++
++        $normalized = ltrim($port, '0');
++        if ($normalized === '') {
++            return 0;
++        }
++
++        if (strlen($normalized) > 5 || (int) $normalized > 0xFFFF) {
++            return null;
++        }
++
++        return (int) $normalized;
++    }
+ }
+diff --git a/src/ServerRequest.php b/src/ServerRequest.php
+index 341af9c..3f87f96 100644
+--- a/src/ServerRequest.php
++++ b/src/ServerRequest.php
+@@ -166,7 +166,7 @@ class ServerRequest extends Request implements ServerRequestInterface
+     public static function fromGlobals(): ServerRequestInterface
+     {
+         $method = self::getServerParam('REQUEST_METHOD') ?? 'GET';
+-        $headers = self::getAllHeaders();
++        $headers = self::removeInvalidHostHeader(self::getAllHeaders());
+         $uri = self::getUriFromGlobals();
+         $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
+         $serverProtocol = self::getServerParam('SERVER_PROTOCOL');
+@@ -213,20 +213,31 @@ class ServerRequest extends Request implements ServerRequestInterface
+     }
+ 
+     /**
+-     * @return array{0: string|null, 1: int|null}
++     * @param array<array-key, string> $headers
++     *
++     * @return array<array-key, string>
+      */
+-    private static function extractHostAndPortFromAuthority(string $authority): array
++    private static function removeInvalidHostHeader(array $headers): array
+     {
+-        $uri = 'http://'.$authority;
+-        $parts = parse_url($uri);
+-        if (!is_array($parts)) {
+-            return [null, null];
++        foreach ($headers as $name => $value) {
++            if (strtolower((string) $name) !== 'host') {
++                continue;
++            }
++
++            if (Rfc7230::parseHostHeader($value) === null) {
++                unset($headers[$name]);
++            }
+         }
+ 
+-        $host = $parts['host'] ?? null;
+-        $port = $parts['port'] ?? null;
++        return $headers;
++    }
+ 
+-        return [$host, $port];
++    /**
++     * @return array{0: string|null, 1: int|null}
++     */
++    private static function extractHostAndPortFromAuthority(string $authority): array
++    {
++        return Rfc7230::parseHostHeader($authority) ?? [null, null];
+     }
+ 
+     /**
+diff --git a/src/Uri.php b/src/Uri.php
+index bef82e2..54bbb0a 100644
+--- a/src/Uri.php
++++ b/src/Uri.php
+@@ -38,19 +38,6 @@ class Uri implements UriInterface, \JsonSerializable
+         'ldap' => 389,
+     ];
+ 
+-    /**
+-     * Unreserved characters for use in a regex.
+-     *
+-     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.3
+-     */
+-    private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~';
+-
+-    /**
+-     * Sub-delims for use in a regex.
+-     *
+-     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
+-     */
+-    private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';
+     private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26', '+' => '%2B'];
+ 
+     /** @var string Uri scheme. */
+@@ -596,7 +583,7 @@ class Uri implements UriInterface, \JsonSerializable
+         }
+ 
+         return preg_replace_callback(
+-            '/(?:[^%'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.']+|%(?![A-Fa-f0-9]{2}))/',
++            '/(?:[^%'.Rfc3986::CHAR_UNRESERVED.Rfc3986::CHAR_SUB_DELIMS.']+|%(?![A-Fa-f0-9]{2}))/',
+             [$this, 'rawurlencodeMatchZero'],
+             $component
+         );
+@@ -695,7 +682,7 @@ class Uri implements UriInterface, \JsonSerializable
+         }
+ 
+         return preg_replace_callback(
+-            '/(?:[^'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.'%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
++            '/(?:[^'.Rfc3986::CHAR_UNRESERVED.Rfc3986::CHAR_SUB_DELIMS.'%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
+             [$this, 'rawurlencodeMatchZero'],
+             $path
+         );
+@@ -715,7 +702,7 @@ class Uri implements UriInterface, \JsonSerializable
+         }
+ 
+         return preg_replace_callback(
+-            '/(?:[^'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.'%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
++            '/(?:[^'.Rfc3986::CHAR_UNRESERVED.Rfc3986::CHAR_SUB_DELIMS.'%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
+             [$this, 'rawurlencodeMatchZero'],
+             $str
+         );
+diff --git a/tests/MessageTest.php b/tests/MessageTest.php
+index 1a43152..42909be 100644
+--- a/tests/MessageTest.php
++++ b/tests/MessageTest.php
+@@ -107,6 +107,62 @@ class MessageTest extends TestCase
+         self::assertSame('http://foo.com/', (string) $request->getUri());
+     }
+ 
++    /**
++     * @dataProvider invalidHostHeaderProvider
++     */
++    public function testParseRequestRejectsInvalidHostHeader(string $host): void
++    {
++        $this->expectException(\InvalidArgumentException::class);
++
++        Psr7\Message::parseRequest("GET / HTTP/1.1\r\nHost: {$host}\r\n\r\n");
++    }
++
++    public static function invalidHostHeaderProvider(): iterable
++    {
++        yield 'userinfo delimiter' => ['trusted.example@evil.example'];
++        yield 'path delimiter' => ['example.com/path'];
++        yield 'query delimiter' => ['example.com?query'];
++        yield 'fragment delimiter' => ['example.com#fragment'];
++        yield 'backslash delimiter' => ['example.com\\evil'];
++        yield 'space' => ['bad host'];
++        yield 'tab' => ["bad\thost"];
++        yield 'control character' => ['example'.chr(1).'com'];
++        yield 'delete' => ['example'.chr(0x7F).'com'];
++        yield 'multiple ports' => ['example.com:443:8443'];
++        yield 'missing closing bracket' => ['[::1'];
++        yield 'unexpected bracket suffix' => ['[::1]x'];
++        yield 'invalid ip literal' => ['[bad]'];
++        yield 'unexpected opening bracket' => ['foo[bar'];
++        yield 'unexpected closing bracket' => ['foo]bar'];
++    }
++
++    /**
++     * @dataProvider validHostHeaderProvider
++     */
++    public function testParseRequestAcceptsValidHostHeader(string $host, string $expectedUri): void
++    {
++        $request = Psr7\Message::parseRequest("GET / HTTP/1.1\r\nHost: {$host}\r\n\r\n");
++
++        self::assertSame($host, $request->getHeaderLine('Host'));
++        self::assertSame($expectedUri, (string) $request->getUri());
++    }
++
++    public static function validHostHeaderProvider(): iterable
++    {
++        yield 'host' => ['foo.com', 'http://foo.com/'];
++        yield 'https default port' => ['foo.com:443', 'https://foo.com/'];
++        yield 'non-default port' => ['foo.com:8080', 'http://foo.com:8080/'];
++        yield 'ipv6' => ['[::1]', 'http://[::1]/'];
++        yield 'ipv6 port' => ['[::1]:443', 'https://[::1]/'];
++    }
++
++    public function testParseRequestAcceptsMissingHostHeader(): void
++    {
++        $request = Psr7\Message::parseRequest("GET /abc HTTP/1.1\r\nFoo: bar\r\n\r\n");
++
++        self::assertSame('/abc', (string) $request->getUri());
++    }
++
+     public function testParsesRequestMessagesWithFullUri(): void
+     {
+         $req = "GET https://www.google.com:443/search?q=foobar HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
+diff --git a/tests/ServerRequestTest.php b/tests/ServerRequestTest.php
+index 939ab19..914f949 100644
+--- a/tests/ServerRequestTest.php
++++ b/tests/ServerRequestTest.php
+@@ -354,6 +354,46 @@ class ServerRequestTest extends TestCase
+                 'https://localhost/blog/article.php?id=10&user=foo',
+                 array_merge($server, ['HTTP_HOST' => 'a:b']),
+             ],
++            'Host header with userinfo delimiter' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'trusted.example@evil.example']),
++            ],
++            'Host header with path delimiter' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'example.com/path']),
++            ],
++            'Host header with query delimiter' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'example.com?x=1']),
++            ],
++            'Host header with fragment delimiter' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'example.com#frag']),
++            ],
++            'Host header with backslash delimiter' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'example.com\\evil']),
++            ],
++            'Host header with space' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'bad host']),
++            ],
++            'Host header with multiple ports' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'example.com:80:90']),
++            ],
++            'Host header with invalid ip literal' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => '[bad]']),
++            ],
++            'Host header with unexpected opening bracket' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'foo[bar']),
++            ],
++            'Host header with unexpected closing bracket' => [
++                'https://localhost/blog/article.php?id=10&user=foo',
++                array_merge($server, ['HTTP_HOST' => 'foo]bar']),
++            ],
+             'Different port with SERVER_PORT' => [
+                 'https://www.example.org:8324/blog/article.php?id=10&user=foo',
+                 array_merge($server, ['SERVER_PORT' => '8324']),
+@@ -536,6 +576,44 @@ class ServerRequestTest extends TestCase
+         self::assertSame('1.1', $server->getProtocolVersion());
+     }
+ 
++    /**
++     * @dataProvider invalidHostHeaderFromGlobalsProvider
++     */
++    public function testFromGlobalsDropsInvalidHostHeaderWhenUriFallsBack(string $host): void
++    {
++        if (!\function_exists('getallheaders')) {
++            self::markTestSkipped('getallheaders() is not available.');
++        }
++
++        $_SERVER = [
++            'REQUEST_URI' => '/',
++            'HTTP_HOST' => $host,
++            'SERVER_PORT' => '443',
++            'HTTPS' => 'on',
++        ];
++
++        $_COOKIE = $_POST = $_GET = $_FILES = [];
++
++        $request = ServerRequest::fromGlobals();
++
++        self::assertSame('localhost', $request->getUri()->getHost());
++        self::assertSame('localhost', $request->getHeaderLine('Host'));
++    }
++
++    public static function invalidHostHeaderFromGlobalsProvider(): iterable
++    {
++        yield 'userinfo delimiter' => ['trusted.example@evil.example'];
++        yield 'path delimiter' => ['example.com/path'];
++        yield 'query delimiter' => ['example.com?x=1'];
++        yield 'fragment delimiter' => ['example.com#frag'];
++        yield 'backslash delimiter' => ['example.com\\evil'];
++        yield 'space' => ['bad host'];
++        yield 'multiple ports' => ['example.com:80:90'];
++        yield 'invalid ip literal' => ['[bad]'];
++        yield 'unexpected opening bracket' => ['foo[bar'];
++        yield 'unexpected closing bracket' => ['foo]bar'];
++    }
++
+     public function testUploadedFiles(): void
+     {
+         $request1 = new ServerRequest('GET', '/');
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/patches/0008-Reject-control-characters-in-URI-hosts-715.patch php-guzzlehttp-psr7-2.7.1/debian/patches/0008-Reject-control-characters-in-URI-hosts-715.patch
--- php-guzzlehttp-psr7-2.7.1/debian/patches/0008-Reject-control-characters-in-URI-hosts-715.patch	1970-01-01 01:00:00.000000000 +0100
+++ php-guzzlehttp-psr7-2.7.1/debian/patches/0008-Reject-control-characters-in-URI-hosts-715.patch	2026-05-30 13:39:01.000000000 +0200
@@ -0,0 +1,185 @@
+From: Graham Campbell <GrahamCampbell@users.noreply.github.com>
+Date: Mon, 25 May 2026 21:16:23 +0100
+Subject: Reject control characters in URI hosts (#715)
+
+* Reject control characters in URI hosts
+
+* Validate generated Host header values
+
+* Mark URI host fix as security
+
+Origin: backport, https://github.com/guzzle/psr7/commit/12caca7f2302477216a460fabf93a92659835a06
+Bug: https://github.com/guzzle/psr7/security/advisories/GHSA-hq7v-mx3g-29hw
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2026-49214
+---
+ src/Request.php       |  4 ++++
+ src/Uri.php           | 39 +++++++++++++++++++++++++++++++++++----
+ tests/RequestTest.php | 23 +++++++++++++++++++++++
+ tests/UriTest.php     | 26 ++++++++++++++++++++++++++
+ 4 files changed, 88 insertions(+), 4 deletions(-)
+
+diff --git a/src/Request.php b/src/Request.php
+index faafe1a..743c5d2 100644
+--- a/src/Request.php
++++ b/src/Request.php
+@@ -132,10 +132,14 @@ class Request implements RequestInterface
+             return;
+         }
+ 
++        Uri::assertValidHost($host);
++
+         if (($port = $this->uri->getPort()) !== null) {
+             $host .= ':'.$port;
+         }
+ 
++        $this->assertValue($host);
++
+         if (isset($this->headerNames['host'])) {
+             $header = $this->headerNames['host'];
+         } else {
+diff --git a/src/Uri.php b/src/Uri.php
+index 54bbb0a..b26e12d 100644
+--- a/src/Uri.php
++++ b/src/Uri.php
+@@ -71,7 +71,13 @@ class Uri implements UriInterface, \JsonSerializable
+             if ($parts === false) {
+                 throw new MalformedUriException("Unable to parse URI: $uri");
+             }
+-            $this->applyParts($parts);
++            try {
++                $this->applyParts($parts);
++            } catch (MalformedUriException $e) {
++                throw $e;
++            } catch (\InvalidArgumentException $e) {
++                throw new MalformedUriException($e->getMessage(), 0, $e);
++            }
+         }
+     }
+ 
+@@ -347,12 +353,34 @@ class Uri implements UriInterface, \JsonSerializable
+     public static function fromParts(array $parts): UriInterface
+     {
+         $uri = new self();
+-        $uri->applyParts($parts);
+-        $uri->validateState();
++        try {
++            $uri->applyParts($parts);
++            $uri->validateState();
++        } catch (MalformedUriException $e) {
++            throw $e;
++        } catch (\InvalidArgumentException $e) {
++            throw new MalformedUriException($e->getMessage(), 0, $e);
++        }
+ 
+         return $uri;
+     }
+ 
++    /**
++     * @throws \InvalidArgumentException If the host is invalid.
++     *
++     * @internal
++     */
++    public static function assertValidHost(string $host): void
++    {
++        if ($host === '') {
++            return;
++        }
++
++        if (preg_match('/[\x00-\x20\x7F]/', $host)) {
++            throw new \InvalidArgumentException(sprintf('Invalid host: "%s"', $host));
++        }
++    }
++
+     public function getScheme(): string
+     {
+         return $this->scheme;
+@@ -600,7 +628,10 @@ class Uri implements UriInterface, \JsonSerializable
+             throw new \InvalidArgumentException('Host must be a string');
+         }
+ 
+-        return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
++        $host = \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
++        self::assertValidHost($host);
++
++        return $host;
+     }
+ 
+     /**
+diff --git a/tests/RequestTest.php b/tests/RequestTest.php
+index 19d71c3..3a62c57 100644
+--- a/tests/RequestTest.php
++++ b/tests/RequestTest.php
+@@ -9,6 +9,7 @@ use GuzzleHttp\Psr7\Request;
+ use GuzzleHttp\Psr7\Uri;
+ use PHPUnit\Framework\TestCase;
+ use Psr\Http\Message\StreamInterface;
++use Psr\Http\Message\UriInterface;
+ 
+ /**
+  * @covers \GuzzleHttp\Psr7\MessageTrait
+@@ -306,6 +307,28 @@ class RequestTest extends TestCase
+         self::assertSame('foo.com:8125', $r->getHeaderLine('host'));
+     }
+ 
++    public function testGeneratedHostHeaderRejectsInvalidUriHostFromCustomUri(): void
++    {
++        $uri = $this->createMock(UriInterface::class);
++        $uri->method('getHost')->willReturn("foo\nbar");
++        $uri->method('getPort')->willReturn(null);
++
++        $this->expectException(\InvalidArgumentException::class);
++
++        new Request('GET', $uri);
++    }
++
++    public function testGeneratedHostHeaderValidatesAssembledHostWithPort(): void
++    {
++        $uri = $this->createMock(UriInterface::class);
++        $uri->method('getHost')->willReturn('example.com');
++        $uri->method('getPort')->willReturn(8080);
++
++        $request = new Request('GET', $uri);
++
++        self::assertSame('example.com:8080', $request->getHeaderLine('Host'));
++    }
++
+     /**
+      * @dataProvider provideHeaderValuesContainingNotAllowedChars
+      */
+diff --git a/tests/UriTest.php b/tests/UriTest.php
+index 3fb0716..da229a7 100644
+--- a/tests/UriTest.php
++++ b/tests/UriTest.php
+@@ -153,6 +153,32 @@ class UriTest extends TestCase
+         (new Uri())->withHost([]);
+     }
+ 
++    /**
++     * @dataProvider getInvalidHostsWithControlCharacters
++     */
++    public function testHostMustRejectControlCharacters(string $host): void
++    {
++        $this->expectException(\InvalidArgumentException::class);
++
++        (new Uri())->withHost($host);
++    }
++
++    public static function getInvalidHostsWithControlCharacters(): iterable
++    {
++        for ($i = 0; $i <= 0x20; ++$i) {
++            yield 'ascii 0x'.strtoupper(dechex($i)) => ['example'.chr($i).'com'];
++        }
++
++        yield 'ascii 0x7F' => ['example'.chr(0x7F).'com'];
++    }
++
++    public function testParseUriRejectsHostWithControlCharacter(): void
++    {
++        $this->expectException(MalformedUriException::class);
++
++        new Uri("http://example.com\r\nX-Injected:%20yes/");
++    }
++
+     public function testPathMustHaveCorrectType(): void
+     {
+         $this->expectException(\InvalidArgumentException::class);
diff -Nru php-guzzlehttp-psr7-2.7.1/debian/patches/series php-guzzlehttp-psr7-2.7.1/debian/patches/series
--- php-guzzlehttp-psr7-2.7.1/debian/patches/series	2025-03-31 12:18:24.000000000 +0200
+++ php-guzzlehttp-psr7-2.7.1/debian/patches/series	2026-05-30 13:39:01.000000000 +0200
@@ -1,4 +1,9 @@
 0001-Adapt-path-to-Debian-expectations.patch
 0002-Compatibility-with-recent-PHPUnit-10.patch
 0003-Make-provider-functions-static-PHPUnit-11-Fix.patch
+0004-2.8-Encode-plus-sign-in-withQueryValue-and-withQuery.patch
+0005-Harden-ServerRequest-globals-handling-660.patch
+0006-Normalize-global-header-values-718.patch
+0007-Reject-malformed-Host-authorities-717.patch
+0008-Reject-control-characters-in-URI-hosts-715.patch
 0004-Modernize-PHPUnit-syntax.patch
