php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
http.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Sara Golemon <pollita@php.net> |
14 +----------------------------------------------------------------------+
15*/
16
17#include "php_http.h"
18#include "php_ini.h"
19#include "url.h"
20#include "SAPI.h"
21#include "zend_exceptions.h"
22#include "basic_functions.h"
23#include "zend_enum.h"
24
25static void php_url_encode_scalar(zval *scalar, smart_str *form_str,
26 int encoding_type, zend_ulong index_int,
27 const char *index_string, size_t index_string_len,
28 const char *num_prefix, size_t num_prefix_len,
29 const zend_string *key_prefix,
30 const zend_string *arg_sep)
31{
32 if (form_str->s) {
33 smart_str_append(form_str, arg_sep);
34 }
35 /* Simple key=value */
36 if (key_prefix) {
37 smart_str_append(form_str, key_prefix);
38 }
39 if (index_string) {
40 zend_string *encoded_key;
41 if (encoding_type == PHP_QUERY_RFC3986) {
42 encoded_key = php_raw_url_encode(index_string, index_string_len);
43 } else {
44 encoded_key = php_url_encode(index_string, index_string_len);
45 }
46 smart_str_append(form_str, encoded_key);
47 zend_string_free(encoded_key);
48 } else {
49 /* Numeric key */
50 if (num_prefix) {
51 smart_str_appendl(form_str, num_prefix, num_prefix_len);
52 }
53 smart_str_append_long(form_str, index_int);
54 }
55 if (key_prefix) {
56 smart_str_appendl(form_str, "%5D", strlen("%5D"));
57 }
58 smart_str_appendc(form_str, '=');
59
60try_again:
61 switch (Z_TYPE_P(scalar)) {
62 case IS_STRING: {
63 zend_string *encoded_data;
64 if (encoding_type == PHP_QUERY_RFC3986) {
65 encoded_data = php_raw_url_encode(Z_STRVAL_P(scalar), Z_STRLEN_P(scalar));
66 } else {
67 encoded_data = php_url_encode(Z_STRVAL_P(scalar), Z_STRLEN_P(scalar));
68 }
69 smart_str_append(form_str, encoded_data);
70 zend_string_free(encoded_data);
71 break;
72 }
73 case IS_LONG:
74 smart_str_append_long(form_str, Z_LVAL_P(scalar));
75 break;
76 case IS_DOUBLE: {
77 zend_string *encoded_data;
79 if (encoding_type == PHP_QUERY_RFC3986) {
80 encoded_data = php_raw_url_encode(ZSTR_VAL(tmp), ZSTR_LEN(tmp));
81 } else {
82 encoded_data = php_url_encode(ZSTR_VAL(tmp), ZSTR_LEN(tmp));
83 }
84 smart_str_append(form_str, encoded_data);
85 zend_string_free(tmp);
86 zend_string_free(encoded_data);
87 break;
88 }
89 case IS_FALSE:
90 smart_str_appendc(form_str, '0');
91 break;
92 case IS_TRUE:
93 smart_str_appendc(form_str, '1');
94 break;
95 case IS_OBJECT:
96 ZEND_ASSERT(Z_OBJCE_P(scalar)->ce_flags & ZEND_ACC_ENUM);
97 if (Z_OBJCE_P(scalar)->enum_backing_type == IS_UNDEF) {
98 zend_value_error("Unbacked enum %s cannot be converted to a string", ZSTR_VAL(Z_OBJCE_P(scalar)->name));
99 return;
100 }
101 scalar = zend_enum_fetch_case_value(Z_OBJ_P(scalar));
102 goto try_again;
103 /* All possible types are either handled here or previously */
105 }
106}
107
108/* {{{ php_url_encode_hash */
110 const char *num_prefix, size_t num_prefix_len,
111 const zend_string *key_prefix,
112 zval *type, const zend_string *arg_sep, int enc_type)
113{
115 const char *prop_name;
116 size_t prop_len;
117 zend_ulong idx;
118 zval *zdata = NULL;
120
121 if (GC_IS_RECURSIVE(ht)) {
122 /* Prevent recursion */
123 return;
124 }
125
126 if (!arg_sep) {
127 arg_sep = zend_ini_str("arg_separator.output", strlen("arg_separator.output"), false);
128 if (ZSTR_LEN(arg_sep) == 0) {
129 arg_sep = ZSTR_CHAR('&');
130 }
131 }
132
133 ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, zdata) {
134 bool is_dynamic = 1;
135 if (Z_TYPE_P(zdata) == IS_INDIRECT) {
136 zdata = Z_INDIRECT_P(zdata);
137 if (Z_ISUNDEF_P(zdata)) {
138 continue;
139 }
140
141 is_dynamic = 0;
142 }
143
144 /* handling for private & protected object properties */
145 if (key) {
146 prop_name = ZSTR_VAL(key);
147 prop_len = ZSTR_LEN(key);
148
149 if (type != NULL && zend_check_property_access(Z_OBJ_P(type), key, is_dynamic) != SUCCESS) {
150 /* property not visible in this scope */
151 continue;
152 }
153
154 if (ZSTR_VAL(key)[0] == '\0' && type != NULL) {
155 const char *tmp;
156 zend_unmangle_property_name_ex(key, &tmp, &prop_name, &prop_len);
157 } else {
158 prop_name = ZSTR_VAL(key);
159 prop_len = ZSTR_LEN(key);
160 }
161 } else {
162 prop_name = NULL;
163 prop_len = 0;
164 }
165
166 ZVAL_DEREF(zdata);
167 if (Z_TYPE_P(zdata) == IS_ARRAY
168 || (Z_TYPE_P(zdata) == IS_OBJECT
169 && !(Z_OBJCE_P(zdata)->ce_flags & ZEND_ACC_ENUM))) {
170 zend_string *new_prefix;
171 if (key) {
172 zend_string *encoded_key;
173 if (enc_type == PHP_QUERY_RFC3986) {
174 encoded_key = php_raw_url_encode(prop_name, prop_len);
175 } else {
176 encoded_key = php_url_encode(prop_name, prop_len);
177 }
178
179 if (key_prefix) {
180 new_prefix = zend_string_concat3(ZSTR_VAL(key_prefix), ZSTR_LEN(key_prefix), ZSTR_VAL(encoded_key), ZSTR_LEN(encoded_key), "%5D%5B", strlen("%5D%5B"));
181 } else {
182 new_prefix = zend_string_concat2(ZSTR_VAL(encoded_key), ZSTR_LEN(encoded_key), "%5B", strlen("%5B"));
183 }
184 zend_string_release_ex(encoded_key, false);
185 } else { /* is integer index */
186 char *index_int_as_str;
187 size_t index_int_as_str_len;
188
189 index_int_as_str_len = spprintf(&index_int_as_str, 0, ZEND_LONG_FMT, idx);
190
191 if (key_prefix && num_prefix) {
192 /* zend_string_concat4() */
193 size_t len = ZSTR_LEN(key_prefix) + num_prefix_len + index_int_as_str_len + strlen("%5D%5B");
194 new_prefix = zend_string_alloc(len, 0);
195
196 memcpy(ZSTR_VAL(new_prefix), ZSTR_VAL(key_prefix), ZSTR_LEN(key_prefix));
197 memcpy(ZSTR_VAL(new_prefix) + ZSTR_LEN(key_prefix), num_prefix, num_prefix_len);
198 memcpy(ZSTR_VAL(new_prefix) + ZSTR_LEN(key_prefix) + num_prefix_len, index_int_as_str, index_int_as_str_len);
199 memcpy(ZSTR_VAL(new_prefix) + ZSTR_LEN(key_prefix) + num_prefix_len +index_int_as_str_len, "%5D%5B", strlen("%5D%5B"));
200 ZSTR_VAL(new_prefix)[len] = '\0';
201 } else if (key_prefix) {
202 new_prefix = zend_string_concat3(ZSTR_VAL(key_prefix), ZSTR_LEN(key_prefix), index_int_as_str, index_int_as_str_len, "%5D%5B", strlen("%5D%5B"));
203 } else if (num_prefix) {
204 new_prefix = zend_string_concat3(num_prefix, num_prefix_len, index_int_as_str, index_int_as_str_len, "%5B", strlen("%5B"));
205 } else {
206 new_prefix = zend_string_concat2(index_int_as_str, index_int_as_str_len, "%5B", strlen("%5B"));
207 }
208 efree(index_int_as_str);
209 }
211 php_url_encode_hash_ex(HASH_OF(zdata), formstr, NULL, 0, new_prefix, (Z_TYPE_P(zdata) == IS_OBJECT ? zdata : NULL), arg_sep, enc_type);
213 zend_string_release_ex(new_prefix, false);
214 } else if (Z_TYPE_P(zdata) == IS_NULL || Z_TYPE_P(zdata) == IS_RESOURCE) {
215 /* Skip these types */
216 continue;
217 } else {
218 php_url_encode_scalar(zdata, formstr,
219 enc_type, idx,
220 prop_name, prop_len,
221 num_prefix, num_prefix_len,
222 key_prefix,
223 arg_sep);
224 }
226}
227/* }}} */
228
229 /* If there is a prefix we need to close the key with an encoded ] ("%5D") */
230/* {{{ Generates a form-encoded query string from an associative array or object. */
232{
233 zval *formdata;
234 char *prefix = NULL;
235 size_t prefix_len = 0;
236 zend_string *arg_sep = NULL;
237 smart_str formstr = {0};
238 zend_long enc_type = PHP_QUERY_RFC1738;
239
243 Z_PARAM_STRING(prefix, prefix_len)
244 Z_PARAM_STR_OR_NULL(arg_sep)
245 Z_PARAM_LONG(enc_type)
247
248 if (UNEXPECTED(Z_TYPE_P(formdata) == IS_OBJECT && (Z_OBJCE_P(formdata)->ce_flags & ZEND_ACC_ENUM))) {
249 zend_argument_type_error(1, "must not be an enum, %s given", zend_zval_value_name(formdata));
251 }
252
253 php_url_encode_hash_ex(HASH_OF(formdata), &formstr, prefix, prefix_len, /* key_prefix */ NULL, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL), arg_sep, (int)enc_type);
254
255 RETURN_STR(smart_str_extract(&formstr));
256}
257/* }}} */
258
259static zend_result cache_request_parse_body_option(HashTable *options, zval *option, int cache_offset)
260{
261 if (option) {
263 ZVAL_DEREF(option);
264 if (Z_TYPE_P(option) == IS_STRING) {
265 zend_string *errstr;
266 result = zend_ini_parse_quantity(Z_STR_P(option), &errstr);
267 if (errstr) {
268 zend_error(E_WARNING, "%s", ZSTR_VAL(errstr));
269 zend_string_release(errstr);
270 }
271 } else if (Z_TYPE_P(option) == IS_LONG) {
272 result = Z_LVAL_P(option);
273 } else {
274 zend_value_error("Invalid %s value in $options argument", zend_zval_value_name(option));
275 return FAILURE;
276 }
277 SG(request_parse_body_context).options_cache[cache_offset].set = true;
278 SG(request_parse_body_context).options_cache[cache_offset].value = result;
279 } else {
280 SG(request_parse_body_context).options_cache[cache_offset].set = false;
281 }
282
283 return SUCCESS;
284}
285
286static zend_result cache_request_parse_body_options(HashTable *options)
287{
289 zval *value;
291 if (!key) {
292 zend_value_error("Invalid integer key in $options argument");
293 return FAILURE;
294 }
295 if (ZSTR_LEN(key) == 0) {
296 zend_value_error("Invalid empty string key in $options argument");
297 return FAILURE;
298 }
299
300#define CHECK_OPTION(name) \
301 if (zend_string_equals_literal_ci(key, #name)) { \
302 if (cache_request_parse_body_option(options, value, REQUEST_PARSE_BODY_OPTION_ ## name) == FAILURE) { \
303 return FAILURE; \
304 } \
305 continue; \
306 }
307
308 switch (ZSTR_VAL(key)[0]) {
309 case 'm':
310 case 'M':
311 CHECK_OPTION(max_file_uploads);
312 CHECK_OPTION(max_input_vars);
313 CHECK_OPTION(max_multipart_body_parts);
314 break;
315 case 'p':
316 case 'P':
317 CHECK_OPTION(post_max_size);
318 break;
319 case 'u':
320 case 'U':
321 CHECK_OPTION(upload_max_filesize);
322 break;
323 }
324
325 zend_value_error("Invalid key \"%s\" in $options argument", ZSTR_VAL(key));
326 return FAILURE;
328
329#undef CACHE_OPTION
330
331 return SUCCESS;
332}
333
335{
337
342
343 SG(request_parse_body_context).throw_exceptions = true;
344 if (options) {
345 if (cache_request_parse_body_options(options) == FAILURE) {
346 goto exit;
347 }
348 }
349
350 if (!SG(request_info).content_type) {
351 zend_throw_error(zend_ce_request_parse_body_exception, "Request does not provide a content type");
352 goto exit;
353 }
354
356 if (!SG(request_info).post_entry) {
357 zend_throw_error(zend_ce_request_parse_body_exception, "Content-Type \"%s\" is not supported", SG(request_info).content_type);
358 goto exit;
359 }
360
361 zval post, files, old_post, old_files;
362 zval *global_post = &PG(http_globals)[TRACK_VARS_POST];
363 zval *global_files = &PG(http_globals)[TRACK_VARS_FILES];
364
365 ZVAL_COPY_VALUE(&old_post, global_post);
366 ZVAL_COPY_VALUE(&old_files, global_files);
367 array_init(global_post);
368 array_init(global_files);
369 sapi_handle_post(global_post);
370 ZVAL_COPY_VALUE(&post, global_post);
371 ZVAL_COPY_VALUE(&files, global_files);
372 ZVAL_COPY_VALUE(global_post, &old_post);
373 ZVAL_COPY_VALUE(global_files, &old_files);
374
375 RETVAL_ARR(zend_new_pair(&post, &files));
376
377exit:
378 SG(request_parse_body_context).throw_exceptions = false;
379 memset(&SG(request_parse_body_context).options_cache, 0, sizeof(SG(request_parse_body_context).options_cache));
380}
381
383{
386 }
387
388 if (!Z_ISUNDEF(BG(last_http_headers))) {
389 RETURN_COPY(&BG(last_http_headers));
390 } else {
391 RETURN_NULL();
392 }
393}
394
396{
399 }
400
401 zval_ptr_dtor(&BG(last_http_headers));
402 ZVAL_UNDEF(&BG(last_http_headers));
403}
SAPI_API void sapi_read_post_data(void)
Definition SAPI.c:170
SAPI_API void sapi_handle_post(void *arg)
Definition SAPI.c:161
#define SG(v)
Definition SAPI.h:160
size_t len
Definition apprentice.c:174
#define BG(v)
http_clear_last_response_headers()
http_get_last_response_headers()
request_parse_body(?array $options=null)
http_build_query(array|object $data, string $numeric_prefix="", ?string $arg_separator=null, int $encoding_type=PHP_QUERY_RFC1738)
zend_ffi_type * type
Definition ffi.c:3812
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
HashTable * ht
Definition ffi.c:4838
#define NULL
Definition gdcache.h:45
#define prefix
#define SUCCESS
Definition hash_sha3.c:261
#define CHECK_OPTION(name)
PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, const char *num_prefix, size_t num_prefix_len, const zend_string *key_prefix, zval *type, const zend_string *arg_sep, int enc_type)
Definition http.c:109
#define PHP_FUNCTION
Definition php.h:364
#define PHPAPI
Definition php.h:71
#define TRACK_VARS_POST
Definition php_globals.h:40
#define TRACK_VARS_FILES
Definition php_globals.h:45
#define PG(v)
Definition php_globals.h:31
PHP_JSON_API size_t int options
Definition php_json.h:102
unsigned char key[REFLECTION_KEY_LEN]
#define spprintf
Definition spprintf.h:29
zend_string * s
PHPAPI zend_string * php_raw_url_encode(char const *s, size_t len)
Definition url.c:608
PHPAPI zend_string * php_url_encode(char const *s, size_t len)
Definition url.c:546
#define PHP_QUERY_RFC3986
Definition url.h:50
#define PHP_QUERY_RFC1738
Definition url.h:49
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
Definition zend.c:1666
ZEND_API const char * zend_zval_value_name(const zval *arg)
Definition zend_API.c:148
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:423
#define RETURN_COPY(zv)
Definition zend_API.h:1054
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define Z_PARAM_ARRAY_HT_OR_NULL(dest)
Definition zend_API.h:1855
#define Z_PARAM_STR_OR_NULL(dest)
Definition zend_API.h:2089
#define RETURN_NULL()
Definition zend_API.h:1036
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define zend_parse_parameters_none()
Definition zend_API.h:353
#define Z_PARAM_STRING(dest, dest_len)
Definition zend_API.h:2071
#define RETVAL_ARR(r)
Definition zend_API.h:1024
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define RETURN_THROWS()
Definition zend_API.h:1060
#define HASH_OF(p)
Definition zend_API.h:1062
#define RETURN_STR(s)
Definition zend_API.h:1039
#define Z_PARAM_ARRAY_OR_OBJECT(dest)
Definition zend_API.h:1700
#define array_init(arg)
Definition zend_API.h:537
#define efree(ptr)
Definition zend_alloc.h:155
struct _zval_struct zval
strlen(string $string)
exit(string|int $status=0)
zend_string_release_ex(func->internal_function.function_name, 0)
ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, const char **class_name, const char **prop_name, size_t *prop_len)
#define ZEND_ACC_ENUM
#define E_WARNING
Definition zend_errors.h:24
ZEND_API zend_class_entry * zend_ce_request_parse_body_exception
ZEND_API HashTable *ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2)
Definition zend_hash.c:296
#define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val)
Definition zend_hash.h:1181
#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val)
Definition zend_hash.h:1166
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr)
Definition zend_ini.c:857
ZEND_API zend_string * zend_ini_str(const char *name, size_t name_length, bool orig)
Definition zend_ini.c:545
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
ZEND_API zend_result zend_check_property_access(const zend_object *zobj, zend_string *prop_info_name, bool is_dynamic)
ZEND_API zend_string *ZEND_FASTCALL zend_double_to_str(double num)
#define ZEND_ASSERT(c)
#define EMPTY_SWITCH_DEFAULT_CASE()
#define UNEXPECTED(condition)
ZEND_API zend_string * zend_string_concat2(const char *str1, size_t str1_len, const char *str2, size_t str2_len)
ZEND_API zend_string * zend_string_concat3(const char *str1, size_t str1_len, const char *str2, size_t str2_len, const char *str3, size_t str3_len)
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define ZSTR_CHAR(c)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_TRUE
Definition zend_types.h:603
#define ZVAL_UNDEF(z)
#define IS_FALSE
Definition zend_types.h:602
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define Z_ISUNDEF_P(zval_p)
Definition zend_types.h:957
#define ZVAL_DEREF(z)
#define IS_STRING
Definition zend_types.h:606
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_RESOURCE
Definition zend_types.h:609
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define GC_TRY_UNPROTECT_RECURSION(p)
Definition zend_types.h:880
#define IS_NULL
Definition zend_types.h:601
#define Z_OBJCE_P(zval_p)
@ FAILURE
Definition zend_types.h:61
#define IS_OBJECT
Definition zend_types.h:608
#define GC_TRY_PROTECT_RECURSION(p)
Definition zend_types.h:876
#define IS_LONG
Definition zend_types.h:604
#define Z_INDIRECT_P(zval_p)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define GC_IS_RECURSIVE(p)
Definition zend_types.h:865
#define Z_DVAL_P(zval_p)
Definition zend_types.h:969
#define IS_INDIRECT
Definition zend_types.h:623
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zend_string * name
bool result
value