Coverage Report

Created: 2025-07-23 06:33

/src/php-src/ext/uri/php_uri.c
Line
Count
Source (jump to first uncovered line)
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: Máté Kocsis <kocsismate@php.net>                            |
14
   +----------------------------------------------------------------------+
15
*/
16
17
#ifdef HAVE_CONFIG_H
18
# include <config.h>
19
#endif
20
21
#include "php.h"
22
#include "Zend/zend_interfaces.h"
23
#include "Zend/zend_exceptions.h"
24
#include "Zend/zend_attributes.h"
25
#include "Zend/zend_enum.h"
26
#include "ext/standard/info.h"
27
28
#include "php_uri_common.h"
29
#include "php_lexbor.h"
30
#include "php_uriparser.h"
31
#include "php_uri_arginfo.h"
32
#include "uriparser/src/UriConfig.h"
33
34
zend_class_entry *uri_rfc3986_uri_ce;
35
zend_object_handlers uri_rfc3986_uri_object_handlers;
36
zend_class_entry *uri_whatwg_url_ce;
37
zend_object_handlers uri_whatwg_uri_object_handlers;
38
zend_class_entry *uri_comparison_mode_ce;
39
zend_class_entry *uri_exception_ce;
40
zend_class_entry *uri_invalid_uri_exception_ce;
41
zend_class_entry *uri_whatwg_invalid_url_exception_ce;
42
zend_class_entry *uri_whatwg_url_validation_error_type_ce;
43
zend_class_entry *uri_whatwg_url_validation_error_ce;
44
45
11
#define URIPARSER_VERSION PACKAGE_VERSION
46
47
static const zend_module_dep uri_deps[] = {
48
  ZEND_MOD_REQUIRED("lexbor")
49
  ZEND_MOD_END
50
};
51
52
static zend_array uri_handlers;
53
54
static uri_handler_t *uri_handler_by_name(const char *handler_name, size_t handler_name_len)
55
0
{
56
0
  return zend_hash_str_find_ptr(&uri_handlers, handler_name, handler_name_len);
57
0
}
58
59
static HashTable *uri_get_debug_properties(zend_object *object)
60
0
{
61
0
  uri_internal_t *internal_uri = uri_internal_from_obj(object);
62
0
  ZEND_ASSERT(internal_uri != NULL);
63
64
0
  HashTable *std_properties = zend_std_get_properties(object);
65
0
  HashTable *result = zend_array_dup(std_properties);
66
67
0
  if (UNEXPECTED(internal_uri->uri == NULL)) {
68
0
    return result;
69
0
  }
70
71
0
  const uri_property_handlers_t property_handlers = internal_uri->handler->property_handlers;
72
73
0
  zval tmp;
74
0
  if (property_handlers.scheme.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
75
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_SCHEME), &tmp);
76
0
  }
77
78
0
  if (property_handlers.username.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
79
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_USERNAME), &tmp);
80
0
  }
81
82
0
  if (property_handlers.password.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
83
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PASSWORD), &tmp);
84
0
  }
85
86
0
  if (property_handlers.host.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
87
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_HOST), &tmp);
88
0
  }
89
90
0
  if (property_handlers.port.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
91
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PORT), &tmp);
92
0
  }
93
94
0
  if (property_handlers.path.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
95
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PATH), &tmp);
96
0
  }
97
98
0
  if (property_handlers.query.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
99
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_QUERY), &tmp);
100
0
  }
101
102
0
  if (property_handlers.fragment.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
103
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_FRAGMENT), &tmp);
104
0
  }
105
106
0
  return result;
107
0
}
108
109
/**
110
 * Pass the errors parameter by ref to errors_zv for userland, and frees it if
111
 * it is not not needed anymore.
112
 */
