Browse Source

A bug in PHP prevents the headers from correctly beeing sent when a content-type header is present and
NOT at the end of the array

https://bugs.php.net/bug.php?id=61548

This updates fixes the array by moving the content-type header to the end

Markus Tacker 12 years ago
parent
commit
821f57f443

+ 24 - 0
src/Composer/Util/StreamContextFactory.php

@@ -82,6 +82,30 @@ final class StreamContextFactory
 
         $options = array_replace_recursive($options, $defaultOptions);
 
+        if (isset($options['http']['header'])) {
+            $options['http']['header'] = self::fixHttpHeaderField($options['http']['header']);
+        }
+
         return stream_context_create($options, $defaultParams);
     }
+
+    /**
+     * A bug in PHP prevents the headers from correctly beeing sent when a content-type header is present and
+     * NOT at the end of the array
+     *
+     * This method fixes the array by moving the content-type header to the end
+     *
+     * @link https://bugs.php.net/bug.php?id=61548
+     * @param $header
+     * @return array
+     * @author Markus Tacker <m@coderbyheart.de>
+     */
+    public static function fixHttpHeaderField($header)
+    {
+        if (!is_array($header)) $header = explode("\r\n", $header);
+        uasort($header, function ($el) {
+            return preg_match('/^content-type/i', $el) ? 1 : -1;
+        });
+        return $header;
+    }
 }

+ 24 - 0
tests/Composer/Test/Util/StreamContextFactoryTest.php

@@ -133,4 +133,28 @@ class StreamContextFactoryTest extends \PHPUnit_Framework_TestCase
             array('ssl://proxyserver:8443', 'https://proxyserver:8443'),
         );
     }
+
+    /**
+     * @author Markus Tacker <m@coderbyheart.de>
+     */
+    public function testEnsureThatfixHttpHeaderFieldMovesContentTypeToEndOfOptions()
+    {
+        $options = array(
+            'http' => array(
+                'header' => "X-Foo: bar\r\nContent-Type: application/json\r\nAuthorization: Basic aW52YWxpZA=="
+            )
+        );
+        $expectedOptions = array(
+            'http' => array(
+                'header' => array(
+                    "X-Foo: bar",
+                    "Authorization: Basic aW52YWxpZA==",
+                    "Content-Type: application/json"
+                )
+            )
+        );
+        $context = StreamContextFactory::getContext($options);
+        $ctxoptions = stream_context_get_options($context);
+        $this->assertEquals(join("\n", $ctxoptions['http']['header']), join("\n", $expectedOptions['http']['header']));
+    }
 }