Coverage Report

Created: 2025-06-13 06:43

/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.h"
29
#include "php_uri_common.h"
30
#include "php_lexbor.h"
31
#include "php_uri_arginfo.h"
32
#include "uriparser/src/UriConfig.h"
33
34
zend_class_entry *uri_whatwg_url_ce;
35
zend_object_handlers uri_whatwg_uri_object_handlers;
36
zend_class_entry *uri_comparison_mode_ce;
37
zend_class_entry *uri_exception_ce;
38
zend_class_entry *uri_invalid_uri_exception_ce;
39
zend_class_entry *uri_whatwg_invalid_url_exception_ce;
40
zend_class_entry *uri_whatwg_url_validation_error_type_ce;
41
zend_class_entry *uri_whatwg_url_validation_error_ce;
42
43
5
#define URIPARSER_VERSION PACKAGE_VERSION
44
45
static const zend_module_dep uri_deps[] = {
46
  ZEND_MOD_REQUIRED("lexbor")
47
  ZEND_MOD_END
48
};
49
50
static zend_array uri_handlers;
51
52
static uri_handler_t *uri_handler_by_name(const char *handler_name, size_t handler_name_len)
53
0
{
54
0
  return zend_hash_str_find_ptr(&uri_handlers, handler_name, handler_name_len);
55
0
}
56
57
static HashTable *uri_get_debug_properties(zend_object *object)
58
0
{
59
0
  uri_internal_t *internal_uri = uri_internal_from_obj(object);
60
0
  ZEND_ASSERT(internal_uri != NULL);
61
62
0
  HashTable *std_properties = zend_std_get_properties(object);
63
0
  HashTable *result = zend_array_dup(std_properties);
64
65
0
  if (UNEXPECTED(internal_uri->uri == NULL)) {
66
0
    return result;
67
0
  }
68
69
0
  const uri_property_handlers_t property_handlers = internal_uri->handler->property_handlers;
70
71
0
  zval tmp;
72
0
  if (property_handlers.scheme.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
73
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_SCHEME), &tmp);
74
0
  }
75
76
0
  if (property_handlers.username.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
77
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_USERNAME), &tmp);
78
0
  }
79
80
0
  if (property_handlers.password.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
81
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PASSWORD), &tmp);
82
0
  }
83
84
0
  if (property_handlers.host.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
85
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_HOST), &tmp);
86
0
  }
87
88
0
  if (property_handlers.port.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
89
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PORT), &tmp);
90
0
  }
91
92
0
  if (property_handlers.path.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
93
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PATH), &tmp);
94
0
  }
95
96
0
  if (property_handlers.query.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
97
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_QUERY), &tmp);
98
0
  }
99
100
0
  if (property_handlers.fragment.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) {
101
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_FRAGMENT), &tmp);
102
0
  }
103
104
0
  return result;
105
0
}
106
107
PHP_METHOD(Uri_WhatWg_InvalidUrlException, __construct)
108
5
{
109
5
  zend_string *message = NULL;
110
5
  zval *errors = NULL;
111
5
  zend_long code = 0;
112
5
  zval *previous = NULL;
113
114
15
  ZEND_PARSE_PARAMETERS_START(0, 4)
115
15
    Z_PARAM_OPTIONAL
116
15
    Z_PARAM_STR(message)
117
0
    Z_PARAM_ARRAY(errors)
118
0
    Z_PARAM_LONG(code)
119
0
    Z_PARAM_OBJECT_OF_CLASS_OR_NULL(previous, zend_ce_throwable)
120
5
  ZEND_PARSE_PARAMETERS_END();
121
122
5
  if (zend_update_exception_properties(INTERNAL_FUNCTION_PARAM_PASSTHRU, message, code, previous) == FAILURE) {
123
0
    RETURN_THROWS();
124
0
  }
125
126
5
  if (errors == NULL) {
127
5
    zval tmp;
128
5
    ZVAL_EMPTY_ARRAY(&tmp);
129
5
    zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp);
130
5
  } else {
131
0
    zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), errors);
132
0
  }
133
5
  if (EG(exception)) {
134
0
    RETURN_THROWS();
135
0
  }
