mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
RFC: Add CurlSharePersistentHandle objects (#16937)
see https://wiki.php.net/rfc/curl_share_persistence_improvement
This commit is contained in:
1
NEWS
1
NEWS
@@ -19,6 +19,7 @@ PHP NEWS
|
||||
|
||||
- Curl:
|
||||
. Added curl_multi_get_handles(). (timwolla)
|
||||
. Added curl_share_init_persistent(). (enorris)
|
||||
|
||||
- Date:
|
||||
. Fix undefined behaviour problems regarding integer overflow in extreme edge
|
||||
|
||||
13
UPGRADING
13
UPGRADING
@@ -68,6 +68,11 @@ PHP 8.5 UPGRADE NOTES
|
||||
. Added support for Closures in constant expressions.
|
||||
RFC: https://wiki.php.net/rfc/closures_in_const_expr
|
||||
|
||||
- Curl:
|
||||
. Added support for share handles that are persisted across multiple PHP
|
||||
requests, safely allowing for more effective connection reuse.
|
||||
RFC: https://wiki.php.net/rfc/curl_share_persistence_improvement
|
||||
|
||||
- DOM:
|
||||
. Added Dom\Element::$outerHTML.
|
||||
|
||||
@@ -148,6 +153,9 @@ PHP 8.5 UPGRADE NOTES
|
||||
. curl_multi_get_handles() allows retrieving all CurlHandles current
|
||||
attached to a CurlMultiHandle. This includes both handles added using
|
||||
curl_multi_add_handle() and handles accepted by CURLMOPT_PUSHFUNCTION.
|
||||
. curl_share_init_persistent() allows creating a share handle that is
|
||||
persisted across multiple PHP requests.
|
||||
RFC: https://wiki.php.net/rfc/curl_share_persistence_improvement
|
||||
|
||||
- DOM:
|
||||
. Added Dom\Element::insertAdjacentHTML().
|
||||
@@ -166,6 +174,11 @@ PHP 8.5 UPGRADE NOTES
|
||||
7. New Classes and Interfaces
|
||||
========================================
|
||||
|
||||
- Curl:
|
||||
. CurlSharePersistentHandle representing a share handle that is persisted
|
||||
across multiple PHP requests.
|
||||
RFC: https://wiki.php.net/rfc/curl_share_persistence_improvement
|
||||
|
||||
========================================
|
||||
8. Removed Extensions and SAPIs
|
||||
========================================
|
||||
|
||||
@@ -46,6 +46,7 @@ static const func_info_t func_infos[] = {
|
||||
F1("curl_multi_strerror", MAY_BE_STRING|MAY_BE_NULL),
|
||||
F1("curl_share_init", MAY_BE_OBJECT),
|
||||
F1("curl_share_strerror", MAY_BE_STRING|MAY_BE_NULL),
|
||||
F1("curl_share_init_persistent", MAY_BE_OBJECT),
|
||||
F1("curl_strerror", MAY_BE_STRING|MAY_BE_NULL),
|
||||
F1("curl_version", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE),
|
||||
F1("date", MAY_BE_STRING),
|
||||
|
||||
@@ -3668,6 +3668,15 @@ final class CurlShareHandle
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @strict-properties
|
||||
* @not-serializable
|
||||
*/
|
||||
final class CurlSharePersistentHandle
|
||||
{
|
||||
public readonly array $options;
|
||||
}
|
||||
|
||||
function curl_close(CurlHandle $handle): void {}
|
||||
|
||||
/** @refcount 1 */
|
||||
@@ -3750,6 +3759,9 @@ function curl_share_setopt(CurlShareHandle $share_handle, int $option, mixed $va
|
||||
/** @refcount 1 */
|
||||
function curl_share_strerror(int $error_code): ?string {}
|
||||
|
||||
/** @refcount 1 */
|
||||
function curl_share_init_persistent(array $share_options): CurlSharePersistentHandle {}
|
||||
|
||||
/** @refcount 1 */
|
||||
function curl_strerror(int $error_code): ?string {}
|
||||
|
||||
|
||||
24
ext/curl/curl_arginfo.h
generated
24
ext/curl/curl_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: e2800e5ecc33f092576c7afcdb98d89825809669 */
|
||||
* Stub hash: 7d3cd96f8725c59be46817487bb8d06e04384269 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_close, 0, 1, IS_VOID, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, handle, CurlHandle, 0)
|
||||
@@ -137,6 +137,10 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_curl_share_strerror arginfo_curl_multi_strerror
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_curl_share_init_persistent, 0, 1, CurlSharePersistentHandle, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, share_options, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_curl_strerror arginfo_curl_multi_strerror
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_curl_version, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE)
|
||||
@@ -176,6 +180,7 @@ ZEND_FUNCTION(curl_share_errno);
|
||||
ZEND_FUNCTION(curl_share_init);
|
||||
ZEND_FUNCTION(curl_share_setopt);
|
||||
ZEND_FUNCTION(curl_share_strerror);
|
||||
ZEND_FUNCTION(curl_share_init_persistent);
|
||||
ZEND_FUNCTION(curl_strerror);
|
||||
ZEND_FUNCTION(curl_version);
|
||||
|
||||
@@ -214,6 +219,7 @@ static const zend_function_entry ext_functions[] = {
|
||||
ZEND_FE(curl_share_init, arginfo_curl_share_init)
|
||||
ZEND_FE(curl_share_setopt, arginfo_curl_share_setopt)
|
||||
ZEND_FE(curl_share_strerror, arginfo_curl_share_strerror)
|
||||
ZEND_FE(curl_share_init_persistent, arginfo_curl_share_init_persistent)
|
||||
ZEND_FE(curl_strerror, arginfo_curl_strerror)
|
||||
ZEND_FE(curl_version, arginfo_curl_version)
|
||||
ZEND_FE_END
|
||||
@@ -1137,3 +1143,19 @@ static zend_class_entry *register_class_CurlShareHandle(void)
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_CurlSharePersistentHandle(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "CurlSharePersistentHandle", NULL);
|
||||
class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE);
|
||||
|
||||
zval property_options_default_value;
|
||||
ZVAL_UNDEF(&property_options_default_value);
|
||||
zend_string *property_options_name = zend_string_init("options", sizeof("options") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_options_name, &property_options_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY));
|
||||
zend_string_release(property_options_name);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
@@ -40,9 +40,20 @@
|
||||
#define SAVE_CURL_ERROR(__handle, __err) \
|
||||
do { (__handle)->err.no = (int) __err; } while (0)
|
||||
|
||||
|
||||
ZEND_BEGIN_MODULE_GLOBALS(curl)
|
||||
HashTable persistent_curlsh;
|
||||
ZEND_END_MODULE_GLOBALS(curl)
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(curl)
|
||||
|
||||
#define CURL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(curl, v)
|
||||
|
||||
PHP_MINIT_FUNCTION(curl);
|
||||
PHP_MSHUTDOWN_FUNCTION(curl);
|
||||
PHP_MINFO_FUNCTION(curl);
|
||||
PHP_GINIT_FUNCTION(curl);
|
||||
PHP_GSHUTDOWN_FUNCTION(curl);
|
||||
|
||||
typedef struct {
|
||||
zend_fcall_info_cache fcc;
|
||||
@@ -153,6 +164,8 @@ static inline php_curlsh *curl_share_from_obj(zend_object *obj) {
|
||||
|
||||
void curl_multi_register_handlers(void);
|
||||
void curl_share_register_handlers(void);
|
||||
void curl_share_persistent_register_handlers(void);
|
||||
void curl_share_free_persistent_curlsh(zval *data);
|
||||
void curlfile_register_class(void);
|
||||
zend_result curl_cast_object(zend_object *obj, zval *result, int type);
|
||||
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
|
||||
#include "curl_arginfo.h"
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(curl)
|
||||
|
||||
#ifdef PHP_CURL_NEED_OPENSSL_TSL /* {{{ */
|
||||
static MUTEX_T *php_curl_openssl_tsl = NULL;
|
||||
|
||||
@@ -215,7 +217,11 @@ zend_module_entry curl_module_entry = {
|
||||
NULL,
|
||||
PHP_MINFO(curl),
|
||||
PHP_CURL_VERSION,
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
PHP_MODULE_GLOBALS(curl),
|
||||
PHP_GINIT(curl),
|
||||
PHP_GSHUTDOWN(curl),
|
||||
NULL,
|
||||
STANDARD_MODULE_PROPERTIES_EX
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
@@ -223,10 +229,22 @@ zend_module_entry curl_module_entry = {
|
||||
ZEND_GET_MODULE (curl)
|
||||
#endif
|
||||
|
||||
PHP_GINIT_FUNCTION(curl)
|
||||
{
|
||||
zend_hash_init(&curl_globals->persistent_curlsh, 0, NULL, curl_share_free_persistent_curlsh, true);
|
||||
GC_MAKE_PERSISTENT_LOCAL(&curl_globals->persistent_curlsh);
|
||||
}
|
||||
|
||||
PHP_GSHUTDOWN_FUNCTION(curl)
|
||||
{
|
||||
zend_hash_destroy(&curl_globals->persistent_curlsh);
|
||||
}
|
||||
|
||||
/* CurlHandle class */
|
||||
|
||||
zend_class_entry *curl_ce;
|
||||
zend_class_entry *curl_share_ce;
|
||||
zend_class_entry *curl_share_persistent_ce;
|
||||
static zend_object_handlers curl_object_handlers;
|
||||
|
||||
static zend_object *curl_create_object(zend_class_entry *class_type);
|
||||
@@ -410,6 +428,10 @@ PHP_MINIT_FUNCTION(curl)
|
||||
|
||||
curl_share_ce = register_class_CurlShareHandle();
|
||||
curl_share_register_handlers();
|
||||
|
||||
curl_share_persistent_ce = register_class_CurlSharePersistentHandle();
|
||||
curl_share_persistent_register_handlers();
|
||||
|
||||
curlfile_register_class();
|
||||
|
||||
return SUCCESS;
|
||||
@@ -2281,16 +2303,24 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
|
||||
|
||||
case CURLOPT_SHARE:
|
||||
{
|
||||
if (Z_TYPE_P(zvalue) == IS_OBJECT && Z_OBJCE_P(zvalue) == curl_share_ce) {
|
||||
php_curlsh *sh = Z_CURL_SHARE_P(zvalue);
|
||||
curl_easy_setopt(ch->cp, CURLOPT_SHARE, sh->share);
|
||||
|
||||
if (ch->share) {
|
||||
OBJ_RELEASE(&ch->share->std);
|
||||
}
|
||||
GC_ADDREF(&sh->std);
|
||||
ch->share = sh;
|
||||
if (Z_TYPE_P(zvalue) != IS_OBJECT) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (Z_OBJCE_P(zvalue) != curl_share_ce && Z_OBJCE_P(zvalue) != curl_share_persistent_ce) {
|
||||
break;
|
||||
}
|
||||
|
||||
php_curlsh *sh = Z_CURL_SHARE_P(zvalue);
|
||||
|
||||
curl_easy_setopt(ch->cp, CURLOPT_SHARE, sh->share);
|
||||
|
||||
if (ch->share) {
|
||||
OBJ_RELEASE(&ch->share->std);
|
||||
}
|
||||
|
||||
GC_ADDREF(&sh->std);
|
||||
ch->share = sh;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ extern zend_module_entry curl_module_entry;
|
||||
|
||||
PHP_CURL_API extern zend_class_entry *curl_ce;
|
||||
PHP_CURL_API extern zend_class_entry *curl_share_ce;
|
||||
PHP_CURL_API extern zend_class_entry *curl_share_persistent_ce;
|
||||
PHP_CURL_API extern zend_class_entry *curl_multi_ce;
|
||||
PHP_CURL_API extern zend_class_entry *curl_CURLFile_class;
|
||||
PHP_CURL_API extern zend_class_entry *curl_CURLStringFile_class;
|
||||
|
||||
166
ext/curl/share.c
166
ext/curl/share.c
@@ -21,6 +21,7 @@
|
||||
#endif
|
||||
|
||||
#include "php.h"
|
||||
#include "Zend/zend_exceptions.h"
|
||||
|
||||
#include "curl_private.h"
|
||||
|
||||
@@ -134,6 +135,151 @@ PHP_FUNCTION(curl_share_strerror)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/**
|
||||
* Initialize a persistent curl share handle with the given share options, reusing an existing one if found.
|
||||
*
|
||||
* Throws an exception if the share options are invalid.
|
||||
*/
|
||||
PHP_FUNCTION(curl_share_init_persistent)
|
||||
{
|
||||
// Options specified by the user.
|
||||
HashTable *share_opts = NULL;
|
||||
|
||||
// De-duplicated and sorted options.
|
||||
zval share_opts_prop;
|
||||
ZVAL_UNDEF(&share_opts_prop);
|
||||
|
||||
// An ID representing the unique set of options specified by the user.
|
||||
zend_ulong persistent_id = 0;
|
||||
|
||||
php_curlsh *sh = NULL;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_ARRAY_HT(share_opts)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (zend_hash_num_elements(share_opts) == 0) {
|
||||
zend_argument_must_not_be_empty_error(1);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ZEND_HASH_FOREACH_VAL(share_opts, zval *entry) {
|
||||
ZVAL_DEREF(entry);
|
||||
|
||||
bool failed = false;
|
||||
zend_ulong option = zval_try_get_long(entry, &failed);
|
||||
|
||||
if (failed) {
|
||||
zend_argument_type_error(1, "must contain only int values, %s given", zend_zval_value_name(entry));
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (option) {
|
||||
// Disallowed options
|
||||
case CURL_LOCK_DATA_COOKIE:
|
||||
zend_argument_value_error(1, "must not contain CURL_LOCK_DATA_COOKIE because sharing cookies across PHP requests is unsafe");
|
||||
goto error;
|
||||
|
||||
// Allowed options
|
||||
case CURL_LOCK_DATA_DNS:
|
||||
persistent_id |= 1 << 0;
|
||||
break;
|
||||
case CURL_LOCK_DATA_SSL_SESSION:
|
||||
persistent_id |= 1 << 1;
|
||||
break;
|
||||
case CURL_LOCK_DATA_CONNECT:
|
||||
persistent_id |= 1 << 2;
|
||||
break;
|
||||
case CURL_LOCK_DATA_PSL:
|
||||
persistent_id |= 1 << 3;
|
||||
break;
|
||||
|
||||
// Unknown options
|
||||
default:
|
||||
zend_argument_value_error(1, "must contain only CURL_LOCK_DATA_* constants");
|
||||
goto error;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
// We're now decently confident that we'll be returning a CurlSharePersistentHandle object, so we construct it here.
|
||||
object_init_ex(return_value, curl_share_persistent_ce);
|
||||
|
||||
// Next we initialize a property field for the CurlSharePersistentHandle object with the enabled share options.
|
||||
array_init(&share_opts_prop);
|
||||
|
||||
if (persistent_id & (1 << 0)) {
|
||||
add_next_index_long(&share_opts_prop, CURL_LOCK_DATA_DNS);
|
||||
}
|
||||
|
||||
if (persistent_id & (1 << 1)) {
|
||||
add_next_index_long(&share_opts_prop, CURL_LOCK_DATA_SSL_SESSION);
|
||||
}
|
||||
|
||||
if (persistent_id & (1 << 2)) {
|
||||
add_next_index_long(&share_opts_prop, CURL_LOCK_DATA_CONNECT);
|
||||
}
|
||||
|
||||
if (persistent_id & (1 << 3)) {
|
||||
add_next_index_long(&share_opts_prop, CURL_LOCK_DATA_PSL);
|
||||
}
|
||||
|
||||
zend_update_property(curl_share_persistent_ce, Z_OBJ_P(return_value), ZEND_STRL("options"), &share_opts_prop);
|
||||
|
||||
sh = Z_CURL_SHARE_P(return_value);
|
||||
|
||||
// If we are able to find an existing persistent share handle, we can use it and return early.
|
||||
zval *persisted = zend_hash_index_find(&CURL_G(persistent_curlsh), persistent_id);
|
||||
|
||||
if (persisted) {
|
||||
sh->share = Z_PTR_P(persisted);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// We could not find an existing share handle, so we'll have to create one.
|
||||
sh->share = curl_share_init();
|
||||
|
||||
// Apply the options property to the handle. We avoid using $share_opts as zval_get_long may not necessarily return
|
||||
// the same value as it did in the initial ZEND_HASH_FOREACH_VAL above.
|
||||
ZEND_HASH_PACKED_FOREACH_VAL(Z_ARRVAL_P(&share_opts_prop), zval *entry) {
|
||||
CURLSHcode curlsh_error = curl_share_setopt(sh->share, CURLSHOPT_SHARE, Z_LVAL_P(entry));
|
||||
|
||||
if (curlsh_error != CURLSHE_OK) {
|
||||
zend_throw_exception_ex(NULL, 0, "Could not construct persistent cURL share handle: %s", curl_share_strerror(curlsh_error));
|
||||
|
||||
goto error;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
zend_hash_index_add_new_ptr(&CURL_G(persistent_curlsh), persistent_id, sh->share);
|
||||
|
||||
cleanup:
|
||||
zval_ptr_dtor(&share_opts_prop);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
if (sh) {
|
||||
curl_share_cleanup(sh->share);
|
||||
}
|
||||
|
||||
zval_ptr_dtor(&share_opts_prop);
|
||||
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a persistent curl share handle from the module global HashTable.
|
||||
*
|
||||
* See PHP_GINIT_FUNCTION in ext/curl/interface.c.
|
||||
*/
|
||||
void curl_share_free_persistent_curlsh(zval *data)
|
||||
{
|
||||
CURLSH *handle = Z_PTR_P(data);
|
||||
|
||||
curl_share_cleanup(handle);
|
||||
}
|
||||
|
||||
/* CurlShareHandle class */
|
||||
|
||||
static zend_object *curl_share_create_object(zend_class_entry *class_type) {
|
||||
@@ -171,3 +317,23 @@ void curl_share_register_handlers(void) {
|
||||
curl_share_handlers.clone_obj = NULL;
|
||||
curl_share_handlers.compare = zend_objects_not_comparable;
|
||||
}
|
||||
|
||||
/* CurlSharePersistentHandle class */
|
||||
|
||||
static zend_object_handlers curl_share_persistent_handlers;
|
||||
|
||||
static zend_function *curl_share_persistent_get_constructor(zend_object *object) {
|
||||
zend_throw_error(NULL, "Cannot directly construct CurlSharePersistentHandle, use curl_share_init_persistent() instead");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void curl_share_persistent_register_handlers(void) {
|
||||
curl_share_persistent_ce->create_object = curl_share_create_object;
|
||||
curl_share_persistent_ce->default_object_handlers = &curl_share_persistent_handlers;
|
||||
|
||||
memcpy(&curl_share_persistent_handlers, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
curl_share_persistent_handlers.offset = XtOffsetOf(php_curlsh, std);
|
||||
curl_share_persistent_handlers.get_constructor = curl_share_persistent_get_constructor;
|
||||
curl_share_persistent_handlers.clone_obj = NULL;
|
||||
curl_share_persistent_handlers.compare = zend_objects_not_comparable;
|
||||
}
|
||||
|
||||
46
ext/curl/tests/curl_persistent_share_001.phpt
Normal file
46
ext/curl/tests/curl_persistent_share_001.phpt
Normal file
@@ -0,0 +1,46 @@
|
||||
--TEST--
|
||||
Basic curl persistent share handle test
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
include 'skipif-nocaddy.inc';
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function get_localhost_curl_handle(CurlSharePersistentHandle $sh): CurlHandle {
|
||||
$ch = curl_init("https://localhost");
|
||||
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SHARE, $sh);
|
||||
|
||||
return $ch;
|
||||
}
|
||||
|
||||
$sh1 = curl_share_init_persistent([CURL_LOCK_DATA_CONNECT, CURL_LOCK_DATA_DNS, CURL_LOCK_DATA_DNS]);
|
||||
$ch1 = get_localhost_curl_handle($sh1);
|
||||
|
||||
// Expect the two options we set above, but sorted and de-duplicated.
|
||||
var_dump($sh1->options);
|
||||
|
||||
$sh2 = curl_share_init_persistent([CURL_LOCK_DATA_DNS, CURL_LOCK_DATA_CONNECT]);
|
||||
$ch2 = get_localhost_curl_handle($sh2);
|
||||
|
||||
// Expect the connect time on the subsequent request to be zero, since it's reusing the connection.
|
||||
var_dump(curl_exec($ch1));
|
||||
var_dump(curl_exec($ch2));
|
||||
var_dump("second connect_time: " . (curl_getinfo($ch2)["connect_time"]));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(2) {
|
||||
[0]=>
|
||||
int(3)
|
||||
[1]=>
|
||||
int(5)
|
||||
}
|
||||
string(23) "Caddy is up and running"
|
||||
string(23) "Caddy is up and running"
|
||||
string(22) "second connect_time: 0"
|
||||
42
ext/curl/tests/curl_persistent_share_002.phpt
Normal file
42
ext/curl/tests/curl_persistent_share_002.phpt
Normal file
@@ -0,0 +1,42 @@
|
||||
--TEST--
|
||||
Curl persistent share handle test with different options
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
include 'skipif-nocaddy.inc';
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function get_localhost_curl_handle(CurlSharePersistentHandle $sh): CurlHandle {
|
||||
$ch = curl_init("https://localhost");
|
||||
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SHARE, $sh);
|
||||
|
||||
return $ch;
|
||||
}
|
||||
|
||||
$sh1 = curl_share_init_persistent([CURL_LOCK_DATA_DNS, CURL_LOCK_DATA_CONNECT]);
|
||||
$ch1 = get_localhost_curl_handle($sh1);
|
||||
|
||||
// Note that we're using different share options and thus should get a different persistent share
|
||||
// handle.
|
||||
$sh2 = curl_share_init_persistent([CURL_LOCK_DATA_CONNECT]);
|
||||
$ch2 = get_localhost_curl_handle($sh2);
|
||||
|
||||
var_dump($sh1->options != $sh2->options);
|
||||
|
||||
// Expect the connect time on the subsequent request to be non-zero, since it's *not* reusing the connection.
|
||||
var_dump(curl_exec($ch1));
|
||||
var_dump(curl_exec($ch2));
|
||||
var_dump("second connect_time: " . (curl_getinfo($ch2)["connect_time"]));
|
||||
|
||||
?>
|
||||
--EXPECTREGEX--
|
||||
bool\(true\)
|
||||
string\(23\) "Caddy is up and running"
|
||||
string\(23\) "Caddy is up and running"
|
||||
string\(\d+\) "second connect_time: .*[1-9].*"
|
||||
16
ext/curl/tests/curl_persistent_share_003.phpt
Normal file
16
ext/curl/tests/curl_persistent_share_003.phpt
Normal file
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Curl persistent share handle test with invalid option
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
try {
|
||||
$sh = curl_share_init_persistent([CURL_LOCK_DATA_DNS, CURL_LOCK_DATA_CONNECT, 30]);
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
curl_share_init_persistent(): Argument #1 ($share_options) must contain only CURL_LOCK_DATA_* constants
|
||||
16
ext/curl/tests/curl_persistent_share_004.phpt
Normal file
16
ext/curl/tests/curl_persistent_share_004.phpt
Normal file
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Curl persistent share handle test with disallowed option
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
try {
|
||||
$sh = curl_share_init_persistent([CURL_LOCK_DATA_COOKIE]);
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
curl_share_init_persistent(): Argument #1 ($share_options) must not contain CURL_LOCK_DATA_COOKIE because sharing cookies across PHP requests is unsafe
|
||||
18
ext/curl/tests/curl_persistent_share_005.phpt
Normal file
18
ext/curl/tests/curl_persistent_share_005.phpt
Normal file
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
Curl persistent share handles cannot be used with curl_share_setopt
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$sh = curl_share_init_persistent([CURL_LOCK_DATA_DNS]);
|
||||
|
||||
try {
|
||||
curl_share_setopt($sh, CURLOPT_SHARE, CURL_LOCK_DATA_CONNECT);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
curl_share_setopt(): Argument #1 ($share_handle) must be of type CurlShareHandle, CurlSharePersistentHandle given
|
||||
16
ext/curl/tests/curl_persistent_share_006.phpt
Normal file
16
ext/curl/tests/curl_persistent_share_006.phpt
Normal file
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Curl persistent share handles must be initialized with a non-empty $share_opts
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
try {
|
||||
$sh = curl_share_init_persistent([]);
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
curl_share_init_persistent(): Argument #1 ($share_options) must not be empty
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
$ch = curl_init("https://localhost");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
|
||||
$body = curl_exec($ch);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user