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
@@ -120,17 +121,15 @@ typedef struct _php_stream_http_response_header_info {
120
121
size_t file_size ;
121
122
bool error ;
122
123
bool follow_location ;
123
- char location [HTTP_HEADER_BLOCK_SIZE ];
124
+ char * location ;
125
+ size_t location_len ;
124
126
} php_stream_http_response_header_info ;
125
127
126
128
static void php_stream_http_response_header_info_init (
127
129
php_stream_http_response_header_info * header_info )
128
130
{
129
- header_info -> transfer_encoding = NULL ;
130
- header_info -> file_size = 0 ;
131
- header_info -> error = false;
131
+ memset (header_info , 0 , sizeof (php_stream_http_response_header_info ));
132
132
header_info -> follow_location = 1 ;
133
- header_info -> location [0 ] = '\0' ;
134
133
}
135
134
136
135
/* Trim white spaces from response header line and update its length */
@@ -256,7 +255,22 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w
256
255
* RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
257
256
header_info -> follow_location = 0 ;
258
257
}
259
- strlcpy (header_info -> location , last_header_value , sizeof (header_info -> location ));
258
+ size_t last_header_value_len = strlen (last_header_value );
259
+ if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE ) {
260
+ header_info -> error = true;
261
+ php_stream_wrapper_log_error (wrapper , options ,
262
+ "HTTP Location header size is over the limit of %d bytes" ,
263
+ HTTP_HEADER_MAX_LOCATION_SIZE );
264
+ zend_string_efree (last_header_line_str );
265
+ return NULL ;
266
+ }
267
+ if (header_info -> location_len == 0 ) {
268
+ header_info -> location = emalloc (last_header_value_len + 1 );
269
+ } else if (header_info -> location_len <= last_header_value_len ) {
270
+ header_info -> location = erealloc (header_info -> location , last_header_value_len + 1 );
271
+ }
272
+ header_info -> location_len = last_header_value_len ;
273
+ memcpy (header_info -> location , last_header_value , last_header_value_len + 1 );
260
274
} else if (!strncasecmp (last_header_line , "Content-Type:" , sizeof ("Content-Type:" )- 1 )) {
261
275
php_stream_notify_info (context , PHP_STREAM_NOTIFY_MIME_TYPE_IS , last_header_value , 0 );
262
276
} else if (!strncasecmp (last_header_line , "Content-Length:" , sizeof ("Content-Length:" )- 1 )) {
@@ -560,6 +574,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
560
574
}
561
575
}
562
576
577
+ php_stream_http_response_header_info_init (& header_info );
578
+
563
579
if (stream == NULL )
564
580
goto out ;
565
581
@@ -941,8 +957,6 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
941
957
}
942
958
}
943
959
944
- php_stream_http_response_header_info_init (& header_info );
945
-
946
960
/* read past HTTP headers */
947
961
while (!php_stream_eof (stream )) {
948
962
size_t http_header_line_length ;
@@ -1012,12 +1026,12 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1012
1026
last_header_line_str , NULL , NULL , response_code , response_header , & header_info );
1013
1027
}
1014
1028
1015
- if (!reqok || (header_info .location [ 0 ] != '\0' && header_info .follow_location )) {
1029
+ if (!reqok || (header_info .location != NULL && header_info .follow_location )) {
1016
1030
if (!header_info .follow_location || (((options & STREAM_ONLY_GET_HEADERS ) || ignore_errors ) && redirect_max <= 1 )) {
1017
1031
goto out ;
1018
1032
}
1019
1033
1020
- if (header_info .location [ 0 ] != '\0' )
1034
+ if (header_info .location != NULL )
1021
1035
php_stream_notify_info (context , PHP_STREAM_NOTIFY_REDIRECTED , header_info .location , 0 );
1022
1036
1023
1037
php_stream_close (stream );
@@ -1028,18 +1042,17 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1028
1042
header_info .transfer_encoding = NULL ;
1029
1043
}
1030
1044
1031
- if (header_info .location [ 0 ] != '\0' ) {
1045
+ if (header_info .location != NULL ) {
1032
1046
1033
- char new_path [HTTP_HEADER_BLOCK_SIZE ];
1034
- char loc_path [HTTP_HEADER_BLOCK_SIZE ];
1047
+ char * new_path = NULL ;
1035
1048
1036
- * new_path = '\0' ;
1037
1049
if (strlen (header_info .location ) < 8 ||
1038
1050
(strncasecmp (header_info .location , "http://" , sizeof ("http://" )- 1 ) &&
1039
1051
strncasecmp (header_info .location , "https://" , sizeof ("https://" )- 1 ) &&
1040
1052
strncasecmp (header_info .location , "ftp://" , sizeof ("ftp://" )- 1 ) &&
1041
1053
strncasecmp (header_info .location , "ftps://" , sizeof ("ftps://" )- 1 )))
1042
1054
{
1055
+ char * loc_path = NULL ;
1043
1056
if (* header_info .location != '/' ) {
1044
1057
if (* (header_info .location + 1 ) != '\0' && resource -> path ) {
1045
1058
char * s = strrchr (ZSTR_VAL (resource -> path ), '/' );
@@ -1057,31 +1070,35 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1057
1070
if (resource -> path &&
1058
1071
ZSTR_VAL (resource -> path )[0 ] == '/' &&
1059
1072
ZSTR_VAL (resource -> path )[1 ] == '\0' ) {
1060
- snprintf (loc_path , sizeof (loc_path ) - 1 , "%s%s" ,
1061
- ZSTR_VAL (resource -> path ), header_info .location );
1073
+ spprintf (& loc_path , 0 , "%s%s" , ZSTR_VAL (resource -> path ), header_info .location );
1062
1074
} else {
1063
- snprintf (loc_path , sizeof (loc_path ) - 1 , "%s/%s" ,
1064
- ZSTR_VAL (resource -> path ), header_info .location );
1075
+ spprintf (& loc_path , 0 , "%s/%s" , ZSTR_VAL (resource -> path ), header_info .location );
1065
1076
}
1066
1077
} else {
1067
- snprintf ( loc_path , sizeof ( loc_path ) - 1 , "/%s" , header_info .location );
1078
+ spprintf ( & loc_path , 0 , "/%s" , header_info .location );
1068
1079
}
1069
1080
} else {
1070
- strlcpy (loc_path , header_info .location , sizeof (loc_path ));
1081
+ loc_path = header_info .location ;
1082
+ header_info .location = NULL ;
1071
1083
}
1072
1084
if ((use_ssl && resource -> port != 443 ) || (!use_ssl && resource -> port != 80 )) {
1073
- snprintf (new_path , sizeof (new_path ) - 1 , "%s://%s:%d%s" , ZSTR_VAL (resource -> scheme ), ZSTR_VAL (resource -> host ), resource -> port , loc_path );
1085
+ spprintf (& new_path , 0 , "%s://%s:%d%s" , ZSTR_VAL (resource -> scheme ),
1086
+ ZSTR_VAL (resource -> host ), resource -> port , loc_path );
1074
1087
} else {
1075
- snprintf (new_path , sizeof (new_path ) - 1 , "%s://%s%s" , ZSTR_VAL (resource -> scheme ), ZSTR_VAL (resource -> host ), loc_path );
1088
+ spprintf (& new_path , 0 , "%s://%s%s" , ZSTR_VAL (resource -> scheme ),
1089
+ ZSTR_VAL (resource -> host ), loc_path );
1076
1090
}
1091
+ efree (loc_path );
1077
1092
} else {
1078
- strlcpy (new_path , header_info .location , sizeof (new_path ));
1093
+ new_path = header_info .location ;
1094
+ header_info .location = NULL ;
1079
1095
}
1080
1096
1081
1097
php_url_free (resource );
1082
1098
/* check for invalid redirection URLs */
1083
1099
if ((resource = php_url_parse (new_path )) == NULL ) {
1084
1100
php_stream_wrapper_log_error (wrapper , options , "Invalid redirect URL! %s" , new_path );
1101
+ efree (new_path );
1085
1102
goto out ;
1086
1103
}
1087
1104
@@ -1093,6 +1110,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1093
1110
while (s < e) { \
1094
1111
if (iscntrl(*s)) { \
1095
1112
php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); \
1113
+ efree(new_path); \
1096
1114
goto out; \
1097
1115
} \
1098
1116
s++; \
@@ -1115,6 +1133,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1115
1133
stream = php_stream_url_wrap_http_ex (
1116
1134
wrapper , new_path , mode , options , opened_path , context ,
1117
1135
-- redirect_max , new_flags , response_header STREAMS_CC );
1136
+ efree (new_path );
1118
1137
} else {
1119
1138
php_stream_wrapper_log_error (wrapper , options , "HTTP request failed! %s" , tmp_line );
1120
1139
}
@@ -1127,6 +1146,10 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
1127
1146
efree (http_header_line );
1128
1147
}
1129
1148
1149
+ if (header_info .location != NULL ) {
1150
+ efree (header_info .location );
1151
+ }
1152
+
1130
1153
if (resource ) {
1131
1154
php_url_free (resource );
1132
1155
}
0 commit comments