113
static zend_result pass_errors_by_ref_and_free(zval *errors_zv, zval *errors)
114
0
{
115
0
  ZEND_ASSERT(Z_TYPE_P(errors) == IS_UNDEF || Z_TYPE_P(errors) == IS_ARRAY);
116
117
  /* There was no error during parsing */
118
0
  if (Z_ISUNDEF_P(errors)) {
119
0
    return SUCCESS;
120
0
  }
121
122
  /* The errors parameter is an array, but the pass-by ref argument stored by
123
   * errors_zv was not passed - the URI implementation either doesn't support
124
   * returning additional error information, or the caller is not interested in it */
125
0
  if (errors_zv == NULL) {
126
0
    zval_ptr_dtor(errors);
127
0
    return SUCCESS;
128
0
  }
129
130
0
  ZEND_TRY_ASSIGN_REF_ARR(errors_zv, Z_ARRVAL_P(errors));
131
0
  if (EG(exception)) {
132
0
    zval_ptr_dtor(errors);
133
0
    return FAILURE;
134
0
  }
135
136
0
  return SUCCESS;
137
0
}
138
139
PHPAPI void php_uri_instantiate_uri(
140
  INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_object *base_url_object,
141
  bool should_throw, bool should_update_this_object, zval *errors_zv
142
0
) {
143
0
  zval errors;
144
0
  ZVAL_UNDEF(&errors);
145
146
0
  void *base_url = NULL;
147
0
  if (base_url_object != NULL) {
148
0
    uri_internal_t *internal_base_url = uri_internal_from_obj(base_url_object);
149
0
    URI_ASSERT_INITIALIZATION(internal_base_url);
150
0
    base_url = internal_base_url->uri;
151
0
  }
152
153
0
  void *uri = handler->parse_uri(uri_str, base_url, should_throw || errors_zv != NULL ? &errors : NULL, !should_throw);
154
0
  if (UNEXPECTED(uri == NULL)) {
155
0
    if (should_throw) {
156
0
      zval_ptr_dtor(&errors);
157
0
      RETURN_THROWS();
158
0
    } else {
159
0
      if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) {
160
0
        RETURN_THROWS();
161
0
      }
162
0
      RETURN_NULL();
163
0
    }
164
0
  }
165
166
0
  if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) {
167
0
    RETURN_THROWS();
168
0
  }
169
170
0
  uri_object_t *uri_object;
171
0
  if (should_update_this_object) {
172
0
    uri_object = Z_URI_OBJECT_P(ZEND_THIS);
173
0
  } else {
174
0
    if (EX(func)->common.fn_flags & ZEND_ACC_STATIC) {
175
0
      object_init_ex(return_value, Z_CE_P(ZEND_THIS));
176
0
    } else {
177
0
      object_init_ex(return_value, Z_OBJCE_P(ZEND_THIS));
178
0
    }
179
0
    uri_object = Z_URI_OBJECT_P(return_value);
180
0
  }
181
182
0
  uri_object->internal.handler = handler;
183
0
  uri_object->internal.uri = uri;
184
0
}
185
186
static void create_rfc3986_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
187
5
{
188
5
  zend_string *uri_str;
189
5
  zend_object *base_url_object = NULL;
190
191
10
  ZEND_PARSE_PARAMETERS_START(1, 2)
192
10
    Z_PARAM_PATH_STR(uri_str)
193
0
    Z_PARAM_OPTIONAL
194
0
    Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, uri_rfc3986_uri_ce)
195
5
  ZEND_PARSE_PARAMETERS_END();
196
197
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &uriparser_uri_handler, uri_str, base_url_object, is_constructor, is_constructor, NULL);
198
0
}
199
200
PHP_METHOD(Uri_Rfc3986_Uri, parse)
201
0
{
202
0
  create_rfc3986_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
203
0
}
204
205
PHP_METHOD(Uri_Rfc3986_Uri, __construct)
206
5
{
207
5
  create_rfc3986_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
208
5
}
209
210
PHP_METHOD(Uri_WhatWg_InvalidUrlException, __construct)
211
5
{
212
5
  zend_string *message = NULL;
213
5
  zval *errors = NULL;
214
5
  zend_long code = 0;
215
5
  zval *previous = NULL;
216
217
15
  ZEND_PARSE_PARAMETERS_START(0, 4)
218
15
    Z_PARAM_OPTIONAL
219
15
    Z_PARAM_STR(message)
220
0
    Z_PARAM_ARRAY(errors)
221
0
    Z_PARAM_LONG(code)
222
0
    Z_PARAM_OBJECT_OF_CLASS_OR_NULL(previous, zend_ce_throwable)
223
5
  ZEND_PARSE_PARAMETERS_END();
224
225
5
  if (zend_update_exception_properties(INTERNAL_FUNCTION_PARAM_PASSTHRU, message, code, previous) == FAILURE) {
226
0
    RETURN_THROWS();
227
0
  }
228
229
5
  if (errors == NULL) {
230
5
    zval tmp;
231
5
    ZVAL_EMPTY_ARRAY(&tmp);
232
5
    zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp);
233
5
  } else {
234
0
    zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), errors);
