Net-Curl
view release on metacpan or search on metacpan
Curl_Easy.xsh view on Meta::CPAN
SIMPLELL_FREE( easy->strings, Safefree );
SIMPLELL_FREE( easy->slists, curl_slist_free_all );
if ( easy->form_sv )
sv_2mortal( easy->form_sv );
} /*}}}*/
static inline CURLMcode
perl_curl_easy_remove_from_multi( pTHX_ perl_curl_easy_t* easy )
{
CURLMcode ret = CURLM_OK;
if (easy->multi) {
/* NB: We remove easy from multi->easies BEFORE calling
curl_multi_remove_handle(). See below for details.
*/
{
SV *easysv;
easysv = perl_curl_simplell_del( aTHX_ &easy->multi->easies,
PTR2nat( easy ) );
if ( !easysv )
croak( "internal Net::Curl error" );
sv_2mortal( easysv );
}
/* In certain cases curl_multi_remove_handle() invokes a callback
that may decrement the multi SVâs reference count, which triggers
Perlâs garbage collection, which frees the multi while curl
is in the middle of removing an easy from it, which in turn
triggers a segfault.
We avoid that by incrementing/decrementing the reference count.
*/
SvREFCNT_inc( easy->multi->perl_self );
ret = curl_multi_remove_handle( easy->multi->handle, easy->handle );
/* As described above: */
SvREFCNT_dec( easy->multi->perl_self );
easy->multi = NULL;
}
return ret;
}
static void
perl_curl_easy_delete( pTHX_ perl_curl_easy_t *easy )
/*{{{*/ {
/* this may trigger a callback,
* we want it while easy handle is still alive */
curl_easy_setopt( easy->handle, CURLOPT_SHARE, NULL );
/* when using multi handle, the connection may stay open in that multi,
* but the easy will be long dead. In case of ftp for instance, connection
* closing will send a trailer with no apparent destination */
/* this also disables header callback if not using multi, SORRY */
curl_easy_setopt( easy->handle, CURLOPT_HEADERFUNCTION, NULL );
curl_easy_setopt( easy->handle, CURLOPT_WRITEHEADER, NULL );
/* If Perl reaps an easy and its multi "together", there is a
* chance Perl might clear the easy first, leading to a segfault when
* the multi tries to remove an easy that is already cleaned up.
* This prevents that. */
perl_curl_easy_remove_from_multi( aTHX_ easy );
if ( easy->handle )
curl_easy_cleanup( easy->handle );
perl_curl_easy_delete_mostly( aTHX_ easy );
if ( easy->share_sv )
sv_2mortal( easy->share_sv );
Safefree( easy );
} /*}}}*/
static int
perl_curl_easy_magic_free( pTHX_ SV *sv, MAGIC *mg )
{
if ( mg->mg_ptr ) {
/* prevent recursive destruction */
SvREFCNT( sv ) = 1 << 30;
perl_curl_easy_delete( aTHX_ (void *)mg->mg_ptr );
SvREFCNT( sv ) = 0;
}
return 0;
}
static MGVTBL perl_curl_easy_vtbl = {
NULL, NULL, NULL, NULL
,perl_curl_easy_magic_free
,NULL
,perl_curl_any_magic_nodup
#ifdef MGf_LOCAL
,NULL
#endif
};
static void
perl_curl_easy_preset( perl_curl_easy_t *easy )
{
/* configure curl to always callback to the XS interface layer */
curl_easy_setopt( easy->handle, CURLOPT_WRITEFUNCTION, cb_easy_write );
curl_easy_setopt( easy->handle, CURLOPT_READFUNCTION, cb_easy_read );
/* set our own object as the context for all curl callbacks */
curl_easy_setopt( easy->handle, CURLOPT_FILE, easy );
curl_easy_setopt( easy->handle, CURLOPT_INFILE, easy );
/* we always collect this, in case it's wanted */
curl_easy_setopt( easy->handle, CURLOPT_ERRORBUFFER, easy->errbuf );
curl_easy_setopt( easy->handle, CURLOPT_PRIVATE, (void *) easy );
}
#define EASY_DIE( ret ) \
STMT_START { \
CURLcode code = (ret); \
if ( code != CURLE_OK ) \
die_code( "Easy", code ); \
} STMT_END
MODULE = Net::Curl PACKAGE = Net::Curl::Easy
INCLUDE: const-easy-xs.inc
PROTOTYPES: ENABLE
void
new( sclass="Net::Curl::Easy", base=HASHREF_BY_DEFAULT )
const char *sclass
SV *base
PREINIT:
perl_curl_easy_t *easy;
HV *stash;
PPCODE:
if ( ! SvOK( base ) || ! SvROK( base ) )
croak( "object base must be a valid reference\n" );
easy = perl_curl_easy_new();
perl_curl_easy_preset( easy );
perl_curl_setptr( aTHX_ base, &perl_curl_easy_vtbl, easy );
stash = gv_stashpv( sclass, 0 );
ST(0) = sv_bless( base, stash );
easy->perl_self = SvRV( ST(0) );
XSRETURN(1);
void
duphandle( easy, base=HASHREF_BY_DEFAULT )
Net::Curl::Easy easy
SV *base
PREINIT:
perl_curl_easy_t *clone;
const char *sclass;
perl_curl_easy_callback_code_t i;
HV *stash;
PPCODE:
if ( ! SvOK( base ) || ! SvROK( base ) )
croak( "object base must be a valid reference\n" );
sclass = sv_reftype( SvRV( ST(0) ), TRUE );
clone = perl_curl_easy_duphandle( easy );
perl_curl_easy_preset( clone );
if ( easy->cb[ CB_EASY_HEADER ].func
|| easy->cb[ CB_EASY_HEADER ].data ) {
curl_easy_setopt( clone->handle, CURLOPT_HEADERFUNCTION, cb_easy_header );
curl_easy_setopt( clone->handle, CURLOPT_WRITEHEADER, clone );
}
if ( easy->cb[ CB_EASY_PROGRESS ].func ) {
curl_easy_setopt( clone->handle, CURLOPT_PROGRESSFUNCTION, cb_easy_progress );
curl_easy_setopt( clone->handle, CURLOPT_PROGRESSDATA, clone );
}
//
#ifdef CURLOPT_XFERINFOFUNCTION
# ifdef CURLOPT_XFERINFODATA
if ( easy->cb[ CB_EASY_XFERINFO ].func ) {
curl_easy_setopt( clone->handle, CURLOPT_XFERINFOFUNCTION, cb_easy_xferinfo );
curl_easy_setopt( clone->handle, CURLOPT_XFERINFODATA, clone );
}
# endif
#endif
if ( easy->cb[ CB_EASY_DEBUG ].func ) {
curl_easy_setopt( clone->handle, CURLOPT_DEBUGFUNCTION, cb_easy_debug );
curl_easy_setopt( clone->handle, CURLOPT_DEBUGDATA, clone );
}
for( i = 0; i < CB_EASY_LAST; i++ ) {
SvREPLACE( clone->cb[i].func, easy->cb[i].func );
SvREPLACE( clone->cb[i].data, easy->cb[i].data );
};
/* clone strings and set */
if ( easy->strings ) {
simplell_t *in, **out;
in = easy->strings;
out = &clone->strings;
do {
Newx( *out, 1, simplell_t );
(*out)->next = NULL;
(*out)->key = in->key;
(*out)->value = savepv( in->value );
curl_easy_setopt( clone->handle, in->key, (*out)->value );
out = &(*out)->next;
in = in->next;
} while ( in != NULL );
}
/* clone slists and set */
if ( easy->slists ) {
simplell_t *in, **out;
struct curl_slist *sin, *sout;
in = easy->slists;
out = &clone->slists;
do {
Newx( *out, 1, simplell_t );
sout = NULL;
sin = in->value;
do {
sout = curl_slist_append( sout, sin->data );
} while ( ( sin = sin->next ) != NULL );
(*out)->next = NULL;
(*out)->key = in->key;
(*out)->value = sout;
( run in 2.052 seconds using v1.01-cache-2.11-cpan-437f7b0c052 )