Implement curl server push

This commit is contained in:
Davey Shafik 2015-10-02 09:31:10 +02:00
parent d56d2f452b
commit ad15e1ccda
3 changed files with 124 additions and 5 deletions

View file

@ -1337,6 +1337,9 @@ PHP_MINIT_FUNCTION(curl)
#if LIBCURL_VERSION_NUM >= 0x072e00 /* Available since 7.46.0 */
REGISTER_CURL_CONSTANT(CURLOPT_STREAM_WEIGHT);
REGISTER_CURL_CONSTANT(CURLMOPT_PUSHFUNCTION);
REGISTER_CURL_CONSTANT(CURL_PUSH_OK);
REGISTER_CURL_CONSTANT(CURL_PUSH_DENY);
#endif
#if LIBCURL_VERSION_NUM >= 0x072f00 /* Available since 7.47.0 */
@ -1853,7 +1856,7 @@ PHP_FUNCTION(curl_version)
/* {{{ alloc_curl_handle
*/
static php_curl *alloc_curl_handle()
php_curl *alloc_curl_handle()
{
php_curl *ch = ecalloc(1, sizeof(php_curl));
ch->to_free = ecalloc(1, sizeof(struct _php_curl_free));
@ -3399,10 +3402,12 @@ static void _php_curl_close_ex(php_curl *ch)
*
* Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2
*/
curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing);
curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing);
if (ch->cp != NULL) {
curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing);
curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing);
curl_easy_cleanup(ch->cp);
curl_easy_cleanup(ch->cp);
}
/* cURL destructors should be invoked only by last curl handle */
if (--(*ch->clone) == 0) {

View file

@ -63,6 +63,7 @@ PHP_FUNCTION(curl_multi_init)
mh = ecalloc(1, sizeof(php_curlm));
mh->multi = curl_multi_init();
mh->handlers = ecalloc(1, sizeof(php_curlm_handlers));
zend_llist_init(&mh->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0);
@ -400,6 +401,12 @@ void _php_curl_multi_close(zend_resource *rsrc) /* {{{ */
curl_multi_cleanup(mh->multi);
zend_llist_clean(&mh->easyh);
if (mh->handlers->server_push) {
efree(mh->handlers->server_push);
}
if (mh->handlers) {
efree(mh->handlers);
}
efree(mh);
rsrc->ptr = NULL;
}
@ -447,6 +454,83 @@ PHP_FUNCTION(curl_multi_strerror)
/* }}} */
#endif
#if LIBCURL_VERSION_NUM >= 0x072C00 /* Available since 7.44.0 */
static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_headers, struct curl_pushheaders *push_headers, void *userp) /* {{{ */
{
php_curl *ch;
php_curl *parent;
php_curlm *mh = (php_curlm *)userp;
size_t rval = CURL_PUSH_DENY;
php_curlm_server_push *t = mh->handlers->server_push;
zval *pz_parent_ch = NULL;
zval pz_ch;
zval headers;
zval retval;
zend_resource *res;
char *header;
int error;
zend_fcall_info fci = empty_fcall_info;
pz_parent_ch = _php_curl_multi_find_easy_handle(mh, parent_ch);
if (pz_parent_ch == NULL) {
return rval;
}
parent = (php_curl*)zend_fetch_resource(Z_RES_P(pz_parent_ch), le_curl_name, le_curl);
ch = alloc_curl_handle();
ch->cp = easy;
_php_setup_easy_copy_handlers(ch, parent);
Z_ADDREF_P(pz_parent_ch);
res = zend_register_resource(ch, le_curl);
ZVAL_RES(&pz_ch, res);
size_t i;
array_init(&headers);
for(i=0; i<num_headers; i++) {
header = curl_pushheader_bynum(push_headers, i);
add_next_index_string(&headers, header);
}
zend_fcall_info_init(&t->func_name, 0, &fci, &t->fci_cache, NULL, NULL);
zend_fcall_info_argn(
&fci, 3,
pz_parent_ch,
&pz_ch,
&headers
);
fci.retval = &retval;
error = zend_call_function(&fci, &t->fci_cache);
zend_fcall_info_args_clear(&fci, 1);
zval_dtor(&headers);
if (error == FAILURE) {
php_error_docref(NULL, E_WARNING, "Cannot call the CURLMOPT_PUSHFUNCTION");
} else if (!Z_ISUNDEF(retval)) {
if (CURL_PUSH_DENY != zval_get_long(&retval)) {
rval = CURL_PUSH_OK;
/* we want to create a copy of this zval that we store in the multihandle structure element "easyh" */
zval tmp_val;
ZVAL_DUP(&tmp_val, &pz_ch);
zend_llist_add_element(&mh->easyh, &tmp_val);
} else {
/* libcurl will free this easy handle, avoid double free */
ch->cp = NULL;
}
}
return rval;
}
#endif
#if LIBCURL_VERSION_NUM >= 0x070f04 /* 7.15.4 */
static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue, zval *return_value) /* {{{ */
{
@ -468,7 +552,29 @@ static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue,
#endif
error = curl_multi_setopt(mh->multi, option, zval_get_long(zvalue));
break;
#if LIBCURL_VERSION_NUM > 0x072D00 /* Available since 7.46.0 */
case CURLMOPT_PUSHFUNCTION:
if (mh->handlers->server_push == NULL) {
mh->handlers->server_push = ecalloc(1, sizeof(php_curlm_server_push));
} else if (!Z_ISUNDEF(mh->handlers->server_push->func_name)) {
zval_ptr_dtor(&mh->handlers->server_push->func_name);
mh->handlers->server_push->fci_cache = empty_fcall_info_cache;
}
ZVAL_COPY(&mh->handlers->server_push->func_name, zvalue);
mh->handlers->server_push->method = PHP_CURL_USER;
if (!Z_ISUNDEF(mh->handlers->server_push->func_name)) {
zval_ptr_dtor(&mh->handlers->server_push->func_name);
mh->handlers->server_push->fci_cache = empty_fcall_info_cache;
}
error = curl_multi_setopt(mh->multi, option, _php_server_push_callback);
if (error != CURLM_OK) {
return 0;
}
error = curl_multi_setopt(mh->multi, CURLMOPT_PUSHDATA, mh);
break;
#endif
default:
php_error_docref(NULL, E_WARNING, "Invalid curl multi configuration option");
error = CURLM_UNKNOWN_OPTION;

View file

@ -66,6 +66,8 @@ extern int le_curl_multi_handle;
#define le_curl_multi_handle_name "cURL Multi Handle"
extern int le_curl_share_handle;
#define le_curl_share_handle_name "cURL Share Handle"
//extern int le_curl_pushheaders;
//#define le_curl_pushheaders "cURL Push Headers"
PHP_MINIT_FUNCTION(curl);
PHP_MSHUTDOWN_FUNCTION(curl);
@ -146,7 +148,7 @@ typedef struct {
zval func_name;
zend_fcall_info_cache fci_cache;
int method;
} php_curl_progress, php_curl_fnmatch;
} php_curl_progress, php_curl_fnmatch, php_curlm_server_push;
typedef struct {
php_curl_write *write;
@ -190,10 +192,15 @@ typedef struct {
#define CURLOPT_SAFE_UPLOAD -1
typedef struct {
php_curlm_server_push *server_push;
} php_curlm_handlers;
typedef struct {
int still_running;
CURLM *multi;
zend_llist easyh;
php_curlm_handlers *handlers;
struct {
int no;
} err;
@ -206,6 +213,7 @@ typedef struct {
} err;
} php_curlsh;
php_curl *alloc_curl_handle();
void _php_curl_cleanup_handle(php_curl *);
void _php_curl_multi_cleanup_list(void *data);
void _php_curl_verify_handlers(php_curl *ch, int reporterror);