@@ -146,6 +146,7 @@ static zend_result php_stream_handle_proxy_authorization_header(const char *s, s
146146typedef struct _php_stream_http_response_header_info {
147147 php_stream_filter * transfer_encoding ;
148148 size_t file_size ;
149+ bool error ;
149150 bool follow_location ;
150151 char location [HTTP_HEADER_BLOCK_SIZE ];
151152} php_stream_http_response_header_info ;
@@ -155,6 +156,7 @@ static void php_stream_http_response_header_info_init(
155156{
156157 header_info -> transfer_encoding = NULL ;
157158 header_info -> file_size = 0 ;
159+ header_info -> error = false;
158160 header_info -> follow_location = 1 ;
159161 header_info -> location [0 ] = '\0' ;
160162}
@@ -192,10 +194,11 @@ static bool php_stream_http_response_header_trim(char *http_header_line,
192194/* Process folding headers of the current line and if there are none, parse last full response
193195 * header line. It returns NULL if the last header is finished, otherwise it returns updated
194196 * last header line. */
195- static zend_string * php_stream_http_response_headers_parse (php_stream * stream ,
196- php_stream_context * context , int options , zend_string * last_header_line_str ,
197- char * header_line , size_t * header_line_length , int response_code ,
198- zval * response_header , php_stream_http_response_header_info * header_info )
197+ static zend_string * php_stream_http_response_headers_parse (php_stream_wrapper * wrapper ,
198+ php_stream * stream , php_stream_context * context , int options ,
199+ zend_string * last_header_line_str , char * header_line , size_t * header_line_length ,
200+ int response_code , zval * response_header ,
201+ php_stream_http_response_header_info * header_info )
199202{
200203 char * last_header_line = ZSTR_VAL (last_header_line_str );
201204 size_t last_header_line_length = ZSTR_LEN (last_header_line_str );
@@ -237,6 +240,19 @@ static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
237240 /* Find header separator position. */
238241 char * last_header_value = memchr (last_header_line , ':' , last_header_line_length );
239242 if (last_header_value ) {
243+ /* Verify there is no space in header name */
244+ char * last_header_name = last_header_line + 1 ;
245+ while (last_header_name < last_header_value ) {
246+ if (* last_header_name == ' ' || * last_header_name == '\t' ) {
247+ header_info -> error = true;
248+ php_stream_wrapper_log_error (wrapper , options ,
249+ "HTTP invalid response format (space in header name)!" );
250+ zend_string_efree (last_header_line_str );
251+ return NULL ;
252+ }
253+ ++ last_header_name ;
254+ }
255+
240256 last_header_value ++ ; /* Skip ':'. */
241257
242258 /* Strip leading whitespace. */
@@ -245,9 +261,12 @@ static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
245261 last_header_value ++ ;
246262 }
247263 } else {
248- /* There is no colon. Set the value to the end of the header line, which is effectively
249- * an empty string. */
250- last_header_value = last_header_line_end ;
264+ /* There is no colon which means invalid response so error. */
265+ header_info -> error = true;
266+ php_stream_wrapper_log_error (wrapper , options ,
267+ "HTTP invalid response format (no colon in header line)!" );
268+ zend_string_efree (last_header_line_str );
269+ return NULL ;
251270 }
252271
253272 bool store_header = true;
@@ -944,10 +963,16 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
944963
945964 if (last_header_line_str != NULL ) {
946965 /* Parse last header line. */
947- last_header_line_str = php_stream_http_response_headers_parse (stream , context ,
948- options , last_header_line_str , http_header_line , & http_header_line_length ,
949- response_code , response_header , & header_info );
950- if (last_header_line_str != NULL ) {
966+ last_header_line_str = php_stream_http_response_headers_parse (wrapper , stream ,
967+ context , options , last_header_line_str , http_header_line ,
968+ & http_header_line_length , response_code , response_header , & header_info );
969+ if (EXPECTED (last_header_line_str == NULL )) {
970+ if (UNEXPECTED (header_info .error )) {
971+ php_stream_close (stream );
972+ stream = NULL ;
973+ goto out ;
974+ }
975+ } else {
951976 /* Folding header present so continue. */
952977 continue ;
953978 }
@@ -977,8 +1002,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
9771002
9781003 /* If the stream was closed early, we still want to process the last line to keep BC. */
9791004 if (last_header_line_str != NULL ) {
980- php_stream_http_response_headers_parse (stream , context , options , last_header_line_str ,
981- NULL , NULL , response_code , response_header , & header_info );
1005+ php_stream_http_response_headers_parse (wrapper , stream , context , options ,
1006+ last_header_line_str , NULL , NULL , response_code , response_header , & header_info );
9821007 }
9831008
9841009 if (!reqok || (header_info .location [0 ] != '\0' && header_info .follow_location )) {
0 commit comments