235
0
  }
236
5
  if (EG(exception)) {
237
0
    RETURN_THROWS();
238
0
  }
239
5
}
240
241
PHP_METHOD(Uri_WhatWg_UrlValidationError, __construct)
242
5
{
243
5
  zend_string *context;
244
5
  zval *type;
245
5
  bool failure;
246
247
10
  ZEND_PARSE_PARAMETERS_START(3, 3)
248
10
    Z_PARAM_STR(context)
249
0
    Z_PARAM_OBJECT_OF_CLASS(type, uri_whatwg_url_validation_error_type_ce)
250
0
    Z_PARAM_BOOL(failure)
251
5
  ZEND_PARSE_PARAMETERS_END();
252
253
0
  zend_update_property_str(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context);
254
0
  if (EG(exception)) {
255
0
    RETURN_THROWS();
256
0
  }
257
258
0
  zend_update_property_ex(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_TYPE), type);
259
0
  if (EG(exception)) {
260
0
    RETURN_THROWS();
261
0
  }
262
263
0
  zval failure_zv;
264
0
  ZVAL_BOOL(&failure_zv, failure);
265
0
  zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("failure"), &failure_zv);
266
0
  if (EG(exception)) {
267
0
    RETURN_THROWS();
268
0
  }
269
0
}
270
271
static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
272
5
{
273
5
  zend_string *uri_str;
274
5
  zend_object *base_url_object = NULL;
275
5
  zval *errors = NULL;
276
277
10
  ZEND_PARSE_PARAMETERS_START(1, 3)
278
10
    Z_PARAM_PATH_STR(uri_str)
279
0
    Z_PARAM_OPTIONAL
280
0
    Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, uri_whatwg_url_ce)
281
0
    Z_PARAM_ZVAL(errors)
282
5
  ZEND_PARSE_PARAMETERS_END();
283
284
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &lexbor_uri_handler, uri_str, base_url_object, is_constructor, is_constructor, errors);
285
0
}
286
287
PHP_METHOD(Uri_WhatWg_Url, parse)
288
0
{
289
0
  create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
290
0
}
291
292
PHP_METHOD(Uri_WhatWg_Url, __construct)
293
5
{
294
5
  create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
295
5
}
296
297
PHP_METHOD(Uri_Rfc3986_Uri, getScheme)
298
0
{
299
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII);
300
0
}
301
302
PHP_METHOD(Uri_Rfc3986_Uri, getRawScheme)
303
0
{
304
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_RAW);
305
0
}
306
307
static void read_uriparser_userinfo(INTERNAL_FUNCTION_PARAMETERS, uri_component_read_mode_t read_mode)
308
0
{
309
0
  ZEND_PARSE_PARAMETERS_NONE();
310
311
0
  uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS);
312
0
  URI_ASSERT_INITIALIZATION(internal_uri);
313
314
0
  if (UNEXPECTED(uriparser_read_userinfo(internal_uri, read_mode, return_value) == FAILURE)) {
315
0
    zend_throw_error(NULL, "The userinfo component cannot be retrieved");
316
0
    RETURN_THROWS();
317
0
  }
318
0
}
319
320
PHP_METHOD(Uri_Rfc3986_Uri, getUserInfo)
321
0
{
322
0
  read_uriparser_userinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_NORMALIZED_ASCII);
323
0
}
324
325
PHP_METHOD(Uri_Rfc3986_Uri, getRawUserInfo)
326
0
{
327
0
  read_uriparser_userinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_RAW);
