From f2ead458ea49219a332ae44251a2aaa39a33f7db Mon Sep 17 00:00:00 2001 From: stutteringp0et Date: Sun, 10 Apr 2016 11:45:35 -0500 Subject: [PATCH 01/22] Update web.php setHeader $replace previously did nothing other than delete a value - even when false it allowed a duplicate to be created which effectively replaces the original. This modification searches for an existing header with the same name and only inserts it if it doesn't already exist, or if $replace is true. --- libraries/joomla/application/web.php | 34 +++++++++++++--------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 0c23e6ba192ee..8d37b69968a5f 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -624,24 +624,22 @@ public function setHeader($name, $value, $replace = false) // Sanitize the input values. $name = (string) $name; $value = (string) $value; - - // If the replace flag is set, unset all known headers with the given name. - if ($replace) - { - foreach ($this->response->headers as $key => $header) - { - if ($name == $header['name']) - { - unset($this->response->headers[$key]); - } - } - - // Clean up the array as unsetting nested arrays leaves some junk. - $this->response->headers = array_values($this->response->headers); - } - - // Add the header to the internal array. - $this->response->headers[] = array('name' => $name, 'value' => $value); + + // create an array of names to search for duplicates + $names = array(); + foreach($this->response->headers as $key=>$header) { + $names[$key]=$header['name']; + } + $key = array_search($name,$names); // find existing headers by name + if($key !== false && $replace || $key === false) { // found & replace or not found + if($key !== false) { // remove before insert when header is found + unset($this->response->headers[$key]); + // Clean up the array as unsetting nested arrays leaves some junk. + $this->response->headers = array_values($this->response->headers); + } + // Add the header to the internal array. + $this->response->headers[] = array('name' => $name, 'value' => $value); + } return $this; } From 95a70296eb4ba80277244115040070b4b767071e Mon Sep 17 00:00:00 2001 From: stutteringp0et Date: Sun, 10 Apr 2016 12:48:39 -0500 Subject: [PATCH 02/22] JApplicationWeb::setHeader behavior Fix Travis CI error regarding invalid foreach --- libraries/joomla/application/web.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 8d37b69968a5f..96770e4ceae4d 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -626,11 +626,14 @@ public function setHeader($name, $value, $replace = false) $value = (string) $value; // create an array of names to search for duplicates - $names = array(); - foreach($this->response->headers as $key=>$header) { - $names[$key]=$header['name']; + $key = false; + if(count($this->response->headers)) { + $names = array(); + foreach($this->response->headers as $key=>$header) { + $names[$key]=$header['name']; + } + $key = array_search($name,$names); // find existing headers by name } - $key = array_search($name,$names); // find existing headers by name if($key !== false && $replace || $key === false) { // found & replace or not found if($key !== false) { // remove before insert when header is found unset($this->response->headers[$key]); From e0eb2c8c9512f83bc3f642c251f0110d99d454b1 Mon Sep 17 00:00:00 2001 From: stutteringp0et Date: Sun, 10 Apr 2016 13:41:04 -0500 Subject: [PATCH 03/22] JApplicationWeb::setHeader behavior Formatting changes --- libraries/joomla/application/web.php | 51 +++++++++++++++++----------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 96770e4ceae4d..a87e377bbbb16 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -624,25 +624,37 @@ public function setHeader($name, $value, $replace = false) // Sanitize the input values. $name = (string) $name; $value = (string) $value; + + // Create an array of names to search for duplicates + $key = false; + if(count($this->response->headers)) + { + $names = array(); + foreach($this->response->headers as $key => $header) + { + $names[$key] = $header['name']; + } + + // Find existing headers by name + $key = array_search($name,$names); + } - // create an array of names to search for duplicates - $key = false; - if(count($this->response->headers)) { - $names = array(); - foreach($this->response->headers as $key=>$header) { - $names[$key]=$header['name']; - } - $key = array_search($name,$names); // find existing headers by name - } - if($key !== false && $replace || $key === false) { // found & replace or not found - if($key !== false) { // remove before insert when header is found - unset($this->response->headers[$key]); - // Clean up the array as unsetting nested arrays leaves some junk. - $this->response->headers = array_values($this->response->headers); - } - // Add the header to the internal array. - $this->response->headers[] = array('name' => $name, 'value' => $value); - } + // Found & replace or not found + if($key !== false && $replace || $key === false) + { + + // remove before insert when header is found + if($key !== false) + { + unset($this->response->headers[$key]); + + // Clean up the array as unsetting nested arrays leaves some junk. + $this->response->headers = array_values($this->response->headers); + } + + // Add the header to the internal array. + $this->response->headers[] = array('name' => $name, 'value' => $value); + } return $this; } @@ -651,8 +663,7 @@ public function setHeader($name, $value, $replace = false) * Method to get the array of response headers to be sent when the response is sent * to the client. * - * @return array - * + * @return array * * @since 11.3 */ public function getHeaders() From b630e31efebe4b8ff25879ce9870ac92d4512293 Mon Sep 17 00:00:00 2001 From: stutteringp0et Date: Sun, 10 Apr 2016 13:50:59 -0500 Subject: [PATCH 04/22] JApplicationWeb::setHeader behavior Formatting issues --- libraries/joomla/application/web.php | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index a87e377bbbb16..e7ab9bd145e90 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -627,31 +627,31 @@ public function setHeader($name, $value, $replace = false) // Create an array of names to search for duplicates $key = false; - if(count($this->response->headers)) + if (count($this->response->headers)) { $names = array(); - foreach($this->response->headers as $key => $header) + foreach ($this->response->headers as $key => $header) { $names[$key] = $header['name']; } - + // Find existing headers by name - $key = array_search($name,$names); + $key = array_search($name, $names); } - + // Found & replace or not found - if($key !== false && $replace || $key === false) + if ($key !== false && $replace || $key === false) { - - // remove before insert when header is found - if($key !== false) - { + + // Remove before insert when header is found + if ($key !== false) + { unset($this->response->headers[$key]); - + // Clean up the array as unsetting nested arrays leaves some junk. $this->response->headers = array_values($this->response->headers); } - + // Add the header to the internal array. $this->response->headers[] = array('name' => $name, 'value' => $value); } @@ -664,6 +664,7 @@ public function setHeader($name, $value, $replace = false) * to the client. * * @return array * + * * @since 11.3 */ public function getHeaders() From 081e39a6ae7fe15a83b6da1e27961efc1d802021 Mon Sep 17 00:00:00 2001 From: stutteringp0et Date: Sun, 10 Apr 2016 14:23:55 -0500 Subject: [PATCH 05/22] Fix testSetHeader in line 1314 "$this->class->setHeader('foo', 'car');", the method is called without the $replace argument, meaning it uses the default of "false". The way headers are set, allowing a duplicate here means the header is replaced in JApplicationWeb::header. If $replace isn't enforced in setHeader then duplicates mean the header gets replaced anyway. The attempted entry is removed from the assertEquals test. --- .../libraries/joomla/application/JApplicationWebTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unit/suites/libraries/joomla/application/JApplicationWebTest.php b/tests/unit/suites/libraries/joomla/application/JApplicationWebTest.php index 9b624cce097e8..76f3c214ee1d2 100644 --- a/tests/unit/suites/libraries/joomla/application/JApplicationWebTest.php +++ b/tests/unit/suites/libraries/joomla/application/JApplicationWebTest.php @@ -1315,8 +1315,7 @@ public function testSetHeader() $this->assertEquals( array( - array('name' => 'foo', 'value' => 'bar'), - array('name' => 'foo', 'value' => 'car') + array('name' => 'foo', 'value' => 'bar') ), TestReflection::getValue($this->class, 'response')->headers ); From d1f22f6a310d2749da8340ad72d7fd129eb8eab2 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Sun, 10 Apr 2016 20:52:39 -0500 Subject: [PATCH 06/22] JApplicationWeb -setHeader and sendHeader upgrade Current Joomla header operation causes a duplicate header to replace an original header even when $replace = false. The replacement is a result of interaction between setHeader and sendHeader. setHeader happily adds duplicate entries when $replace = false sendHeader happily replaces headers because its default is to replace This commit alters both: setHeader now checks an internal list of headers which may only have one value. If the header is a single value only, the header array is updated only if $replace = true and the update is ignored otherwise If the header is not a single value, the header is replaced if $replace = true, otherwise it is added as a multiple value sendHeader now creates a new array of values, aggregating values under the header name. When the header is sent to the header() method, its value is imploded on ', ' --- libraries/joomla/application/web.php | 96 ++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 25 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index e7ab9bd145e90..0f3b02d57c723 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -92,6 +92,33 @@ class JApplicationWeb extends JApplicationBase 308 => 'Permanent Redirect' ); + /** + * A map of HTTP Response headers which may only send a single value, all others + * are considered to allow multiple + * + * @var object + * @since 3.5.2 + * @see https://tools.ietf.org/html/rfc7230 + */ + private $singleValueResponseHeaders = array( + 'status', // This is not a valid header name, but the representation used by Joomla to identify the HTTP Response Code + 'Content-Length', + 'Host', + 'Content-Type', + 'Content-Location', + 'Date', + 'Location', + 'Retry-After', + 'Server', + 'Mime-Version', + 'Last-Modified', + 'ETag', + 'Accept-Ranges', + 'Content-Range', + 'Age', + 'Expires' + ); + /** * Class constructor. * @@ -626,35 +653,44 @@ public function setHeader($name, $value, $replace = false) $value = (string) $value; // Create an array of names to search for duplicates - $key = false; - if (count($this->response->headers)) + $keys = false; + if ($this->response->headers) { $names = array(); foreach ($this->response->headers as $key => $header) { $names[$key] = $header['name']; } - // Find existing headers by name - $key = array_search($name, $names); + $keys = array_keys($names, $name); } - // Found & replace or not found - if ($key !== false && $replace || $key === false) - { - - // Remove before insert when header is found - if ($key !== false) - { - unset($this->response->headers[$key]); - - // Clean up the array as unsetting nested arrays leaves some junk. - $this->response->headers = array_values($this->response->headers); - } - - // Add the header to the internal array. - $this->response->headers[] = array('name' => $name, 'value' => $value); - } + // Remove existing values if they exist and replace is true + if($keys && $replace) + { + foreach($keys as $key) + { + unset($this->response->headers[$key]); + } + // Clean up the array as unsetting nested arrays leaves some junk. + $this->response->headers = array_values($this->response->headers); + } + + // If no keys found, safe to insert + if(!$keys || + // Or keys found and + ($keys && + // Replace is true or + ($replace || + // Header is a multiple value header and replace is null, indicating multiple insert + (!in_array($name, $this->singleValueResponseHeaders)) + ) + ) + ) + { + // Add the header to the internal array. + $this->response->headers[] = array('name' => $name, 'value' => $value); + } return $this; } @@ -697,18 +733,28 @@ public function sendHeaders() { if (!$this->checkHeadersSent()) { + // Creating an array of headers, making arrays of headers with multiple values + $headers = array(); foreach ($this->response->headers as $header) { - if ('status' == strtolower($header['name'])) + if(!array_key_exists($header['name'],$headers)) + { + $headers[$header['name']] = array(); + } + $headers[$header['name']][] = $header['value']; + } + foreach($headers as $name => $value) + { + if ('status' == strtolower($name)) { // 'status' headers indicate an HTTP status, and need to be handled slightly differently - $this->header('HTTP/1.1 ' . $header['value'], null, (int) $header['value']); + $this->header('HTTP/1.1 ' . $value, null, (int) $value); } else { - $this->header($header['name'] . ': ' . $header['value']); - } - } + $this->header($name . ': ' . implode(', ', $value), true); + } + } } return $this; From d128c399d65a1408ce7bde82c91f374fd8694cf5 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Sun, 10 Apr 2016 20:59:50 -0500 Subject: [PATCH 07/22] Returning test to original state this should be removed from the branch but I'm not sure how to do it. --- .../libraries/joomla/application/JApplicationWebTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/suites/libraries/joomla/application/JApplicationWebTest.php b/tests/unit/suites/libraries/joomla/application/JApplicationWebTest.php index 76f3c214ee1d2..9b624cce097e8 100644 --- a/tests/unit/suites/libraries/joomla/application/JApplicationWebTest.php +++ b/tests/unit/suites/libraries/joomla/application/JApplicationWebTest.php @@ -1315,7 +1315,8 @@ public function testSetHeader() $this->assertEquals( array( - array('name' => 'foo', 'value' => 'bar') + array('name' => 'foo', 'value' => 'bar'), + array('name' => 'foo', 'value' => 'car') ), TestReflection::getValue($this->class, 'response')->headers ); From 04d3a7595ed1330a4dacdd17888ef6dbd92f8677 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Sun, 10 Apr 2016 21:10:09 -0500 Subject: [PATCH 08/22] JApplicationWeb::setHeader behavior Update to fix status header --- libraries/joomla/application/web.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 0f3b02d57c723..492efe540b8a2 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -748,7 +748,7 @@ public function sendHeaders() if ('status' == strtolower($name)) { // 'status' headers indicate an HTTP status, and need to be handled slightly differently - $this->header('HTTP/1.1 ' . $value, null, (int) $value); + $this->header('HTTP/1.1 ' . $value, null, (int) $value[0]); } else { From ac353663f5238238cc5d6e5d00f6b2f0b786d602 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Sun, 10 Apr 2016 21:21:16 -0500 Subject: [PATCH 09/22] JApplicationWeb -setHeader and sendHeader upgrade Fixing for test output --- libraries/joomla/application/web.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 492efe540b8a2..f922a0ffcc222 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -737,23 +737,26 @@ public function sendHeaders() $headers = array(); foreach ($this->response->headers as $header) { - if(!array_key_exists($header['name'],$headers)) + if(array_key_exists($header['name'],$headers)) { - $headers[$header['name']] = array(); + $headers[$header['name']] = implode(', ',array($headers[$header['name']],$header['value'])); + } + else + { + $headers[$header['name']] = $header['value']; } - $headers[$header['name']][] = $header['value']; } foreach($headers as $name => $value) { if ('status' == strtolower($name)) { // 'status' headers indicate an HTTP status, and need to be handled slightly differently - $this->header('HTTP/1.1 ' . $value, null, (int) $value[0]); + $this->header('HTTP/1.1 ' . $value, null, (int) $value); } else { - $this->header($name . ': ' . implode(', ', $value), true); - } + $this->header($name . ': ' . $value, true); + } } } From 496388367790f368d51cf97a7cac9027777c8ae9 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Sun, 10 Apr 2016 21:38:53 -0500 Subject: [PATCH 10/22] JApplicationWeb -setHeader and sendHeader upgrade formatting --- libraries/joomla/application/web.php | 65 ++++++++++++---------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index f922a0ffcc222..b8f3b01caf784 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -92,7 +92,7 @@ class JApplicationWeb extends JApplicationBase 308 => 'Permanent Redirect' ); - /** + /** * A map of HTTP Response headers which may only send a single value, all others * are considered to allow multiple * @@ -100,24 +100,24 @@ class JApplicationWeb extends JApplicationBase * @since 3.5.2 * @see https://tools.ietf.org/html/rfc7230 */ - private $singleValueResponseHeaders = array( - 'status', // This is not a valid header name, but the representation used by Joomla to identify the HTTP Response Code - 'Content-Length', - 'Host', - 'Content-Type', - 'Content-Location', - 'Date', - 'Location', - 'Retry-After', - 'Server', - 'Mime-Version', - 'Last-Modified', - 'ETag', - 'Accept-Ranges', - 'Content-Range', - 'Age', - 'Expires' - ); + private $singleValueResponseHeaders = array( + 'status', // This is not a valid header name, but the representation used by Joomla to identify the HTTP Response Code + 'Content-Length', + 'Host', + 'Content-Type', + 'Content-Location', + 'Date', + 'Location', + 'Retry-After', + 'Server', + 'Mime-Version', + 'Last-Modified', + 'ETag', + 'Accept-Ranges', + 'Content-Range', + 'Age', + 'Expires' + ); /** * Class constructor. @@ -665,28 +665,19 @@ public function setHeader($name, $value, $replace = false) $keys = array_keys($names, $name); } - // Remove existing values if they exist and replace is true - if($keys && $replace) + // Remove existing values if they exist and replace is true + if ($keys && $replace) { - foreach($keys as $key) - { - unset($this->response->headers[$key]); - } - // Clean up the array as unsetting nested arrays leaves some junk. - $this->response->headers = array_values($this->response->headers); + foreach ($keys as $key) + { + unset($this->response->headers[$key]); + } + // Clean up the array as unsetting nested arrays leaves some junk. + $this->response->headers = array_values($this->response->headers); } // If no keys found, safe to insert - if(!$keys || - // Or keys found and - ($keys && - // Replace is true or - ($replace || - // Header is a multiple value header and replace is null, indicating multiple insert - (!in_array($name, $this->singleValueResponseHeaders)) - ) - ) - ) + if (!$keys || ($keys && ($replace || (!in_array($name, $this->singleValueResponseHeaders))))) { // Add the header to the internal array. $this->response->headers[] = array('name' => $name, 'value' => $value); From 74e854c26958182e73648cb67bdf7c409e246f6b Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Sun, 10 Apr 2016 21:50:00 -0500 Subject: [PATCH 11/22] JApplicationWeb -setHeader and sendHeader upgrade formatting --- libraries/joomla/application/web.php | 44 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index b8f3b01caf784..7d99448e5dbcf 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -667,21 +667,21 @@ public function setHeader($name, $value, $replace = false) // Remove existing values if they exist and replace is true if ($keys && $replace) - { + { foreach ($keys as $key) { unset($this->response->headers[$key]); } // Clean up the array as unsetting nested arrays leaves some junk. $this->response->headers = array_values($this->response->headers); - } + } - // If no keys found, safe to insert - if (!$keys || ($keys && ($replace || (!in_array($name, $this->singleValueResponseHeaders))))) - { - // Add the header to the internal array. - $this->response->headers[] = array('name' => $name, 'value' => $value); - } + // If no keys found, safe to insert + if (!$keys || ($keys && ($replace || (!in_array($name, $this->singleValueResponseHeaders))))) + { + // Add the header to the internal array. + $this->response->headers[] = array('name' => $name, 'value' => $value); + } return $this; } @@ -724,21 +724,21 @@ public function sendHeaders() { if (!$this->checkHeadersSent()) { - // Creating an array of headers, making arrays of headers with multiple values - $headers = array(); + // Creating an array of headers, making arrays of headers with multiple values + $headers = array(); foreach ($this->response->headers as $header) { - if(array_key_exists($header['name'],$headers)) - { - $headers[$header['name']] = implode(', ',array($headers[$header['name']],$header['value'])); - } - else - { - $headers[$header['name']] = $header['value']; - } + if (array_key_exists($header['name'], $headers)) + { + $headers[$header['name']] = implode(', ',array($headers[$header['name']], $header['value'])); + } + else + { + $headers[$header['name']] = $header['value']; + } } - foreach($headers as $name => $value) - { + foreach ($headers as $name => $value) + { if ('status' == strtolower($name)) { // 'status' headers indicate an HTTP status, and need to be handled slightly differently @@ -747,8 +747,8 @@ public function sendHeaders() else { $this->header($name . ': ' . $value, true); - } - } + } + } } return $this; From 3a1a134700a6b1c80d988235842e26a530131183 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Sun, 10 Apr 2016 21:57:43 -0500 Subject: [PATCH 12/22] JApplicationWeb -setHeader and sendHeader upgrade formatting --- libraries/joomla/application/web.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 7d99448e5dbcf..a3342d348db7d 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -730,9 +730,9 @@ public function sendHeaders() { if (array_key_exists($header['name'], $headers)) { - $headers[$header['name']] = implode(', ',array($headers[$header['name']], $header['value'])); + $headers[$header['name']] = implode(', ', array($headers[$header['name']], $header['value'])); } - else + else { $headers[$header['name']] = $header['value']; } From ea82d1c7a9429fe934624bbaf3a04040d0e3d952 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Mon, 11 Apr 2016 09:38:36 -0500 Subject: [PATCH 13/22] JApplicationWeb -setHeader and sendHeader upgrade refinement - removed unnecessary parens --- libraries/joomla/application/web.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index a3342d348db7d..e2f33733bc606 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -677,7 +677,7 @@ public function setHeader($name, $value, $replace = false) } // If no keys found, safe to insert - if (!$keys || ($keys && ($replace || (!in_array($name, $this->singleValueResponseHeaders))))) + if (!$keys || ($keys && ($replace || !in_array($name, $this->singleValueResponseHeaders)))) { // Add the header to the internal array. $this->response->headers[] = array('name' => $name, 'value' => $value); From 0ffc9e31d2265a819d359842ac47e456a26cb4b0 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Mon, 11 Apr 2016 11:46:18 -0500 Subject: [PATCH 14/22] JApplicationWeb -setHeader and sendHeader upgrade performance enhancement --- libraries/joomla/application/web.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index e2f33733bc606..6127261eeab4e 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -666,7 +666,7 @@ public function setHeader($name, $value, $replace = false) } // Remove existing values if they exist and replace is true - if ($keys && $replace) + if ($replace && $keys) { foreach ($keys as $key) { From 8c72577cb915c80e0c048a78a6c67f32c299847f Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Tue, 12 Apr 2016 15:02:47 -0500 Subject: [PATCH 15/22] JApplicationWeb -setHeader and sendHeader upgrade performance enhancements, 2 fewer foreach iterations for the headers --- libraries/joomla/application/web.php | 61 ++++++++++++---------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 6127261eeab4e..7cd7ef21a892f 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -652,7 +652,7 @@ public function setHeader($name, $value, $replace = false) $name = (string) $name; $value = (string) $value; - // Create an array of names to search for duplicates + // Create an array of duplicate header names $keys = false; if ($this->response->headers) { @@ -665,23 +665,22 @@ public function setHeader($name, $value, $replace = false) $keys = array_keys($names, $name); } - // Remove existing values if they exist and replace is true - if ($replace && $keys) - { - foreach ($keys as $key) - { - unset($this->response->headers[$key]); - } - // Clean up the array as unsetting nested arrays leaves some junk. - $this->response->headers = array_values($this->response->headers); - } - - // If no keys found, safe to insert - if (!$keys || ($keys && ($replace || !in_array($name, $this->singleValueResponseHeaders)))) - { + // Remove if $replace is true and there are duplicate names + if($replace && $keys) + { + $this->response->headers = array_diff_key($this->response->headers, array_flip($keys)); + } + + /** + * If no keys found, safe to insert (!$keys) + * If ($keys && $replace) it's a replacement and previous have been deleted + * if($keys && !in_array...) it's a multiple value header + */ + if(!$keys || ($keys && ($replace || !in_array($name, $this->singleValueResponseHeaders)))) + { // Add the header to the internal array. $this->response->headers[] = array('name' => $name, 'value' => $value); - } + } return $this; } @@ -724,31 +723,21 @@ public function sendHeaders() { if (!$this->checkHeadersSent()) { - // Creating an array of headers, making arrays of headers with multiple values - $headers = array(); - foreach ($this->response->headers as $header) - { - if (array_key_exists($header['name'], $headers)) - { - $headers[$header['name']] = implode(', ', array($headers[$header['name']], $header['value'])); - } - else - { - $headers[$header['name']] = $header['value']; - } - } - foreach ($headers as $name => $value) - { - if ('status' == strtolower($name)) + // Creating an array of headers, making arrays of headers with multiple values + $values = array(); + foreach($this->response->headers as $header) + { + if ('status' == strtolower($header['name'])) { // 'status' headers indicate an HTTP status, and need to be handled slightly differently - $this->header('HTTP/1.1 ' . $value, null, (int) $value); + $this->header('HTTP/1.1 ' . $value, null, (int) $header['value']); } else { - $this->header($name . ': ' . $value, true); - } - } + $values[$header['name']] = !array_key_exists($header['name'],$values)?$header['value']:implode(', ',array($values[$header['name']],$header['value'])); + $this->header($header['name'] . ': ' . $values[$header['name']], true); + } + } } return $this; From 78567ea114f7f5960f8f098c53a7b5aa81548384 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Tue, 12 Apr 2016 15:31:04 -0500 Subject: [PATCH 16/22] JApplicationWeb -setHeader and sendHeader upgrade formatting fix --- libraries/joomla/application/web.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 7cd7ef21a892f..b6c7ed0fcb936 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -668,7 +668,7 @@ public function setHeader($name, $value, $replace = false) // Remove if $replace is true and there are duplicate names if($replace && $keys) { - $this->response->headers = array_diff_key($this->response->headers, array_flip($keys)); + $this->response->headers = array_diff_key($this->response->headers, array_flip($keys)); } /** From 9033209a58496dc0011a9c5fb6966ca1d53de579 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Tue, 12 Apr 2016 15:38:44 -0500 Subject: [PATCH 17/22] JApplicationWeb -setHeader and sendHeader upgrade Missed a variable change i sendHeader --- libraries/joomla/application/web.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index b6c7ed0fcb936..f70612e831ffe 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -730,7 +730,7 @@ public function sendHeaders() if ('status' == strtolower($header['name'])) { // 'status' headers indicate an HTTP status, and need to be handled slightly differently - $this->header('HTTP/1.1 ' . $value, null, (int) $header['value']); + $this->header('HTTP/1.1 ' . $header['value'], null, (int) $header['value']); } else { From e15c8b3733267a0bf1c1be2d939fac86cda18775 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Tue, 12 Apr 2016 15:47:18 -0500 Subject: [PATCH 18/22] JApplicationWeb -setHeader and sendHeader upgrade formatting fix --- libraries/joomla/application/web.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index f70612e831ffe..e65d87914b3dd 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -734,7 +734,7 @@ public function sendHeaders() } else { - $values[$header['name']] = !array_key_exists($header['name'],$values)?$header['value']:implode(', ',array($values[$header['name']],$header['value'])); + $values[$header['name']] = !array_key_exists($header['name'],$values)?$header['value']:implode(', ',array($values[$header['name']],$header['value'])); $this->header($header['name'] . ': ' . $values[$header['name']], true); } } From cc8eda36376d71a0d36450c2e30260c1bb62e5c6 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Tue, 12 Apr 2016 22:43:35 -0500 Subject: [PATCH 19/22] Update web.php --- libraries/joomla/application/web.php | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index e65d87914b3dd..c852b3c62d646 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -665,22 +665,22 @@ public function setHeader($name, $value, $replace = false) $keys = array_keys($names, $name); } - // Remove if $replace is true and there are duplicate names - if($replace && $keys) + // Remove if $replace is true and there are duplicate names + if ($replace && $keys) { $this->response->headers = array_diff_key($this->response->headers, array_flip($keys)); - } + } - /** + /** * If no keys found, safe to insert (!$keys) * If ($keys && $replace) it's a replacement and previous have been deleted * if($keys && !in_array...) it's a multiple value header */ - if(!$keys || ($keys && ($replace || !in_array($name, $this->singleValueResponseHeaders)))) - { + if (!$keys || ($keys && ($replace || !in_array($name, $this->singleValueResponseHeaders)))) + { // Add the header to the internal array. $this->response->headers[] = array('name' => $name, 'value' => $value); - } + } return $this; } @@ -723,10 +723,10 @@ public function sendHeaders() { if (!$this->checkHeadersSent()) { - // Creating an array of headers, making arrays of headers with multiple values - $values = array(); - foreach($this->response->headers as $header) - { + // Creating an array of headers, making arrays of headers with multiple values + $vals = array(); + foreach ($this->response->headers as $header) + { if ('status' == strtolower($header['name'])) { // 'status' headers indicate an HTTP status, and need to be handled slightly differently @@ -734,10 +734,10 @@ public function sendHeaders() } else { - $values[$header['name']] = !array_key_exists($header['name'],$values)?$header['value']:implode(', ',array($values[$header['name']],$header['value'])); - $this->header($header['name'] . ': ' . $values[$header['name']], true); - } - } + $vals[$header['name']] = !array_key_exists($header['name'], $vals)?$header['value']:implode(', ', array($vals[$header['name']], $header['value'])); + $this->header($header['name'] . ': ' . $vals[$header['name']], true); + } + } } return $this; From c041cf7456198c07e452ace94b34869c34ac78e5 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Tue, 12 Apr 2016 23:01:49 -0500 Subject: [PATCH 20/22] JApplicationWeb -setHeader and sendHeader upgrade fix formatting --- libraries/joomla/application/web.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index c852b3c62d646..22e61637313c1 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -667,11 +667,11 @@ public function setHeader($name, $value, $replace = false) // Remove if $replace is true and there are duplicate names if ($replace && $keys) - { + { $this->response->headers = array_diff_key($this->response->headers, array_flip($keys)); } - /** + /** * If no keys found, safe to insert (!$keys) * If ($keys && $replace) it's a replacement and previous have been deleted * if($keys && !in_array...) it's a multiple value header @@ -724,7 +724,7 @@ public function sendHeaders() if (!$this->checkHeadersSent()) { // Creating an array of headers, making arrays of headers with multiple values - $vals = array(); + $val = array(); foreach ($this->response->headers as $header) { if ('status' == strtolower($header['name'])) @@ -734,8 +734,8 @@ public function sendHeaders() } else { - $vals[$header['name']] = !array_key_exists($header['name'], $vals)?$header['value']:implode(', ', array($vals[$header['name']], $header['value'])); - $this->header($header['name'] . ': ' . $vals[$header['name']], true); + $val[$header['name']] = !isset($val[$header['name']])?$header['value']:implode(', ', array($val[$header['name']], $header['value'])); + $this->header($header['name'] . ': ' . $val[$header['name']], true); } } } From a05bc9fd70ffb4a88a2c3943aab6426069651e9a Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Thu, 14 Apr 2016 12:10:49 -0500 Subject: [PATCH 21/22] JApplicationWeb -setHeader and sendHeader upgrade Adding ability to unset (remove) an existing header using $replace=true and $value=null setHeader('name', null, true) now removes the header entirely, where previous behavior would have sent the header with an empty value. --- libraries/joomla/application/web.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 22e61637313c1..760a43455f31a 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -676,7 +676,8 @@ public function setHeader($name, $value, $replace = false) * If ($keys && $replace) it's a replacement and previous have been deleted * if($keys && !in_array...) it's a multiple value header */ - if (!$keys || ($keys && ($replace || !in_array($name, $this->singleValueResponseHeaders)))) + $single = in_array($name, $this->singleValueResponseHeaders); + if ($value && (!$keys || ($keys && ($replace || !$single)))) { // Add the header to the internal array. $this->response->headers[] = array('name' => $name, 'value' => $value); From 3ee123a43d8bbd3848dc17a93e6c17aa57d4f006 Mon Sep 17 00:00:00 2001 From: Michael Richey Date: Thu, 14 Apr 2016 12:17:17 -0500 Subject: [PATCH 22/22] JApplicationWeb -setHeader and sendHeader upgrade formatting fix --- libraries/joomla/application/web.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/joomla/application/web.php b/libraries/joomla/application/web.php index 760a43455f31a..96d9546a4ae3f 100644 --- a/libraries/joomla/application/web.php +++ b/libraries/joomla/application/web.php @@ -676,7 +676,7 @@ public function setHeader($name, $value, $replace = false) * If ($keys && $replace) it's a replacement and previous have been deleted * if($keys && !in_array...) it's a multiple value header */ - $single = in_array($name, $this->singleValueResponseHeaders); + $single = in_array($name, $this->singleValueResponseHeaders); if ($value && (!$keys || ($keys && ($replace || !$single)))) { // Add the header to the internal array.