Skip to content

Commit 8b42486

Browse files
committed
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
1 parent 905c020 commit 8b42486

File tree

2 files changed

+81
-4
lines changed

2 files changed

+81
-4
lines changed

src/Http/ResponseTransformer.php

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public static function toPsr(CakeResponse $response)
160160
$status = $response->statusCode();
161161
$headers = $response->header();
162162
if (!isset($headers['Content-Type'])) {
163-
$headers['Content-Type'] = $response->type();
163+
$headers = static::setContentType($headers, $response);
164164
}
165165
$cookies = $response->cookie();
166166
if ($cookies) {
@@ -182,6 +182,41 @@ public static function toPsr(CakeResponse $response)
182182
return new DiactorosResponse($stream, $status, $headers);
183183
}
184184

185+
/**
186+
* Add in the Content-Type header if necessary.
187+
*
188+
* @param array $headers The headers to update
189+
* @param CakeResponse $response The CakePHP response to convert
190+
* @return The updated headers.
191+
*/
192+
protected static function setContentType($headers, $response)
193+
{
194+
if (isset($headers['Content-Type'])) {
195+
return $headers;
196+
}
197+
if (in_array($response->statusCode(), [204, 304])) {
198+
return $headers;
199+
}
200+
$whitelist = [
201+
'application/javascript', 'application/json', 'application/xml', 'application/rss+xml'
202+
];
203+
204+
$type = $response->type();
205+
$charset = $response->charset();
206+
207+
$hasCharset = false;
208+
if ($charset && (strpos($type, 'text/') === 0 || in_array($type, $whitelist))) {
209+
$hasCharset = true;
210+
}
211+
212+
$value = $type;
213+
if ($hasCharset) {
214+
$value = "{$type}; charset={$charset}";
215+
}
216+
$headers['Content-Type'] = $value;
217+
return $headers;
218+
}
219+
185220
/**
186221
* Convert an array of cookies into header lines.
187222
*

tests/TestCase/Http/ResponseTransformerTest.php

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,51 @@ public function testToPsrCookieAttributes()
281281
public function testToPsrContentType()
282282
{
283283
$cake = new CakeResponse();
284-
$cake->type('js');
284+
$cake->type('html');
285+
$cake->charset('utf-8');
285286
$result = ResponseTransformer::toPsr($cake);
286-
$this->assertSame('application/javascript', $result->getHeaderLine('Content-Type'));
287+
$this->assertSame('text/html; charset=utf-8', $result->getHeaderLine('Content-Type'));
288+
}
289+
290+
/**
291+
* Test conversion omitting content-type on 304 and 204 status codes
292+
*
293+
* @return void
294+
*/
295+
public function testToPsrContentTypeStatusOmission()
296+
{
297+
$cake = new CakeResponse();
298+
$cake->type('html');
299+
$cake->statusCode(304);
300+
$result = ResponseTransformer::toPsr($cake);
301+
$this->assertSame('', $result->getHeaderLine('Content-Type'));
302+
303+
$cake->statusCode(204);
304+
$result = ResponseTransformer::toPsr($cake);
305+
$this->assertSame('', $result->getHeaderLine('Content-Type'));
306+
}
307+
308+
/**
309+
* Test conversion omitting content-type on 304 and 204 status codes
310+
*
311+
* @return void
312+
*/
313+
public function testToPsrContentTypeCharsetIsTypeSpecific()
314+
{
315+
$cake = new CakeResponse();
316+
$cake->charset('utf-8');
317+
318+
$cake->type('text/html');
319+
$result = ResponseTransformer::toPsr($cake);
320+
$this->assertSame('text/html; charset=utf-8', $result->getHeaderLine('Content-Type'));
321+
322+
$cake->type('application/octet-stream');
323+
$result = ResponseTransformer::toPsr($cake);
324+
$this->assertSame('application/octet-stream', $result->getHeaderLine('Content-Type'));
325+
326+
$cake->type('application/json');
327+
$result = ResponseTransformer::toPsr($cake);
328+
$this->assertSame('application/json; charset=utf-8', $result->getHeaderLine('Content-Type'));
287329
}
288330

289331
/**
@@ -302,7 +344,7 @@ public function testToPsrHeaders()
302344
$expected = [
303345
'X-testing' => ['one', 'two'],
304346
'Location' => ['http://example.com/testing'],
305-
'Content-Type' => ['text/html'],
347+
'Content-Type' => ['text/html; charset=UTF-8'],
306348
];
307349
$this->assertSame($expected, $result->getHeaders());
308350
}

0 commit comments

Comments
 (0)