328
0
}
329
330
PHP_METHOD(Uri_Rfc3986_Uri, getUsername)
331
0
{
332
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_NORMALIZED_ASCII);
333
0
}
334
335
PHP_METHOD(Uri_Rfc3986_Uri, getRawUsername)
336
0
{
337
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_RAW);
338
0
}
339
340
PHP_METHOD(Uri_Rfc3986_Uri, getPassword)
341
0
{
342
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_NORMALIZED_ASCII);
343
0
}
344
345
PHP_METHOD(Uri_Rfc3986_Uri, getRawPassword)
346
0
{
347
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_RAW);
348
0
}
349
350
PHP_METHOD(Uri_Rfc3986_Uri, getHost)
351
0
{
352
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_ASCII);
353
0
}
354
355
PHP_METHOD(Uri_Rfc3986_Uri, getRawHost)
356
0
{
357
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_RAW);
358
0
}
359
360
PHP_METHOD(Uri_Rfc3986_Uri, getPort)
361
0
{
362
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT, URI_COMPONENT_READ_NORMALIZED_ASCII);
363
0
}
364
365
PHP_METHOD(Uri_Rfc3986_Uri, getPath)
366
0
{
367
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_NORMALIZED_ASCII);
368
0
}
369
370
PHP_METHOD(Uri_Rfc3986_Uri, getRawPath)
371
0
{
372
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_RAW);
373
0
}
374
375
PHP_METHOD(Uri_Rfc3986_Uri, getQuery)
376
0
{
377
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_NORMALIZED_ASCII);
378
0
}
379
380
PHP_METHOD(Uri_Rfc3986_Uri, getRawQuery)
381
0
{
382
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_RAW);
383
0
}
384
385
PHP_METHOD(Uri_Rfc3986_Uri, getFragment)
386
0
{
387
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_ASCII);
388
0
}
389
390
PHP_METHOD(Uri_Rfc3986_Uri, getRawFragment)
391
0
{
392
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_RAW);
393
0
}
394
395
static void throw_cannot_recompose_uri_to_string(zend_object *object)
396
0
{
397
0
  zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->ce->name));
398
0
}
399
400
static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, zend_object *comparison_mode)
401
0
{
402
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
403
0
  uri_internal_t *this_internal_uri = uri_internal_from_obj(this_object);
404
0
  URI_ASSERT_INITIALIZATION(this_internal_uri);
405
406
0
  uri_internal_t *that_internal_uri = uri_internal_from_obj(that_object);
407
0
  URI_ASSERT_INITIALIZATION(that_internal_uri);
408
409
0
  if (this_object->ce != that_object->ce &&
410
0
    !instanceof_function(this_object->ce, that_object->ce) &&
411
0
    !instanceof_function(that_object->ce, this_object->ce)
412
0
  ) {
413
0
    RETURN_FALSE;
414
0
  }
415
416
0
  bool exclude_fragment = true;
417
0
  if (comparison_mode) {
418
0
    zval *case_name = zend_enum_fetch_case_name(comparison_mode);
419
0
    exclude_fragment = zend_string_equals_literal(Z_STR_P(case_name), "ExcludeFragment");
420
0
  }
421
422
0
  zend_string *this_str = this_internal_uri->handler->uri_to_string(
423
0
    this_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment);
424
0
  if (this_str == NULL) {
425
0
    throw_cannot_recompose_uri_to_string(this_object);
426
0
    RETURN_THROWS();
427
0
  }
428
429
0
  zend_string *that_str = that_internal_uri->handler->uri_to_string(
430
0
    that_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment);
431
0
  if (that_str == NULL) {
432
0
    zend_string_release(this_str);
433
0
    throw_cannot_recompose_uri_to_string(that_object);
434
0
    RETURN_THROWS();
435
0
  }
436
437
0
  RETVAL_BOOL(zend_string_equals(this_str, that_str));
438
439
0
  zend_string_release(this_str);
440
0
  zend_string_release(that_str);
441
0
}
442
443
PHP_METHOD(Uri_Rfc3986_Uri, equals)
444
0
{
445
0
  zend_object *that_object;
446
0
  zend_object *comparison_mode = NULL;
447
448
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
449
0
    Z_PARAM_OBJ_OF_CLASS(that_object, uri_rfc3986_uri_ce)
450
0
    Z_PARAM_OPTIONAL
451
0
    Z_PARAM_OBJ_OF_CLASS(comparison_mode, uri_comparison_mode_ce)
452
0
  ZEND_PARSE_PARAMETERS_END();
453
454
0
  uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, that_object, comparison_mode);
455
0
}
456
457
PHP_METHOD(Uri_Rfc3986_Uri, toRawString)
458
0
{
459
0
  ZEND_PARSE_PARAMETERS_NONE();
460
461
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
462
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
463
0
  URI_ASSERT_INITIALIZATION(internal_uri);
464
465
0
  zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false);
