67
67
68
68
#include "php_fopen_wrappers.h"
69
69
70
- #define HTTP_HEADER_BLOCK_SIZE 1024
71
- #define PHP_URL_REDIRECT_MAX 20
72
- #define HTTP_HEADER_USER_AGENT 1
73
- #define HTTP_HEADER_HOST 2
74
- #define HTTP_HEADER_AUTH 4
75
- #define HTTP_HEADER_FROM 8
76
- #define HTTP_HEADER_CONTENT_LENGTH 16
77
- #define HTTP_HEADER_TYPE 32
78
- #define HTTP_HEADER_CONNECTION 64
70
+ #define HTTP_HEADER_BLOCK_SIZE 1024
71
+ #define HTTP_HEADER_MAX_LOCATION_SIZE 8182 /* 8192 - 10 (size of "Location: ") */
72
+ #define PHP_URL_REDIRECT_MAX 20
73
+ #define HTTP_HEADER_USER_AGENT 1
74
+ #define HTTP_HEADER_HOST 2
75
+ #define HTTP_HEADER_AUTH 4
76
+ #define HTTP_HEADER_FROM 8
77
+ #define HTTP_HEADER_CONTENT_LENGTH 16
78
+ #define HTTP_HEADER_TYPE 32
79
+ #define HTTP_HEADER_CONNECTION 64
79
80
80
81
#define HTTP_WRAPPER_HEADER_INIT 1
81
82
#define HTTP_WRAPPER_REDIRECTED 2
@@ -119,17 +120,15 @@ typedef struct _php_stream_http_response_header_info {
119
120
size_t file_size ;
120
121
bool error ;
121
122
bool follow_location ;
122
- char location [HTTP_HEADER_BLOCK_SIZE ];
123
+ char * location ;
124
+ size_t location_len ;
123
125
} php_stream_http_response_header_info ;
124
126
125
127
static void php_stream_http_response_header_info_init (
126
128
php_stream_http_response_header_info * header_info )
127
129
{
128
- header_info -> transfer_encoding = NULL ;
129
- header_info -> file_size = 0 ;
130
- header_info -> error = false;
130
+ memset (header_info , 0 , sizeof (php_stream_http_response_header_info ));
131
131
header_info -> follow_location = 1 ;
132
- header_info -> location [0 ] = '\0' ;
133
132
}
134
133
135
134
/* Trim white spaces from response header line and update its length */
@@ -255,7 +254,22 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w
255
254
* RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
256
255
header_info -> follow_location = 0 ;
257
256
}
258
- strlcpy (header_info -> location , last_header_value , sizeof (header_info -> location ));
257
+ size_t last_header_value_len = strlen (last_header_value );
258
+ if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE ) {
259
+ header_info -> error = true;
260
+ php_stream_wrapper_log_error (wrapper , options ,
261
+ "HTTP Location header size is over the limit of %d bytes" ,
262
+ HTTP_HEADER_MAX_LOCATION_SIZE );
263
+ zend_string_efree (last_header_line_str );
264
+ return NULL ;
265
+ }
266
+ if (header_info -> location_len == 0 ) {
267
+ header_info -> location = emalloc (last_header_value_len + 1 );
268
+ } else if (header_info -> location_len <= last_header_value_len ) {
269
+ header_info -> location = erealloc (header_info -> location , last_header_value_len + 1 );
270
+ }
271
+ header_info -> location_len = last_header_value_len ;
272
+ memcpy (header_info -> location , last_header_value , last_header_value_len + 1 );
259
273
} else if (!strncasecmp (last_header_line , "Content-Type:" , sizeof ("Content-Type:" )- 1 )) {
260
274
php_stream_notify_info (context , PHP_STREAM_NOTIFY_MIME_TYPE_IS , last_header_value , 0 );
261
275
} else if (!strncasecmp (last_header_line , "Content-Length:" , sizeof ("Content-Length:" )- 1 )) {
@@ -538,6 +552,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
538
552
}
539
553
}
540
554
555
+ php_stream_http_response_header_info_init (& header_info );
556
+
541
557
if (stream == NULL )
542
558
goto out ;
543
559
@@ -919,8 +935,6 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
919
935
}
920
936
}
921
937
922
- php_stream_http_response_header_info_init (& header_info );
923
-
924
938
/* read past HTTP headers */
925
939
while (!php_stream_eof (stream )) {
926
940
size_t http_header_line_length ;
@@ -990,12 +1004,12 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
990
1004
last_header_line_str , NULL , NULL , response_code , response_header , & header_info );
991
1005
}
992
1006
993
- if (!reqok || (header_info .location [ 0 ] != '\0' && header_info .follow_location )) {
1007
+ if (!reqok || (header_info .location != NULL && header_info .follow_location )) {
994
1008
if (!header_info .follow_location || (((options & STREAM_ONLY_GET_HEADERS ) || ignore_errors ) && redirect_max <= 1 )) {
995
1009
goto out ;
996
1010
}
997
1011
998
- if (header_info .location [ 0 ] != '\0' )
1012
+ if (header_info .location != NULL )
999
1013
php_stream_notify_info (context , PHP_STREAM_NOTIFY_REDIRECTED , header_info .location , 0 );
1000
1014
1001
1015
php_stream_close (stream );
@@ -1006,18 +1020,17 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1006
1020
header_info .transfer_encoding = NULL ;
1007
1021
}
1008
1022
1009
- if (header_info .location [ 0 ] != '\0' ) {
1023
+ if (header_info .location != NULL ) {
1010
1024
1011
- char new_path [HTTP_HEADER_BLOCK_SIZE ];
1012
- char loc_path [HTTP_HEADER_BLOCK_SIZE ];
1025
+ char * new_path = NULL ;
1013
1026
1014
- * new_path = '\0' ;
1015
1027
if (strlen (header_info .location ) < 8 ||
1016
1028
(strncasecmp (header_info .location , "http://" , sizeof ("http://" )- 1 ) &&
1017
1029
strncasecmp (header_info .location , "https://" , sizeof ("https://" )- 1 ) &&
1018
1030
strncasecmp (header_info .location , "ftp://" , sizeof ("ftp://" )- 1 ) &&
1019
1031
strncasecmp (header_info .location , "ftps://" , sizeof ("ftps://" )- 1 )))
1020
1032
{
1033
+ char * loc_path = NULL ;
1021
1034
if (* header_info .location != '/' ) {
1022
1035
if (* (header_info .location + 1 ) != '\0' && resource -> path ) {
1023
1036
char * s = strrchr (ZSTR_VAL (resource -> path ), '/' );
@@ -1035,31 +1048,35 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1035
1048
if (resource -> path &&
1036
1049
ZSTR_VAL (resource -> path )[0 ] == '/' &&
1037
1050
ZSTR_VAL (resource -> path )[1 ] == '\0' ) {
1038
- snprintf (loc_path , sizeof (loc_path ) - 1 , "%s%s" ,
1039
- ZSTR_VAL (resource -> path ), header_info .location );
1051
+ spprintf (& loc_path , 0 , "%s%s" , ZSTR_VAL (resource -> path ), header_info .location );
1040
1052
} else {
1041
- snprintf (loc_path , sizeof (loc_path ) - 1 , "%s/%s" ,
1042
- ZSTR_VAL (resource -> path ), header_info .location );
1053
+ spprintf (& loc_path , 0 , "%s/%s" , ZSTR_VAL (resource -> path ), header_info .location );
1043
1054
}
1044
1055
} else {
1045
- snprintf ( loc_path , sizeof ( loc_path ) - 1 , "/%s" , header_info .location );
1056
+ spprintf ( & loc_path , 0 , "/%s" , header_info .location );
1046
1057
}
1047
1058
} else {
1048
- strlcpy (loc_path , header_info .location , sizeof (loc_path ));
1059
+ loc_path = header_info .location ;
1060
+ header_info .location = NULL ;
1049
1061
}
1050
1062
if ((use_ssl && resource -> port != 443 ) || (!use_ssl && resource -> port != 80 )) {
1051
- snprintf (new_path , sizeof (new_path ) - 1 , "%s://%s:%d%s" , ZSTR_VAL (resource -> scheme ), ZSTR_VAL (resource -> host ), resource -> port , loc_path );
1063
+ spprintf (& new_path , 0 , "%s://%s:%d%s" , ZSTR_VAL (resource -> scheme ),
1064
+ ZSTR_VAL (resource -> host ), resource -> port , loc_path );
1052
1065
} else {
1053
- snprintf (new_path , sizeof (new_path ) - 1 , "%s://%s%s" , ZSTR_VAL (resource -> scheme ), ZSTR_VAL (resource -> host ), loc_path );
1066
+ spprintf (& new_path , 0 , "%s://%s%s" , ZSTR_VAL (resource -> scheme ),
1067
+ ZSTR_VAL (resource -> host ), loc_path );
1054
1068
}
1069
+ efree (loc_path );
1055
1070
} else {
1056
- strlcpy (new_path , header_info .location , sizeof (new_path ));
1071
+ new_path = header_info .location ;
1072
+ header_info .location = NULL ;
1057
1073
}
1058
1074
1059
1075
php_url_free (resource );
1060
1076
/* check for invalid redirection URLs */
1061
1077
if ((resource = php_url_parse (new_path )) == NULL ) {
1062
1078
php_stream_wrapper_log_error (wrapper , options , "Invalid redirect URL! %s" , new_path );
1079
+ efree (new_path );
1063
1080
goto out ;
1064
1081
}
1065
1082
@@ -1071,6 +1088,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1071
1088
while (s < e) { \
1072
1089
if (iscntrl(*s)) { \
1073
1090
php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); \
1091
+ efree(new_path); \
1074
1092
goto out; \
1075
1093
} \
1076
1094
s++; \
@@ -1086,6 +1104,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1086
1104
stream = php_stream_url_wrap_http_ex (
1087
1105
wrapper , new_path , mode , options , opened_path , context ,
1088
1106
-- redirect_max , HTTP_WRAPPER_REDIRECTED , response_header STREAMS_CC );
1107
+ efree (new_path );
1089
1108
} else {
1090
1109
php_stream_wrapper_log_error (wrapper , options , "HTTP request failed! %s" , tmp_line );
1091
1110
}
@@ -1098,6 +1117,10 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1098
1117
efree (http_header_line );
1099
1118
}
1100
1119
1120
+ if (header_info .location != NULL ) {
1121
+ efree (header_info .location );
1122
+ }
1123
+
1101
1124
if (resource ) {
1102
1125
php_url_free (resource );
1103
1126
}
0 commit comments