136
5
}
137
138
PHP_METHOD(Uri_WhatWg_UrlValidationError, __construct)
139
5
{
140
5
  zend_string *context;
141
5
  zval *type;
142
5
  bool failure;
143
144
10
  ZEND_PARSE_PARAMETERS_START(3, 3)
145
10
    Z_PARAM_STR(context)
146
0
    Z_PARAM_OBJECT_OF_CLASS(type, uri_whatwg_url_validation_error_type_ce)
147
0
    Z_PARAM_BOOL(failure)
148
5
  ZEND_PARSE_PARAMETERS_END();
149
150
0
  zend_update_property_str(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context);
151
0
  if (EG(exception)) {
152
0
    RETURN_THROWS();
153
0
  }
154
155
0
  zend_update_property_ex(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_TYPE), type);
156
0
  if (EG(exception)) {
157
0
    RETURN_THROWS();
158
0
  }
159
160
0
  zval failure_zv;
161
0
  ZVAL_BOOL(&failure_zv, failure);
162
0
  zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("failure"), &failure_zv);
163
0
  if (EG(exception)) {
164
0
    RETURN_THROWS();
165
0
  }
166
0
}
167
168
/**
169
 * Pass the errors parameter by ref to errors_zv for userland, and frees it if
170
 * it is not not needed anymore.
171
 */
172
static zend_result pass_errors_by_ref_and_free(zval *errors_zv, zval *errors)
173
0
{
174
0
  ZEND_ASSERT(Z_TYPE_P(errors) == IS_UNDEF || Z_TYPE_P(errors) == IS_ARRAY);
175
176
  /* There was no error during parsing */
177
0
  if (Z_ISUNDEF_P(errors)) {
178
0
    return SUCCESS;
179
0
  }
180
181
  /* The errors parameter is an array, but the pass-by ref argument stored by
182
   * errors_zv was not passed - the URI implementation either doesn't support
183
   * returning additional error information, or the caller is not interested in it */
184
0
  if (errors_zv == NULL) {
185
0
    zval_ptr_dtor(errors);
186
0
    return SUCCESS;
187
0
  }
188
189
0
  ZEND_TRY_ASSIGN_REF_ARR(errors_zv, Z_ARRVAL_P(errors));
190
0
  if (EG(exception)) {
191
0
    zval_ptr_dtor(errors);
192
0
    return FAILURE;
193
0
  }
194
195
0
  return SUCCESS;
196
0
}
197
198
PHPAPI void php_uri_instantiate_uri(
199
  INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_object *base_url_object,
200
  bool should_throw, bool should_update_this_object, zval *errors_zv
201
0
) {
202
0
  zval errors;
203
0
  ZVAL_UNDEF(&errors);
204
205
0
  void *base_url = NULL;
206
0
  if (base_url_object != NULL) {
207
0
    uri_internal_t *internal_base_url = uri_internal_from_obj(base_url_object);
208
0
    URI_ASSERT_INITIALIZATION(internal_base_url);
209
0
    base_url = internal_base_url->uri;
210
0
  }
211
212
0
  void *uri = handler->parse_uri(uri_str, base_url, should_throw || errors_zv != NULL ? &errors : NULL, !should_throw);
213
0
  if (UNEXPECTED(uri == NULL)) {
214
0
    if (should_throw) {
215
0
      zval_ptr_dtor(&errors);
216
0
      RETURN_THROWS();
217
0
    } else {
218
0
      if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) {
219
0
        RETURN_THROWS();
220
0
      }
221
0
      RETURN_NULL();
222
0
    }
223
0
  }
224
225
0
  if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) {
226
0
    RETURN_THROWS();
227
0
  }
228
229
0
  uri_object_t *uri_object;
230
0
  if (should_update_this_object) {
231
0
    uri_object = Z_URI_OBJECT_P(ZEND_THIS);
232
0
  } else {
233
0
    if (EX(func)->common.fn_flags & ZEND_ACC_STATIC) {
234
0
      object_init_ex(return_value, Z_CE_P(ZEND_THIS));
235
0
    } else {
236
0
      object_init_ex(return_value, Z_OBJCE_P(ZEND_THIS));
237
0
    }
238
0
    uri_object = Z_URI_OBJECT_P(return_value);
239
0
  }
240
241
0
  uri_object->internal.handler = handler;
242
0
  uri_object->internal.uri = uri;