466
0
  if (uri_str == NULL) {
467
0
    throw_cannot_recompose_uri_to_string(this_object);
468
0
    RETURN_THROWS();
469
0
  }
470
471
0
  RETURN_STR(uri_str);
472
0
}
473
474
PHP_METHOD(Uri_Rfc3986_Uri, toString)
475
0
{
476
0
  ZEND_PARSE_PARAMETERS_NONE();
477
478
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
479
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
480
0
  URI_ASSERT_INITIALIZATION(internal_uri);
481
482
0
  zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, false);
483
0
  if (uri_str == NULL) {
484
0
    throw_cannot_recompose_uri_to_string(this_object);
485
0
    RETURN_THROWS();
486
0
  }
487
488
0
  RETURN_STR(uri_str);
489
0
}
490
491
PHP_METHOD(Uri_Rfc3986_Uri, resolve)
492
0
{
493
0
  zend_string *uri_str;
494
495
0
  ZEND_PARSE_PARAMETERS_START(1, 1)
496
0
    Z_PARAM_PATH_STR(uri_str)
497
0
  ZEND_PARSE_PARAMETERS_END();
498
499
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
500
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
501
0
  URI_ASSERT_INITIALIZATION(internal_uri);
502
503
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal_uri->handler, uri_str, this_object, true, false, NULL);
504
0
}
505
506
PHP_METHOD(Uri_Rfc3986_Uri, __serialize)
507
0
{
508
0
  ZEND_PARSE_PARAMETERS_NONE();
509
510
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
511
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
512
0
  URI_ASSERT_INITIALIZATION(internal_uri);
513
514
  /* Serialize state: "uri" key in the first array */
515
0
  zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false);
516
0
  if (uri_str == NULL) {
517
0
    throw_cannot_recompose_uri_to_string(this_object);
518
0
    RETURN_THROWS();
519
0
  }
520
0
  zval tmp;
521
0
  ZVAL_STR(&tmp, uri_str);
522
523
0
  array_init(return_value);
524
525
0
  zval arr;
526
0
  array_init(&arr);
527
0
  zend_hash_str_add_new(Z_ARRVAL(arr), URI_SERIALIZED_PROPERTY_NAME, sizeof(URI_SERIALIZED_PROPERTY_NAME) - 1, &tmp);
528
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
529
530
  /* Serialize regular properties: second array */
531
0
  ZVAL_ARR(&arr, this_object->handlers->get_properties(this_object));
532
0
  Z_TRY_ADDREF(arr);
533
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
534
0
}
535
536
static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_name)
537
7
{
538
7
  HashTable *data;
539
540
21
  ZEND_PARSE_PARAMETERS_START(1, 1)
541
28
    Z_PARAM_ARRAY_HT(data)
542
7
  ZEND_PARSE_PARAMETERS_END();
543
544
7
  zend_object *object = Z_OBJ_P(ZEND_THIS);
545
546
  /* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */
547
7
  if (zend_hash_num_elements(data) != 2) {
548
5
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
549
5
    RETURN_THROWS();
550
5
  }
551
552
  /* Unserialize state: "uri" key in the first array */
553
2
  zval *arr = zend_hash_index_find(data, 0);
554
2
  if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) {
555
2
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
556
2
    RETURN_THROWS();
557
2
  }
558
559
  /* Verify the expected number of elements inside the first array, this implicitly ensures that no additional elements are present. */
560
0
  if (zend_hash_num_elements(Z_ARRVAL_P(arr)) != 1) {
561
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
562
0
    RETURN_THROWS();
563
0
  }
564
565
0
  zval *uri_zv = zend_hash_str_find_ind(Z_ARRVAL_P(arr), ZEND_STRL(URI_SERIALIZED_PROPERTY_NAME));
566
0
  if (uri_zv == NULL || Z_TYPE_P(uri_zv) != IS_STRING) {
567
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
568
0
    RETURN_THROWS();
569
0
  }
570
571
0
  uri_internal_t *internal_uri = uri_internal_from_obj(object);
572
0
  internal_uri->handler = uri_handler_by_name(handler_name, strlen(handler_name));
573
0
  if (internal_uri->uri != NULL) {
574
0
    internal_uri->handler->free_uri(internal_uri->uri);
575
0
  }
