From dee1899628380998d3a284e41bfc49ce0737dd2f Mon Sep 17 00:00:00 2001
From: Philipp <admin@philipp.info>
Date: Fri, 20 Aug 2021 19:48:14 +0200
Subject: [PATCH] Fix IHTTPResult::getHeader/s() - Split functionality
 "getHeader()" and "getHeaders()" analog to IMessageInterface::getHeader/s() -
 Fix functionality at various places - Adapt CurlResultTest

---
 src/Network/CurlResult.php             | 18 ++++++++++++------
 src/Network/HTTPRequest.php            |  3 +--
 src/Network/IHTTPResult.php            | 22 +++++++++++++++++++---
 src/Protocol/DFRN.php                  |  2 +-
 src/Protocol/OStatus.php               |  6 ++++--
 src/Protocol/Salmon.php                |  2 +-
 src/Util/ParseUrl.php                  |  3 +--
 tests/datasets/curl/about.head.php     | 20 ++++++++++++++++++++
 tests/datasets/curl/about.redirect.php | 21 +++++++++++++++++++++
 tests/src/Network/CurlResultTest.php   | 14 +++++++++-----
 10 files changed, 89 insertions(+), 22 deletions(-)
 create mode 100644 tests/datasets/curl/about.head.php
 create mode 100644 tests/datasets/curl/about.redirect.php

diff --git a/src/Network/CurlResult.php b/src/Network/CurlResult.php
index 6fb0153b6..227d26140 100644
--- a/src/Network/CurlResult.php
+++ b/src/Network/CurlResult.php
@@ -242,23 +242,29 @@ class CurlResult implements IHTTPResult
 	}
 
 	/** {@inheritDoc} */
-	public function getHeader(string $field = '')
+	public function getHeader($header)
 	{
-		if (empty($field)) {
-			return $this->header;
+		if (empty($header)) {
+			return '';
 		}
 
-		$field = strtolower(trim($field));
+		$header = strtolower(trim($header));
 
 		$headers = $this->getHeaderArray();
 
-		if (isset($headers[$field])) {
-			return $headers[$field];
+		if (isset($headers[$header])) {
+			return $headers[$header];
 		}
 
 		return '';
 	}
 
+	/** {@inheritDoc} */
+	public function getHeaders()
+	{
+		return $this->getHeaderArray();
+	}
+
 	/** {@inheritDoc} */
 	public function inHeader(string $field)
 	{
diff --git a/src/Network/HTTPRequest.php b/src/Network/HTTPRequest.php
index 523efc698..72311ea19 100644
--- a/src/Network/HTTPRequest.php
+++ b/src/Network/HTTPRequest.php
@@ -493,8 +493,7 @@ class HTTPRequest implements IHTTPRequest
 				'timeout'        => $timeout,
 				'accept_content' => $accept_content,
 				'cookiejar'      => $cookiejar
-			],
-			$redirects
+			]
 		);
 	}
 
diff --git a/src/Network/IHTTPResult.php b/src/Network/IHTTPResult.php
index be190c80c..5904bcfa3 100644
--- a/src/Network/IHTTPResult.php
+++ b/src/Network/IHTTPResult.php
@@ -2,6 +2,8 @@
 
 namespace Friendica\Network;
 
+use Psr\Http\Message\MessageInterface;
+
 /**
  * Temporary class to map Friendica used variables based on PSR-7 HTTPResponse
  */
@@ -23,15 +25,25 @@ interface IHTTPResult
 
 	/**
 	 * Returns the headers
+	 * @see MessageInterface::getHeader()
 	 *
-	 * @param string $field optional header field. Return all fields if empty
+	 * @param string $header optional header field. Return all fields if empty
 	 *
 	 * @return string the headers or the specified content of the header variable
 	 */
-	public function getHeader(string $field = '');
+	public function getHeader($header);
+
+	/**
+	 * Returns all headers
+	 * @see MessageInterface::getHeaders()
+	 *
+	 * @return string[][]
+	 */
+	public function getHeaders();
 
 	/**
 	 * Check if a specified header exists
+	 * @see MessageInterface::hasHeader()
 	 *
 	 * @param string $field header field
 	 *
@@ -41,8 +53,10 @@ interface IHTTPResult
 
 	/**
 	 * Returns the headers as an associated array
+	 * @see MessageInterface::getHeaders()
+	 * @deprecated
 	 *
-	 * @return array associated header array
+	 * @return string[][] associated header array
 	 */
 	public function getHeaderArray();
 