243
0
}
244
245
static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
246
5
{
247
5
  zend_string *uri_str;
248
5
  zend_object *base_url_object = NULL;
249
5
  zval *errors = NULL;
250
251
10
  ZEND_PARSE_PARAMETERS_START(1, 3)
252
10
    Z_PARAM_PATH_STR(uri_str)
253
0
    Z_PARAM_OPTIONAL
254
0
    Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, uri_whatwg_url_ce)
255
0
    Z_PARAM_ZVAL(errors)
256
5
  ZEND_PARSE_PARAMETERS_END();
257
258
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &lexbor_uri_handler, uri_str, base_url_object, is_constructor, is_constructor, errors);
259
0
}
260
261
PHP_METHOD(Uri_WhatWg_Url, parse)
262
0
{
263
0
  create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
264
0
}
265
266
PHP_METHOD(Uri_WhatWg_Url, __construct)
267
5
{
268
5
  create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
269
5
}
270
271
static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, zend_object *comparison_mode)
272
0
{
273
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
274
0
  uri_internal_t *this_internal_uri = uri_internal_from_obj(this_object);
275
0
  URI_ASSERT_INITIALIZATION(this_internal_uri);
276
277
0
  uri_internal_t *that_internal_uri = uri_internal_from_obj(that_object);
278
0
  URI_ASSERT_INITIALIZATION(that_internal_uri);
279
280
0
  if (this_object->ce != that_object->ce &&
281
0
    !instanceof_function(this_object->ce, that_object->ce) &&
282
0
    !instanceof_function(that_object->ce, this_object->ce)
283
0
  ) {
284
0
    RETURN_FALSE;
285
0
  }
286
287
0
  bool exclude_fragment = true;
288
0
  if (comparison_mode) {
289
0
    zval *case_name = zend_enum_fetch_case_name(comparison_mode);
290
0
    exclude_fragment = zend_string_equals_literal(Z_STR_P(case_name), "ExcludeFragment");
291
0
  }
292
293
0
  zend_string *this_str = this_internal_uri->handler->uri_to_string(
294
0
    this_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment);
295
0
  if (this_str == NULL) {
296
0
    zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name));
297
0
    RETURN_THROWS();
298
0
  }
299
300
0
  zend_string *that_str = that_internal_uri->handler->uri_to_string(
301
0
    that_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment);
302
0
  if (that_str == NULL) {
303
0
    zend_string_release(this_str);
304
0
    zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(that_object->ce->name));
305
0
    RETURN_THROWS();
306
0
  }
307
308
0
  RETVAL_BOOL(zend_string_equals(this_str, that_str));
309
310
0
  zend_string_release(this_str);
311
0
  zend_string_release(that_str);
312
0
}
313
314
static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_name)
315
0
{
316
0
  HashTable *data;
317
318
0
  ZEND_PARSE_PARAMETERS_START(1, 1)
319
0
    Z_PARAM_ARRAY_HT(data)
320
0
  ZEND_PARSE_PARAMETERS_END();
321
322
0
  zend_object *object = Z_OBJ_P(ZEND_THIS);
323
324
  /* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */
325
0
  if (zend_hash_num_elements(data) != 2) {
326
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
327
0
    RETURN_THROWS();
328
0
  }
329
330
  /* Unserialize state: "uri" key in the first array */
331
0
  zval *arr = zend_hash_index_find(data, 0);
332
0
  if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) {
333
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
334
0
    RETURN_THROWS();
335
0
  }
336
337
  /* Verify the expected number of elements inside the first array, this implicitly ensures that no additional elements are present. */
338
0
  if (zend_hash_num_elements(Z_ARRVAL_P(arr)) != 1) {
339
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
340
0
    RETURN_THROWS();
341
0
  }
342
343
0
  zval *uri_zv = zend_hash_str_find_ind(Z_ARRVAL_P(arr), ZEND_STRL(URI_SERIALIZED_PROPERTY_NAME));
344
0
  if (uri_zv == NULL || Z_TYPE_P(uri_zv) != IS_STRING) {
345
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
346
0
    RETURN_THROWS();
347
0
  }
348
349
0
  uri_internal_t *internal_uri = uri_internal_from_obj(object);
350
0
  internal_uri->handler = uri_handler_by_name(handler_name, strlen(handler_name));
351
0
  if (internal_uri->uri != NULL) {
352
0
    internal_uri->handler->free_uri(internal_uri->uri);
353
0
  }