576
0
  internal_uri->uri = internal_uri->handler->parse_uri(Z_STR_P(uri_zv), NULL, NULL, true);
577
0
  if (internal_uri->uri == NULL) {
578
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
579
0
    RETURN_THROWS();
580
0
  }
581
582
  /* Unserialize regular properties: second array */
583
0
  arr = zend_hash_index_find(data, 1);
584
0
  if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) {
585
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
586
0
    RETURN_THROWS();
587
0
  }
588
589
  /* Verify that there is no regular property in the second array, because the URI classes have no properties and they are final. */
590
0
  if (zend_hash_num_elements(Z_ARRVAL_P(arr)) > 0) {
591
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
592
0
    RETURN_THROWS();
593
0
  }
594
0
}
595
596
PHP_METHOD(Uri_Rfc3986_Uri, __unserialize)
597
1
{
598
1
  uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PARSER_RFC3986);
599
1
}
600
601
PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo)
602
0
{
603
0
  ZEND_PARSE_PARAMETERS_NONE();
604
605
0
  zend_object *object = Z_OBJ_P(ZEND_THIS);
606
607
0
  RETURN_ARR(uri_get_debug_properties(object));
608
0
}
609
610
PHP_METHOD(Uri_WhatWg_Url, getScheme)
611
0
{
612
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII);
613
0
}
614
615
PHP_METHOD(Uri_WhatWg_Url, withScheme)
616
0
{
617
0
  uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME);
618
0
}
619
620
PHP_METHOD(Uri_WhatWg_Url, withUsername)
621
0
{
622
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME);
623
0
}
624
625
PHP_METHOD(Uri_WhatWg_Url, withPassword)
626
0
{
627
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD);
628
0
}
629
630
PHP_METHOD(Uri_WhatWg_Url, getAsciiHost)
631
0
{
632
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_ASCII);
633
0
}
634
635
PHP_METHOD(Uri_WhatWg_Url, getUnicodeHost)
636
0
{
637
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_UNICODE);
638
0
}
639
640
PHP_METHOD(Uri_WhatWg_Url, withHost)
641
0
{
642
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST);
643
0
}
644
645
PHP_METHOD(Uri_WhatWg_Url, withPort)
646
0
{
647
0
  uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT);
648
0
}
649
650
PHP_METHOD(Uri_WhatWg_Url, withPath)
651
0
{
652
0
  uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH);
653
0
}
654
655
PHP_METHOD(Uri_WhatWg_Url, withQuery)
656
0
{
657
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY);
658
0
}
659
660
PHP_METHOD(Uri_WhatWg_Url, withFragment)
661
0
{
662
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT);
663
0
}
664
665
PHP_METHOD(Uri_WhatWg_Url, equals)
666
0
{
667
0
  zend_object *that_object;
668
0
  zend_object *comparison_mode = NULL;
669
670
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
671
0
    Z_PARAM_OBJ_OF_CLASS(that_object, uri_whatwg_url_ce)
672
0
    Z_PARAM_OPTIONAL
673
0
    Z_PARAM_OBJ_OF_CLASS(comparison_mode, uri_comparison_mode_ce)
674
0
  ZEND_PARSE_PARAMETERS_END();
675
676
0
  uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, that_object, comparison_mode);
677
0
}
678
679
PHP_METHOD(Uri_WhatWg_Url, toUnicodeString)
680
0
{
681
0
  ZEND_PARSE_PARAMETERS_NONE();
682
683
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
684
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
685
0
  URI_ASSERT_INITIALIZATION(internal_uri);
686
687
0
  RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_UNICODE, false));
688
0
}
689
690
PHP_METHOD(Uri_WhatWg_Url, toAsciiString)
691
0
{
692
0
  ZEND_PARSE_PARAMETERS_NONE();
693
694
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
695
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
696
0
  URI_ASSERT_INITIALIZATION(internal_uri);
697
698
0
  RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false));
