@@ -308,11 +308,21 @@ PHP_LIBXML_API zend_string *php_libxml_sniff_charset_from_stream(const php_strea
308
308
if (Z_TYPE (s -> wrapperdata ) == IS_ARRAY ) {
309
309
zval * header ;
310
310
311
- ZEND_HASH_FOREACH_VAL_IND (Z_ARRVAL (s -> wrapperdata ), header ) {
312
- const char buf [] = "Content-Type:" ;
313
- if (Z_TYPE_P (header ) == IS_STRING &&
314
- !zend_binary_strncasecmp (Z_STRVAL_P (header ), Z_STRLEN_P (header ), buf , sizeof (buf )- 1 , sizeof (buf )- 1 )) {
315
- return php_libxml_sniff_charset_from_string (Z_STRVAL_P (header ) + sizeof (buf ) - 1 , Z_STRVAL_P (header ) + Z_STRLEN_P (header ));
311
+ /* Scan backwards: The header array might contain the headers for multiple responses, if
312
+ * a redirect was followed.
313
+ */
314
+ ZEND_HASH_REVERSE_FOREACH_VAL_IND (Z_ARRVAL (s -> wrapperdata ), header ) {
315
+ if (Z_TYPE_P (header ) == IS_STRING ) {
316
+ /* If no colon is found in the header, we assume it's the HTTP status line and bail out. */
317
+ char * colon = memchr (Z_STRVAL_P (header ), ':' , Z_STRLEN_P (header ));
318
+ char * space = memchr (Z_STRVAL_P (header ), ' ' , Z_STRLEN_P (header ));
319
+ if (colon == NULL || space < colon ) {
320
+ return NULL ;
321
+ }
322
+
323
+ if (zend_string_starts_with_literal_ci (Z_STR_P (header ), "content-type:" )) {
324
+ return php_libxml_sniff_charset_from_string (Z_STRVAL_P (header ) + strlen ("content-type:" ), Z_STRVAL_P (header ) + Z_STRLEN_P (header ));
325
+ }
316
326
}
317
327
} ZEND_HASH_FOREACH_END ();
318
328
}
0 commit comments