354
0
  internal_uri->uri = internal_uri->handler->parse_uri(Z_STR_P(uri_zv), NULL, NULL, true);
355
0
  if (internal_uri->uri == NULL) {
356
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
357
0
    RETURN_THROWS();
358
0
  }
359
360
  /* Unserialize regular properties: second array */
361
0
  arr = zend_hash_index_find(data, 1);
362
0
  if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) {
363
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
364
0
    RETURN_THROWS();
365
0
  }
366
367
  /* Verify that there is no regular property in the second array, because the URI classes have no properties and they are final. */
368
0
  if (zend_hash_num_elements(Z_ARRVAL_P(arr)) > 0) {
369
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
370
0
    RETURN_THROWS();
371
0
  }
372
0
}
373
374
PHP_METHOD(Uri_WhatWg_Url, getScheme)
375
0
{
376
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII);
377
0
}
378
379
PHP_METHOD(Uri_WhatWg_Url, withScheme)
380
0
{
381
0
  uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME);
382
0
}
383
384
PHP_METHOD(Uri_WhatWg_Url, getUsername)
385
0
{
386
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_NORMALIZED_ASCII);
387
0
}
388
389
PHP_METHOD(Uri_WhatWg_Url, withUsername)
390
0
{
391
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME);
392
0
}
393
394
PHP_METHOD(Uri_WhatWg_Url, getPassword)
395
0
{
396
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_NORMALIZED_ASCII);
397
0
}
398
399
PHP_METHOD(Uri_WhatWg_Url, withPassword)
400
0
{
401
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD);
402
0
}
403
404
PHP_METHOD(Uri_WhatWg_Url, getAsciiHost)
405
0
{
406
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_ASCII);
407
0
}
408
409
PHP_METHOD(Uri_WhatWg_Url, getUnicodeHost)
410
0
{
411
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_UNICODE);
412
0
}
413
414
PHP_METHOD(Uri_WhatWg_Url, withHost)
415
0
{
416
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST);
417
0
}
418
419
PHP_METHOD(Uri_WhatWg_Url, getPort)
420
0
{
421
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT, URI_COMPONENT_READ_NORMALIZED_ASCII);
422
0
}
423
424
PHP_METHOD(Uri_WhatWg_Url, withPort)
425
0
{
426
0
  uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT);
427
0
}
428
429
PHP_METHOD(Uri_WhatWg_Url, getPath)
430
0
{
431
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_NORMALIZED_ASCII);
432
0
}
433
434
PHP_METHOD(Uri_WhatWg_Url, withPath)
435
0
{
436
0
  uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH);
437
0
}
438
439
PHP_METHOD(Uri_WhatWg_Url, getQuery)
440
0
{
441
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_NORMALIZED_ASCII);
442
0
}
443
444
PHP_METHOD(Uri_WhatWg_Url, withQuery)
445
0
{
446
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY);
447
0
}
448
449
PHP_METHOD(Uri_WhatWg_Url, getFragment)
450
0
{
451
0
  uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_ASCII);
452
0
}
453
454
PHP_METHOD(Uri_WhatWg_Url, withFragment)
455
0
{
456
0
  uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT);
457
0
}
458
459
PHP_METHOD(Uri_WhatWg_Url, equals)
460
0
{
461
0
  zend_object *that_object;
462
0
  zend_object *comparison_mode = NULL;
463
464
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
465
0
    Z_PARAM_OBJ_OF_CLASS(that_object, uri_whatwg_url_ce)
466
0
    Z_PARAM_OPTIONAL
467
0
    Z_PARAM_OBJ_OF_CLASS(comparison_mode, uri_comparison_mode_ce)
468
0
  ZEND_PARSE_PARAMETERS_END();
469
470
0
  uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, that_object, comparison_mode);
471
0
}
472
473
PHP_METHOD(Uri_WhatWg_Url, toUnicodeString)
474
0
{
475
0
  ZEND_PARSE_PARAMETERS_NONE();
476
477
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
478
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
479
0
  URI_ASSERT_INITIALIZATION(internal_uri);
480
481
0
  RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_UNICODE, false));
482
0
}
483
484
PHP_METHOD(Uri_WhatWg_Url, toAsciiString)
485
0
{
486
0
  ZEND_PARSE_PARAMETERS_NONE();
487
488
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
489
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
490
0
  URI_ASSERT_INITIALIZATION(internal_uri);
491
492
0
  RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false));