699
0
}
700
701
PHP_METHOD(Uri_WhatWg_Url, resolve)
702
0
{
703
0
  zend_string *uri_str;
704
0
  zval *errors = NULL;
705
706
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
707
0
    Z_PARAM_PATH_STR(uri_str)
708
0
    Z_PARAM_OPTIONAL
709
0
    Z_PARAM_ZVAL(errors)
710
0
  ZEND_PARSE_PARAMETERS_END();
711
712
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
713
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
714
0
  URI_ASSERT_INITIALIZATION(internal_uri);
715
716
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal_uri->handler, uri_str, this_object, true, false, errors);
717
0
}
718
719
PHP_METHOD(Uri_WhatWg_Url, __serialize)
720
0
{
721
0
  ZEND_PARSE_PARAMETERS_NONE();
722
723
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
724
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
725
0
  URI_ASSERT_INITIALIZATION(internal_uri);
726
727
  /* Serialize state: "uri" key in the first array */
728
0
  zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false);
729
0
  if (uri_str == NULL) {
730
0
    throw_cannot_recompose_uri_to_string(this_object);
731
0
    RETURN_THROWS();
732
0
  }
733
0
  zval tmp;
734
0
  ZVAL_STR(&tmp, uri_str);
735
736
0
  array_init(return_value);
737
738
0
  zval arr;
739
0
  array_init(&arr);
740
0
  zend_hash_str_add_new(Z_ARRVAL(arr), ZEND_STRL(URI_SERIALIZED_PROPERTY_NAME), &tmp);
741
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
742
743
  /* Serialize regular properties: second array */
744
0
  ZVAL_ARR(&arr, this_object->handlers->get_properties(this_object));
745
0
  Z_ADDREF(arr);
746
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
747
0
}
748
749
PHP_METHOD(Uri_WhatWg_Url, __unserialize)
750
6
{
751
6
  uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PARSER_WHATWG);