@@ -62,6 +76,8 @@ interface IHTTPResult
 	public function getRedirectUrl();
 
 	/**
+	 * @see MessageInterface::getBody()
+	 *
 	 * @return string
 	 */
 	public function getBody();
diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php
index 832e2bde2..cd63291ee 100644
--- a/src/Protocol/DFRN.php
+++ b/src/Protocol/DFRN.php
@@ -985,7 +985,7 @@ class DFRN
 			return -9; // timed out
 		}
 
-		if (($curl_stat == 503) && (stristr($postResult->getHeader(), 'retry-after'))) {
+		if (($curl_stat == 503) && $postResult->inHeader('retry-after')) {
 			return -10;
 		}
 
diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php
index e813cc250..8d818471b 100644
--- a/src/Protocol/OStatus.php
+++ b/src/Protocol/OStatus.php
@@ -735,7 +735,8 @@ class OStatus
 
 		$xml = '';
 
-		if (stristr($curlResult->getHeader(), 'Content-Type: application/atom+xml')) {
+		if ($curlResult->inHeader('Content-Type') &&
+			stristr($curlResult->getHeader('Content-Type'), 'application/atom+xml')) {
 			$xml = $curlResult->getBody();
 		}
 
@@ -928,7 +929,8 @@ class OStatus
 
 		$xml = '';
 
-		if (stristr($curlResult->getHeader(), 'Content-Type: application/atom+xml')) {
+		if ($curlResult->inHeader('Content-Type') &&
+			stristr($curlResult->getHeader('Content-Type'), 'application/atom+xml')) {
 			Logger::log('Directly fetched XML for URI ' . $related_uri, Logger::DEBUG);
 			$xml = $curlResult->getBody();
 		}
diff --git a/src/Protocol/Salmon.php b/src/Protocol/Salmon.php
index 81b1f7528..53367f6d0 100644
--- a/src/Protocol/Salmon.php
+++ b/src/Protocol/Salmon.php
@@ -215,7 +215,7 @@ class Salmon
 			return -1;
 		}
 
-		if (($return_code == 503) && (stristr($postResult->getHeader(), 'retry-after'))) {
+		if (($return_code == 503) && $postResult->inHeader('retry-after')) {
 			return -1;
 		}
 
diff --git a/src/Util/ParseUrl.php b/src/Util/ParseUrl.php
index d5c9f02ad..75210af0f 100644
--- a/src/Util/ParseUrl.php
+++ b/src/Util/ParseUrl.php
@@ -232,7 +232,6 @@ class ParseUrl
 			}
 		}
 
-		$header = $curlResult->getHeader();
 		$body = $curlResult->getBody();
 
 		if ($do_oembed) {
@@ -273,7 +272,7 @@ class ParseUrl
 		$charset = '';
 		// Look for a charset, first in headers
 		// Expected form: Content-Type: text/html; charset=ISO-8859-4
-		if (preg_match('/charset=([a-z0-9-_.\/]+)/i', $header, $matches)) {
+		if (preg_match('/charset=([a-z0-9-_.\/]+)/i', $curlResult->getContentType(), $matches)) {
 			$charset = trim(trim(trim(array_pop($matches)), ';,'));
 		}
 
diff --git a/tests/datasets/curl/about.head.php b/tests/datasets/curl/about.head.php
new file mode 100644
index 000000000..d0be0feb4
--- /dev/null
+++ b/tests/datasets/curl/about.head.php
@@ -0,0 +1,20 @@
+<?php
+
+return [
+	'http/2 200' => '',
+    'date' => 'Thu, 11 Oct 2018 18:43:54 GMT',
+    'content-type' => 'text/html; charset=utf-8',
+    'vary' => 'Accept-Encoding',
+    'server' => 'Mastodon',
+    'x-frame-options' => 'SAMEORIGIN',
+    'x-content-type-options' => 'nosniff',
+    'x-xss-protection' => '1; mode=block',
+    'etag' => 'W/"706e6c48957e1d46ecf9d7597a7880af"',
+    'cache-control' => 'max-age=0, private, must-revalidate',
+    'set-cookie' => '_mastodon_session=v3kcy%2FW3aZYBBvZUohuwksEKwzYIyEUlEuJ1KqTAfWPKvVQq%2F4UuJ39zp621VyfpQNlvY46TL%2FYutzXowSLYQBNFCJcrEiF04aU0TdtHls9zynMiyeHhoVgCijOXWXNt9%2FCmpQ49RkNEujkv9NaJ0cum32MCVZKjE9%2BMKmLM%2F8ZygZeLBGJ7sg%3D%3D--QGIiU0%2FpXc3Aym8F--he2iRRPePOdtEs3z%2BufSXg%3D%3D; path=/; secure; HttpOnly',
+    'x-request-id' => 'a0c0b8e7-cd60-4efa-b79b-cf1b0d5a0784',
+    'x-runtime' => '0.049566',
+    'strict-transport-security' => 'max-age=31536000; includeSubDomains; preload',
+    'referrer-policy' => 'same-origin',
+    'content-security-policy' => "frame-ancestors 'none'; script-src 'self'; object-src 'self'; img-src * data: blob:; media-src 'self' data:; font-src 'self' data: https://fonts.gstatic.com/; connect-src 'self' blob: wss://mastodonten.de",
+];
diff --git a/tests/datasets/curl/about.redirect.php b/tests/datasets/curl/about.redirect.php
new file mode 100644
index 000000000..5ae3fd88f
--- /dev/null
+++ b/tests/datasets/curl/about.redirect.php
@@ -0,0 +1,21 @@
+<?php
+
+return [
+	'http/2 301' => '',
+    'date' => 'Thu, 11 Oct 2018 18:43:54 GMT',
+    'content-type' => 'text/html; charset=utf-8',
+    'vary' => 'Accept-Encoding',
+    'server' => 'Mastodon',
+    'location' => 'https://test.other/some/',
+    'x-frame-options' => 'SAMEORIGIN',
+    'x-content-type-options' => 'nosniff',
+    'x-xss-protection' => '1; mode=block',
+    'etag' => 'W/"706e6c48957e1d46ecf9d7597a7880af"',
+    'cache-control' => 'max-age=0, private, must-revalidate',
+    'set-cookie' => '_mastodon_session=v3kcy%2FW3aZYBBvZUohuwksEKwzYIyEUlEuJ1KqTAfWPKvVQq%2F4UuJ39zp621VyfpQNlvY46TL%2FYutzXowSLYQBNFCJcrEiF04aU0TdtHls9zynMiyeHhoVgCijOXWXNt9%2FCmpQ49RkNEujkv9NaJ0cum32MCVZKjE9%2BMKmLM%2F8ZygZeLBGJ7sg%3D%3D--QGIiU0%2FpXc3Aym8F--he2iRRPePOdtEs3z%2BufSXg%3D%3D; path=/; secure; HttpOnly',
+    'x-request-id' => 'a0c0b8e7-cd60-4efa-b79b-cf1b0d5a0784',
+    'x-runtime' => '0.049566',
+    'strict-transport-security' => 'max-age=31536000; includeSubDomains; preload',
+    'referrer-policy' => 'same-origin',
+    'content-security-policy' => "frame-ancestors 'none'; script-src 'self'; object-src 'self'; img-src * data: blob:; media-src 'self' data:; font-src 'self' data: https://fonts.gstatic.com/; connect-src 'self' blob: wss://mastodonten.de",
+];
diff --git a/tests/src/Network/CurlResultTest.php b/tests/src/Network/CurlResultTest.php
index 090479642..c28dc5f1b 100644
--- a/tests/src/Network/CurlResultTest.php
+++ b/tests/src/Network/CurlResultTest.php
@@ -53,6 +53,7 @@ class CurlResultTest extends TestCase
 	public function testNormal()
 	{
 		$header = file_get_contents(__DIR__ . '/../../datasets/curl/about.head');
+		$headerArray = include(__DIR__ . '/../../datasets/curl/about.head.php');
 		$body = file_get_contents(__DIR__ . '/../../datasets/curl/about.body');
 
 
@@ -65,7 +66,7 @@ class CurlResultTest extends TestCase
 		self::assertTrue($curlResult->isSuccess());
 		self::assertFalse($curlResult->isTimeout());
 		self::assertFalse($curlResult->isRedirectUrl());
-		self::assertSame($header, $curlResult->getHeader());
+		self::assertSame($headerArray, $curlResult->getHeaders());
 		self::assertSame($body, $curlResult->getBody());
 		self::assertSame('text/html; charset=utf-8', $curlResult->getContentType());
 		self::assertSame('https://test.local', $curlResult->getUrl());
@@ -80,6 +81,7 @@ class CurlResultTest extends TestCase
 	public function testRedirect()
 	{
 		$header = file_get_contents(__DIR__ . '/../../datasets/curl/about.head');
+		$headerArray = include(__DIR__ . '/../../datasets/curl/about.head.php');
 		$body = file_get_contents(__DIR__ . '/../../datasets/curl/about.body');
 
 
@@ -93,7 +95,7 @@ class CurlResultTest extends TestCase
 		self::assertTrue($curlResult->isSuccess());
 		self::assertFalse($curlResult->isTimeout());
 		self::assertTrue($curlResult->isRedirectUrl());
-		self::assertSame($header, $curlResult->getHeader());
+		self::assertSame($headerArray, $curlResult->getHeaders());
 		self::assertSame($body, $curlResult->getBody());
 		self::assertSame('text/html; charset=utf-8', $curlResult->getContentType());
 		self::assertSame('https://test.local/test/it', $curlResult->getUrl());
@@ -106,6 +108,7 @@ class CurlResultTest extends TestCase
 	public function testTimeout()
 	{
 		$header = file_get_contents(__DIR__ . '/../../datasets/curl/about.head');
+		$headerArray = include(__DIR__ . '/../../datasets/curl/about.head.php');
 		$body = file_get_contents(__DIR__ . '/../../datasets/curl/about.body');
 
 
@@ -119,7 +122,7 @@ class CurlResultTest extends TestCase
 		self::assertFalse($curlResult->isSuccess());
 		self::assertTrue($curlResult->isTimeout());
 		self::assertFalse($curlResult->isRedirectUrl());
-		self::assertSame($header, $curlResult->getHeader());
+		self::assertSame($headerArray, $curlResult->getHeaders());
 		self::assertSame($body, $curlResult->getBody());
 		self::assertSame('text/html; charset=utf-8', $curlResult->getContentType());
 		self::assertSame('https://test.local/test/it', $curlResult->getRedirectUrl());
@@ -134,6 +137,7 @@ class CurlResultTest extends TestCase
 	public function testRedirectHeader()
 	{
 		$header = file_get_contents(__DIR__ . '/../../datasets/curl/about.redirect');
+		$headerArray = include(__DIR__ . '/../../datasets/curl/about.redirect.php');
 		$body = file_get_contents(__DIR__ . '/../../datasets/curl/about.body');
 
 
@@ -146,7 +150,7 @@ class CurlResultTest extends TestCase
 		self::assertTrue($curlResult->isSuccess());
 		self::assertFalse($curlResult->isTimeout());
 		self::assertTrue($curlResult->isRedirectUrl());
-		self::assertSame($header, $curlResult->getHeader());
+		self::assertSame($headerArray, $curlResult->getHeaders());
 		self::assertSame($body, $curlResult->getBody());
 		self::assertSame('text/html; charset=utf-8', $curlResult->getContentType());
 		self::assertSame('https://test.local/test/it?key=value', $curlResult->getUrl());
@@ -204,7 +208,7 @@ class CurlResultTest extends TestCase
 			'url' => 'https://test.local'
 		]);
 
-		self::assertNotEmpty($curlResult->getHeader());
+		self::assertNotEmpty($curlResult->getHeaders());
 		self::assertEmpty($curlResult->getHeader('wrongHeader'));
 	}
 }