493
0
}
494
495
PHP_METHOD(Uri_WhatWg_Url, resolve)
496
0
{
497
0
  zend_string *uri_str;
498
0
  zval *errors = NULL;
499
500
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
501
0
    Z_PARAM_PATH_STR(uri_str)
502
0
    Z_PARAM_OPTIONAL
503
0
    Z_PARAM_ZVAL(errors)
504
0
  ZEND_PARSE_PARAMETERS_END();
505
506
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
507
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
508
0
  URI_ASSERT_INITIALIZATION(internal_uri);
509
510
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal_uri->handler, uri_str, this_object, true, false, errors);
511
0
}
512
513
PHP_METHOD(Uri_WhatWg_Url, __serialize)
514
0
{
515
0
  ZEND_PARSE_PARAMETERS_NONE();
516
517
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
518
0
  uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
519
0
  URI_ASSERT_INITIALIZATION(internal_uri);
520
521
  /* Serialize state: "uri" key in the first array */
522
0
  zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false);
523
0
  if (uri_str == NULL) {
524
0
    zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name));
525
0
    RETURN_THROWS();
526
0
  }
527
0
  zval tmp;
528
0
  ZVAL_STR(&tmp, uri_str);
529
530
0
  array_init(return_value);
531
532
0
  zval arr;
533
0
  array_init(&arr);
534
0
  zend_hash_str_add_new(Z_ARRVAL(arr), ZEND_STRL(URI_SERIALIZED_PROPERTY_NAME), &tmp);
535
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
536
537
  /* Serialize regular properties: second array */
538
0
  ZVAL_ARR(&arr, this_object->handlers->get_properties(this_object));
539
0
  Z_ADDREF(arr);
540
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
541
0
}
542
543
PHP_METHOD(Uri_WhatWg_Url, __unserialize)
544
0
{
545
0
  uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PARSER_WHATWG);
