Browse Source

Replicate the logic used to set Content-Type when transforming reponses

When converting responses into PSR7, we need to follow the same logic
when the Content-Type header has not already been set.

Refs #9315
Mark Story 9 years ago
parent
commit
8b424860d5
2 changed files with 81 additions and 4 deletions
  1. 36 1
      src/Http/ResponseTransformer.php
  2. 45 3
      tests/TestCase/Http/ResponseTransformerTest.php

+ 36 - 1
src/Http/ResponseTransformer.php

@@ -160,7 +160,7 @@ class ResponseTransformer
         $status = $response->statusCode();
         $headers = $response->header();
         if (!isset($headers['Content-Type'])) {
-            $headers['Content-Type'] = $response->type();
+            $headers = static::setContentType($headers, $response);
         }
         $cookies = $response->cookie();
         if ($cookies) {
@@ -183,6 +183,41 @@ class ResponseTransformer
     }
 
     /**
+     * Add in the Content-Type header if necessary.
+     *
+     * @param array $headers The headers to update
+     * @param CakeResponse $response The CakePHP response to convert
+     * @return The updated headers.
+     */
+    protected static function setContentType($headers, $response)
+    {
+        if (isset($headers['Content-Type'])) {
+            return $headers;
+        }
+        if (in_array($response->statusCode(), [204, 304])) {
+            return $headers;
+        }
+        $whitelist = [
+            'application/javascript', 'application/json', 'application/xml', 'application/rss+xml'
+        ];
+
+        $type = $response->type();
+        $charset = $response->charset();
+
+        $hasCharset = false;
+        if ($charset && (strpos($type, 'text/') === 0 || in_array($type, $whitelist))) {
+            $hasCharset = true;
+        }
+
+        $value = $type;
+        if ($hasCharset) {
+            $value = "{$type}; charset={$charset}";
+        }
+        $headers['Content-Type'] = $value;
+        return $headers;
+    }
+
+    /**
      * Convert an array of cookies into header lines.
      *
      * @param array $cookies The cookies to serialize.

+ 45 - 3
tests/TestCase/Http/ResponseTransformerTest.php

@@ -281,9 +281,51 @@ class ResponseTransformerTest extends TestCase
     public function testToPsrContentType()
     {
         $cake = new CakeResponse();
-        $cake->type('js');
+        $cake->type('html');
+        $cake->charset('utf-8');
         $result = ResponseTransformer::toPsr($cake);
-        $this->assertSame('application/javascript', $result->getHeaderLine('Content-Type'));
+        $this->assertSame('text/html; charset=utf-8', $result->getHeaderLine('Content-Type'));
+    }
+
+    /**
+     * Test conversion omitting content-type on 304 and 204 status codes
+     *
+     * @return void
+     */
+    public function testToPsrContentTypeStatusOmission()
+    {
+        $cake = new CakeResponse();
+        $cake->type('html');
+        $cake->statusCode(304);
+        $result = ResponseTransformer::toPsr($cake);
+        $this->assertSame('', $result->getHeaderLine('Content-Type'));
+
+        $cake->statusCode(204);
+        $result = ResponseTransformer::toPsr($cake);
+        $this->assertSame('', $result->getHeaderLine('Content-Type'));
+    }
+
+    /**
+     * Test conversion omitting content-type on 304 and 204 status codes
+     *
+     * @return void
+     */
+    public function testToPsrContentTypeCharsetIsTypeSpecific()
+    {
+        $cake = new CakeResponse();
+        $cake->charset('utf-8');
+
+        $cake->type('text/html');
+        $result = ResponseTransformer::toPsr($cake);
+        $this->assertSame('text/html; charset=utf-8', $result->getHeaderLine('Content-Type'));
+
+        $cake->type('application/octet-stream');
+        $result = ResponseTransformer::toPsr($cake);
+        $this->assertSame('application/octet-stream', $result->getHeaderLine('Content-Type'));
+
+        $cake->type('application/json');
+        $result = ResponseTransformer::toPsr($cake);
+        $this->assertSame('application/json; charset=utf-8', $result->getHeaderLine('Content-Type'));
     }
 
     /**
@@ -302,7 +344,7 @@ class ResponseTransformerTest extends TestCase
         $expected = [
             'X-testing' => ['one', 'two'],
             'Location' => ['http://example.com/testing'],
-            'Content-Type' => ['text/html'],
+            'Content-Type' => ['text/html; charset=UTF-8'],
         ];
         $this->assertSame($expected, $result->getHeaders());
     }