752
6
}
753
754
PHP_METHOD(Uri_WhatWg_Url, __debugInfo)
755
0
{
756
0
  ZEND_PARSE_PARAMETERS_NONE();
757
758
0
  zend_object *object = Z_OBJ_P(ZEND_THIS);
759
760
0
  RETURN_ARR(uri_get_debug_properties(object));
761
0
}
762
763
static zend_object *uri_create_object_handler(zend_class_entry *class_type)
764
54
{
765
54
  uri_object_t *uri_object = zend_object_alloc(sizeof(uri_object_t), class_type);
766
767
54
  zend_object_std_init(&uri_object->std, class_type);
768
54
  object_properties_init(&uri_object->std, class_type);
769
770
54
  return &uri_object->std;
771
54
}
772
773
static void uri_free_obj_handler(zend_object *object)
774
54
{
775
54
  uri_object_t *uri_object = uri_object_from_obj(object);
776
777
54
  if (UNEXPECTED(uri_object->internal.uri != NULL)) {
778
0
    uri_object->internal.handler->free_uri(uri_object->internal.uri);
779
0
    uri_object->internal.handler = NULL;
780
0
    uri_object->internal.uri = NULL;
781
0
  }
782
783
54
  zend_object_std_dtor(&uri_object->std);
784
54
}
785
786
zend_object *uri_clone_obj_handler(zend_object *object)
787
0
{
788
0
  uri_object_t *uri_object = uri_object_from_obj(object);
789
0
  uri_internal_t *internal_uri = uri_internal_from_obj(object);
790
791
0
  URI_ASSERT_INITIALIZATION(internal_uri);
792
793
0
  zend_object *new_object = uri_create_object_handler(object->ce);
794
0
  ZEND_ASSERT(new_object != NULL);
795
0
  uri_object_t *new_uri_object = uri_object_from_obj(new_object);
796
797
0
  new_uri_object->internal.handler = internal_uri->handler;
798
799
0
  void *uri = internal_uri->handler->clone_uri(internal_uri->uri);
800
0
  ZEND_ASSERT(uri != NULL);
801
802
0
  new_uri_object->internal.uri = uri;
803
804
0
  zend_objects_clone_members(&new_uri_object->std, &uri_object->std);
805
806
0
  return &new_uri_object->std;
807
0
}
808
809
PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers)
810
32
{
811
32
  ce->create_object = uri_create_object_handler;
812
32
  ce->default_object_handlers = object_handlers;
813
32
  memcpy(object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
814
32
  object_handlers->offset = XtOffsetOf(uri_object_t, std);
815
32
  object_handlers->free_obj = uri_free_obj_handler;
816
32
  object_handlers->clone_obj = uri_clone_obj_handler;
817
32
}
818
819
zend_result uri_handler_register(const uri_handler_t *uri_handler)
820
32
{
821
32
  zend_string *key = zend_string_init_interned(uri_handler->name, strlen(uri_handler->name), 1);
822
823
32
  ZEND_ASSERT(uri_handler->name != NULL);
824
32
  ZEND_ASSERT(uri_handler->parse_uri != NULL);
825
32
  ZEND_ASSERT(uri_handler->clone_uri != NULL);
826
32
  ZEND_ASSERT(uri_handler->uri_to_string != NULL);
827
32
  ZEND_ASSERT(uri_handler->free_uri != NULL);
828
829
32
  zend_result result = zend_hash_add_ptr(&uri_handlers, key, (void *) uri_handler) != NULL ? SUCCESS : FAILURE;
830
831
32
  zend_string_release_ex(key, true);
832
833
32
  return result;
834
32
}
835
836
static PHP_MINIT_FUNCTION(uri)
837
16
{
838
16
  uri_rfc3986_uri_ce = register_class_Uri_Rfc3986_Uri();
839
16
  php_uri_implementation_set_object_handlers(uri_rfc3986_uri_ce, &uri_rfc3986_uri_object_handlers);
840
841
16
  uri_whatwg_url_ce = register_class_Uri_WhatWg_Url();
842
16
  php_uri_implementation_set_object_handlers(uri_whatwg_url_ce, &uri_whatwg_uri_object_handlers);
843
844
16
  uri_comparison_mode_ce = register_class_Uri_UriComparisonMode();
845
16
  uri_exception_ce = register_class_Uri_UriException(zend_ce_exception);
846
16
  uri_invalid_uri_exception_ce = register_class_Uri_InvalidUriException(uri_exception_ce);
847
16
  uri_whatwg_invalid_url_exception_ce = register_class_Uri_WhatWg_InvalidUrlException(uri_invalid_uri_exception_ce);
848
16
  uri_whatwg_url_validation_error_ce = register_class_Uri_WhatWg_UrlValidationError();
849
16
  uri_whatwg_url_validation_error_type_ce = register_class_Uri_WhatWg_UrlValidationErrorType();
850
851
16
  zend_hash_init(&uri_handlers, 4, NULL, NULL, true);
852
853
16
  if (PHP_MINIT(uri_uriparser)(INIT_FUNC_ARGS_PASSTHRU) == FAILURE) {
854
0
    return FAILURE;
855
0
  }
856
857
16
  if (uri_handler_register(&lexbor_uri_handler) == FAILURE) {
858
0
    return FAILURE;
859
0
  }
860
861
16
  return SUCCESS;
862
16
}
863
864
static PHP_MINFO_FUNCTION(uri)
865
11
{
866
11
  php_info_print_table_start();
867
11
  php_info_print_table_row(2, "uri support", "active");
868
11
  php_info_print_table_row(2, "uriparser library version", URIPARSER_VERSION);
869
11
  php_info_print_table_end();
870
11
}
871
872
static PHP_MSHUTDOWN_FUNCTION(uri)
873
0
{
874
0
  zend_hash_destroy(&uri_handlers);
875
876
0
  return SUCCESS;
877
0
}
878
879
PHP_RINIT_FUNCTION(uri)
880
268k
{
881
268k
  if (lexbor_request_init() == FAILURE) {
882
0
    return FAILURE;
883
0
  }
884
885
268k
  return SUCCESS;
886
268k
}
887
888
PHP_RSHUTDOWN_FUNCTION(uri)
889
268k
{
890
268k
  lexbor_request_shutdown();
891
892
268k
  return SUCCESS;
893
268k
}
894
895
zend_module_entry uri_module_entry = {
896
  STANDARD_MODULE_HEADER_EX, NULL,
897
  uri_deps,
898
  "uri",                          /* Extension name */
899
  NULL,                           /* zend_function_entry */
900
  PHP_MINIT(uri),                 /* PHP_MINIT - Module initialization */
901
  PHP_MSHUTDOWN(uri),             /* PHP_MSHUTDOWN - Module shutdown */
902
  PHP_RINIT(uri),                 /* PHP_RINIT - Request initialization */
903
  PHP_RSHUTDOWN(uri),             /* PHP_RSHUTDOWN - Request shutdown */
904
  PHP_MINFO(uri),                 /* PHP_MINFO - Module info */
905
  PHP_VERSION,                    /* Version */
906
  STANDARD_MODULE_PROPERTIES
907
};