546
0
}
547
548
PHP_METHOD(Uri_WhatWg_Url, __debugInfo)
549
0
{
550
0
  ZEND_PARSE_PARAMETERS_NONE();
551
552
0
  zend_object *object = Z_OBJ_P(ZEND_THIS);
553
554
0
  RETURN_ARR(uri_get_debug_properties(object));
555
0
}
556
557
static zend_object *uri_create_object_handler(zend_class_entry *class_type)
558
5
{
559
5
  uri_object_t *uri_object = zend_object_alloc(sizeof(uri_object_t), class_type);
560
561
5
  zend_object_std_init(&uri_object->std, class_type);
562
5
  object_properties_init(&uri_object->std, class_type);
563
564
5
  return &uri_object->std;
565
5
}
566
567
static void uri_free_obj_handler(zend_object *object)
568
5
{
569
5
  uri_object_t *uri_object = uri_object_from_obj(object);
570
571
5
  if (UNEXPECTED(uri_object->internal.uri != NULL)) {
572
0
    uri_object->internal.handler->free_uri(uri_object->internal.uri);
573
0
    uri_object->internal.handler = NULL;
574
0
    uri_object->internal.uri = NULL;
575
0
  }
576
577
5
  zend_object_std_dtor(&uri_object->std);
578
5
}
579
580
zend_object *uri_clone_obj_handler(zend_object *object)
581
0
{
582
0
  uri_object_t *uri_object = uri_object_from_obj(object);
583
0
  uri_internal_t *internal_uri = uri_internal_from_obj(object);
584
585
0
  URI_ASSERT_INITIALIZATION(internal_uri);
586
587
0
  zend_object *new_object = uri_create_object_handler(object->ce);
588
0
  ZEND_ASSERT(new_object != NULL);
589
0
  uri_object_t *new_uri_object = uri_object_from_obj(new_object);
590
591
0
  new_uri_object->internal.handler = internal_uri->handler;
592
593
0
  void *uri = internal_uri->handler->clone_uri(internal_uri->uri);
594
0
  ZEND_ASSERT(uri != NULL);
595
596
0
  new_uri_object->internal.uri = uri;
597
598
0
  zend_objects_clone_members(&new_uri_object->std, &uri_object->std);
599
600
0
  return &new_uri_object->std;
601
0
}
602
603
PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers)
604
16
{
605
16
  ce->create_object = uri_create_object_handler;
606
16
  ce->default_object_handlers = object_handlers;
607
16
  memcpy(object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
608
16
  object_handlers->offset = XtOffsetOf(uri_object_t, std);
609
16
  object_handlers->free_obj = uri_free_obj_handler;
610
16
  object_handlers->clone_obj = uri_clone_obj_handler;
611
16
}
612
613
zend_result uri_handler_register(const uri_handler_t *uri_handler)
614
16
{
615
16
  zend_string *key = zend_string_init_interned(uri_handler->name, strlen(uri_handler->name), 1);
616
617
16
  ZEND_ASSERT(uri_handler->name != NULL);
618
16
  ZEND_ASSERT(uri_handler->parse_uri != NULL);
619
16
  ZEND_ASSERT(uri_handler->clone_uri != NULL);
620
16
  ZEND_ASSERT(uri_handler->uri_to_string != NULL);
621
16
  ZEND_ASSERT(uri_handler->free_uri != NULL);
622
623
16
  zend_result result = zend_hash_add_ptr(&uri_handlers, key, (void *) uri_handler) != NULL ? SUCCESS : FAILURE;
624
625
16
  zend_string_release_ex(key, true);
626
627
16
  return result;
628
16
}
629
630
static PHP_MINIT_FUNCTION(uri)
631
16
{
632
16
  uri_whatwg_url_ce = register_class_Uri_WhatWg_Url();
633
16
  php_uri_implementation_set_object_handlers(uri_whatwg_url_ce, &uri_whatwg_uri_object_handlers);
634
635
16
  uri_comparison_mode_ce = register_class_Uri_UriComparisonMode();
636
16
  uri_exception_ce = register_class_Uri_UriException(zend_ce_exception);
637
16
  uri_invalid_uri_exception_ce = register_class_Uri_InvalidUriException(uri_exception_ce);
638
16
  uri_whatwg_invalid_url_exception_ce = register_class_Uri_WhatWg_InvalidUrlException(uri_invalid_uri_exception_ce);
639
16
  uri_whatwg_url_validation_error_ce = register_class_Uri_WhatWg_UrlValidationError();
640
16
  uri_whatwg_url_validation_error_type_ce = register_class_Uri_WhatWg_UrlValidationErrorType();
641
642
16
  zend_hash_init(&uri_handlers, 4, NULL, NULL, true);
643
644
16
  if (uri_handler_register(&lexbor_uri_handler) == FAILURE) {
645
0
    return FAILURE;
646
0
  }
647
648
16
  return SUCCESS;
649
16
}
650
651
static PHP_MINFO_FUNCTION(uri)
652
5
{
653
5
  php_info_print_table_start();
654
5
  php_info_print_table_row(2, "uri support", "active");
655
5
  php_info_print_table_row(2, "uriparser library version", URIPARSER_VERSION);
656
5
  php_info_print_table_end();
657
5
}
658
659
static PHP_MSHUTDOWN_FUNCTION(uri)
660
0
{
661
0
  zend_hash_destroy(&uri_handlers);
662
663
0
  return SUCCESS;
664
0
}
665
666
PHP_RINIT_FUNCTION(uri)
667
300k
{
668
300k
  if (lexbor_request_init() == FAILURE) {
669
0
    return FAILURE;
670
0
  }
671
672
300k
  return SUCCESS;
673
300k
}
674
675
PHP_RSHUTDOWN_FUNCTION(uri)
676
300k
{
677
300k
  lexbor_request_shutdown();
678
679
300k
  return SUCCESS;
680
300k
}
681
682
zend_module_entry uri_module_entry = {
683
  STANDARD_MODULE_HEADER_EX, NULL,
684
  uri_deps,
685
  "uri",                          /* Extension name */
686
  NULL,                           /* zend_function_entry */
687
  PHP_MINIT(uri),                 /* PHP_MINIT - Module initialization */
688
  PHP_MSHUTDOWN(uri),             /* PHP_MSHUTDOWN - Module shutdown */
689
  PHP_RINIT(uri),                 /* PHP_RINIT - Request initialization */
690
  PHP_RSHUTDOWN(uri),             /* PHP_RSHUTDOWN - Request shutdown */
691
  PHP_MINFO(uri),                 /* PHP_MINFO - Module info */
692
  PHP_VERSION,                    /* Version */
693
  STANDARD_MODULE_PROPERTIES
694
};