/* * Perl interface for libcurl. Check out the file README for more info. */ /* * Copyright (C) 2000, 2001, 2002, 2005, 2008 Daniel Stenberg, Cris Bailiff, et al. * You may opt to use, copy, modify, merge, publish, distribute and/or * sell copies of the Software, and permit persons to whom the * Software is furnished to do so, under the terms of the MIT license. */ #define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include #include #define header_callback_func writeheader_callback_func /* Do a favor for older perl versions */ #ifndef Newxz # define Newxz(v,n,t) Newz(0,v,n,t) #endif typedef enum { CALLBACK_WRITE = 0, CALLBACK_READ, CALLBACK_HEADER, CALLBACK_PROGRESS, CALLBACK_DEBUG, CALLBACK_LAST } perl_curl_easy_callback_code; typedef enum { SLIST_HTTPHEADER = 0, SLIST_QUOTE, SLIST_POSTQUOTE, #ifdef CURLOPT_RESOLVE SLIST_RESOLVE, #endif SLIST_LAST } perl_curl_easy_slist_code; typedef struct { /* The main curl handle */ struct CURL *curl; I32 *y; /* Lists that can be set via curl_easy_setopt() */ struct curl_slist *slist[SLIST_LAST]; SV *callback[CALLBACK_LAST]; SV *callback_ctx[CALLBACK_LAST]; /* copy of error buffer var for caller*/ char errbuf[CURL_ERROR_SIZE+1]; char *errbufvarname; I32 strings_index; char* strings[CURLOPTTYPE_FUNCTIONPOINT - 10000]; } perl_curl_easy; typedef struct { struct curl_httppost * post; struct curl_httppost * last; } perl_curl_form; typedef struct { #ifdef __CURL_MULTI_H struct CURLM *curlm; #else struct void *curlm; #endif } perl_curl_multi; typedef struct { struct CURLSH *curlsh; } perl_curl_share; /* switch from curl option codes to the relevant callback index */ static perl_curl_easy_callback_code callback_index(int option) { switch(option) { case CURLOPT_WRITEFUNCTION: case CURLOPT_FILE: return CALLBACK_WRITE; break; case CURLOPT_READFUNCTION: case CURLOPT_INFILE: return CALLBACK_READ; break; case CURLOPT_HEADERFUNCTION: case CURLOPT_WRITEHEADER: return CALLBACK_HEADER; break; case CURLOPT_PROGRESSFUNCTION: case CURLOPT_PROGRESSDATA: return CALLBACK_PROGRESS; break; case CURLOPT_DEBUGFUNCTION: case CURLOPT_DEBUGDATA: return CALLBACK_DEBUG; break; } croak("Bad callback index requested\n"); return CALLBACK_LAST; } /* switch from curl slist names to an slist index */ static perl_curl_easy_slist_code slist_index(int option) { switch(option) { case CURLOPT_HTTPHEADER: return SLIST_HTTPHEADER; break; case CURLOPT_QUOTE: return SLIST_QUOTE; break; case CURLOPT_POSTQUOTE: return SLIST_POSTQUOTE; break; #ifdef CURLOPT_RESOLVE case CURLOPT_RESOLVE: return SLIST_RESOLVE; break; #endif } croak("Bad slist index requested\n"); return SLIST_LAST; } static perl_curl_easy * perl_curl_easy_new() { perl_curl_easy *self; Newz(1, self, 1, perl_curl_easy); self->curl=curl_easy_init(); return self; } static perl_curl_easy * perl_curl_easy_duphandle(perl_curl_easy *orig) { perl_curl_easy *self; Newz(1, self, 1, perl_curl_easy); self->curl=curl_easy_duphandle(orig->curl); return self; } static void perl_curl_easy_delete(perl_curl_easy *self) { dTHX; perl_curl_easy_slist_code index; perl_curl_easy_callback_code i; if (self->curl) curl_easy_cleanup(self->curl); *self->y = *self->y - 1; if (*self->y <= 0) { for (index=0;indexslist[index]) curl_slist_free_all(self->slist[index]); }; Safefree(self->y); } for(i=0;icallback[i]); } for(i=0;icallback_ctx[i]); } if (self->errbufvarname) free(self->errbufvarname); for (i=0;i<=self->strings_index;i++) { if (self->strings[i] != NULL) { char* ptr = self->strings[i]; Safefree(ptr); } } Safefree(self); } /* Register a callback function */ static void perl_curl_easy_register_callback(perl_curl_easy *self, SV **callback, SV *function) { dTHX; if (function && SvOK(function)) { /* FIXME: need to check the ref-counts here */ if (*callback == NULL) { *callback = newSVsv(function); } else { SvSetSV(*callback, function); } } else { if (*callback != NULL) { sv_2mortal(*callback); *callback = NULL; } } } /* start of form functions - very un-finished! */ static perl_curl_form * perl_curl_form_new() { perl_curl_form *self; Newz(1, self, 1, perl_curl_form); self->post=NULL; self->last=NULL; return self; } static void perl_curl_form_delete(perl_curl_form *self) { if (self->post) { curl_formfree(self->post); } Safefree(self); } /* make a new multi */ static perl_curl_multi * perl_curl_multi_new() { perl_curl_multi *self; Newz(1, self, 1, perl_curl_multi); #ifdef __CURL_MULTI_H self->curlm=curl_multi_init(); #else croak("curl version too old to support curl_multi_init()"); #endif return self; } /* delete the multi */ static void perl_curl_multi_delete(perl_curl_multi *self) { #ifdef __CURL_MULTI_H if (self->curlm) curl_multi_cleanup(self->curlm); Safefree(self); #endif } /* make a new share */ static perl_curl_share * perl_curl_share_new() { perl_curl_share *self; Newz(1, self, 1, perl_curl_share); self->curlsh=curl_share_init(); return self; } /* delete the share */ static void perl_curl_share_delete(perl_curl_share *self) { if (self->curlsh) curl_share_cleanup(self->curlsh); Safefree(self); } static size_t write_to_ctx(pTHX_ SV* const call_ctx, const char* const ptr, size_t const n) { PerlIO *handle; SV* out_str; if (call_ctx) { /* a GLOB or a SCALAR ref */ if(SvROK(call_ctx) && SvTYPE(SvRV(call_ctx)) <= SVt_PVMG) { /* write to a scalar ref */ out_str = SvRV(call_ctx); if (SvOK(out_str)) { sv_catpvn(out_str, ptr, n); } else { sv_setpvn(out_str, ptr, n); } return n; } else { /* write to a filehandle */ handle = IoOFP(sv_2io(call_ctx)); } } else { /* punt to stdout */ handle = PerlIO_stdout(); } return PerlIO_write(handle, ptr, n); } /* generic fwrite callback, which decides which callback to call */ static size_t fwrite_wrapper ( const void *ptr, size_t size, size_t nmemb, perl_curl_easy *self, void *call_function, void *call_ctx) { dTHX; if (call_function) { /* We are doing a callback to perl */ dSP; int count, status; ENTER; SAVETMPS; PUSHMARK(SP); if (ptr) { XPUSHs(sv_2mortal(newSVpvn((char *)ptr, (STRLEN)(size * nmemb)))); } else { /* just in case */ XPUSHs(&PL_sv_undef); } if (call_ctx) { XPUSHs(sv_2mortal(newSVsv(call_ctx))); } else { /* should be a stdio glob ? */ XPUSHs(&PL_sv_undef); } PUTBACK; count = perl_call_sv((SV *) call_function, G_SCALAR); SPAGAIN; if (count != 1) croak("callback for CURLOPT_WRITEFUNCTION didn't return a status\n"); status = POPi; PUTBACK; FREETMPS; LEAVE; return status; } else { return write_to_ctx(aTHX_ call_ctx, ptr, size * nmemb); } } /* debug fwrite callback */ static size_t fwrite_wrapper2 ( const void *ptr, size_t size, perl_curl_easy *self, void *call_function, void *call_ctx, int curl_infotype) { dTHX; dSP; if (call_function) { /* We are doing a callback to perl */ int count, status; SV *sv; ENTER; SAVETMPS; PUSHMARK(SP); if (ptr) { XPUSHs(sv_2mortal(newSVpvn((char *)ptr, (STRLEN)(size * sizeof(char))))); } else { /* just in case */ XPUSHs(&PL_sv_undef); } if (call_ctx) { XPUSHs(sv_2mortal(newSVsv(call_ctx))); } else { /* should be a stdio glob ? */ XPUSHs(&PL_sv_undef); } XPUSHs(sv_2mortal(newSViv(curl_infotype))); PUTBACK; count = perl_call_sv((SV *) call_function, G_SCALAR); SPAGAIN; if (count != 1) croak("callback for CURLOPT_*FUNCTION didn't return a status\n"); status = POPi; PUTBACK; FREETMPS; LEAVE; return status; } else { return write_to_ctx(aTHX_ call_ctx, ptr, size * sizeof(char)); } } /* Write callback for calling a perl callback */ static size_t write_callback_func(const void *ptr, size_t size, size_t nmemb, void *stream) { perl_curl_easy *self; self=(perl_curl_easy *)stream; return fwrite_wrapper(ptr,size,nmemb,self, self->callback[CALLBACK_WRITE],self->callback_ctx[CALLBACK_WRITE]); } /* header callback for calling a perl callback */ static size_t writeheader_callback_func(const void *ptr, size_t size, size_t nmemb, void *stream) { perl_curl_easy *self; self=(perl_curl_easy *)stream; return fwrite_wrapper(ptr,size,nmemb,self, self->callback[CALLBACK_HEADER],self->callback_ctx[CALLBACK_HEADER]); } /* debug callback for calling a perl callback */ static size_t debug_callback_func(CURL* handle, int curl_infotype, const void *ptr, size_t size, void *stream) { perl_curl_easy *self; self=(perl_curl_easy *)stream; return fwrite_wrapper2(ptr,size,self, self->callback[CALLBACK_DEBUG],self->callback_ctx[CALLBACK_DEBUG],curl_infotype); } /* read callback for calling a perl callback */ static size_t read_callback_func( void *ptr, size_t size, size_t nmemb, void *stream) { dTHX; dSP ; size_t maxlen; perl_curl_easy *self; self=(perl_curl_easy *)stream; maxlen = size*nmemb; if (self->callback[CALLBACK_READ]) { /* We are doing a callback to perl */ char *data; int count; SV *sv; STRLEN len; ENTER ; SAVETMPS ; PUSHMARK(SP) ; if (self->callback_ctx[CALLBACK_READ]) { sv = self->callback_ctx[CALLBACK_READ]; } else { sv = &PL_sv_undef; } XPUSHs(sv_2mortal(newSViv(maxlen))); XPUSHs(sv_2mortal(newSVsv(sv))); PUTBACK ; count = perl_call_sv(self->callback[CALLBACK_READ], G_SCALAR); SPAGAIN; if (count != 1) croak("callback for CURLOPT_READFUNCTION didn't return any data\n"); sv = POPs; data = SvPV(sv,len); /* only allowed to return the number of bytes asked for */ len = (lencallback_ctx[CALLBACK_READ]) { /* hope its a GLOB! */ f = IoIFP(sv_2io(self->callback_ctx[CALLBACK_READ])); } else { /* punt to stdin */ f = PerlIO_stdin(); } return PerlIO_read(f,ptr,maxlen); } } /* Progress callback for calling a perl callback */ static int progress_callback_func(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { dTHX; dSP; int count; perl_curl_easy *self; self=(perl_curl_easy *)clientp; ENTER; SAVETMPS; PUSHMARK(sp); if (self->callback_ctx[CALLBACK_PROGRESS]) { XPUSHs(sv_2mortal(newSVsv(self->callback_ctx[CALLBACK_PROGRESS]))); } else { XPUSHs(&PL_sv_undef); } XPUSHs(sv_2mortal(newSVnv(dltotal))); XPUSHs(sv_2mortal(newSVnv(dlnow))); XPUSHs(sv_2mortal(newSVnv(ultotal))); XPUSHs(sv_2mortal(newSVnv(ulnow))); PUTBACK; count = perl_call_sv(self->callback[CALLBACK_PROGRESS], G_SCALAR); SPAGAIN; if (count != 1) croak("callback for CURLOPT_PROGRESSFUNCTION didn't return 1\n"); count = POPi; PUTBACK; FREETMPS; LEAVE; return count; } #if 0 /* awaiting closepolicy prototype */ int closepolicy_callback_func(void *clientp) { dSP; int argc, status; SV *pl_status; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; argc = perl_call_sv(closepolicy_callback, G_SCALAR); SPAGAIN; if (argc != 1) { croak("Unexpected number of arguments returned from closefunction callback\n"); } pl_status = POPs; status = SvTRUE(pl_status) ? 0 : 1; PUTBACK; FREETMPS; LEAVE; return status; } #endif #include "curlopt-constants.c" typedef perl_curl_easy * WWW__Curl__Easy; typedef perl_curl_form * WWW__Curl__Form; typedef perl_curl_multi * WWW__Curl__Multi; typedef perl_curl_share * WWW__Curl__Share; MODULE = WWW::Curl PACKAGE = WWW::Curl PREFIX = curl_ void curl__global_cleanup() CODE: curl_global_cleanup(); MODULE = WWW::Curl PACKAGE = WWW::Curl::Easy PREFIX = curl_easy_ BOOT: curl_global_init(CURL_GLOBAL_ALL); /* FIXME: does this need a mutex for ithreads? */ PROTOTYPES: ENABLE int constant(name) char * name void curl_easy_init(...) ALIAS: new = 1 PREINIT: perl_curl_easy *self; char *sclass = "WWW::Curl::Easy"; PPCODE: if (items>0 && !SvROK(ST(0))) { STRLEN dummy; sclass = SvPV(ST(0),dummy); } self=perl_curl_easy_new(); /* curl handle created by this point */ ST(0) = sv_newmortal(); sv_setref_pv(ST(0), sclass, (void*)self); SvREADONLY_on(SvRV(ST(0))); Newxz(self->y,1,I32); if (!self->y) { croak ("out of memory"); } (*self->y)++; /* configure curl to always callback to the XS interface layer */ curl_easy_setopt(self->curl, CURLOPT_WRITEFUNCTION, write_callback_func); curl_easy_setopt(self->curl, CURLOPT_READFUNCTION, read_callback_func); /* set our own object as the context for all curl callbacks */ curl_easy_setopt(self->curl, CURLOPT_FILE, self); curl_easy_setopt(self->curl, CURLOPT_INFILE, self); /* we always collect this, in case it's wanted */ curl_easy_setopt(self->curl, CURLOPT_ERRORBUFFER, self->errbuf); XSRETURN(1); void curl_easy_duphandle(self) WWW::Curl::Easy self PREINIT: perl_curl_easy *clone; char *sclass = "WWW::Curl::Easy"; perl_curl_easy_callback_code i; PPCODE: clone=perl_curl_easy_duphandle(self); clone->y = self->y; (*self->y)++; ST(0) = sv_newmortal(); sv_setref_pv(ST(0), sclass, (void*)clone); SvREADONLY_on(SvRV(ST(0))); /* configure curl to always callback to the XS interface layer */ curl_easy_setopt(clone->curl, CURLOPT_WRITEFUNCTION, write_callback_func); curl_easy_setopt(clone->curl, CURLOPT_READFUNCTION, read_callback_func); if (self->callback[callback_index(CURLOPT_HEADERFUNCTION)] || self->callback_ctx[callback_index(CURLOPT_WRITEHEADER)]) { curl_easy_setopt(clone->curl, CURLOPT_HEADERFUNCTION, header_callback_func); curl_easy_setopt(clone->curl, CURLOPT_WRITEHEADER, clone); } if (self->callback[callback_index(CURLOPT_PROGRESSFUNCTION)] || self->callback_ctx[callback_index(CURLOPT_PROGRESSDATA)]) { curl_easy_setopt(clone->curl, CURLOPT_PROGRESSFUNCTION, progress_callback_func); curl_easy_setopt(clone->curl, CURLOPT_PROGRESSDATA, clone); } if (self->callback[callback_index(CURLOPT_DEBUGFUNCTION)] || self->callback_ctx[callback_index(CURLOPT_DEBUGDATA)]) { curl_easy_setopt(clone->curl, CURLOPT_DEBUGFUNCTION, debug_callback_func); curl_easy_setopt(clone->curl, CURLOPT_DEBUGDATA, clone); } /* set our own object as the context for all curl callbacks */ curl_easy_setopt(clone->curl, CURLOPT_FILE, clone); curl_easy_setopt(clone->curl, CURLOPT_INFILE, clone); curl_easy_setopt(clone->curl, CURLOPT_ERRORBUFFER, clone->errbuf); for(i=0;icallback[i]), self->callback[i]); perl_curl_easy_register_callback(clone,&(clone->callback_ctx[i]), self->callback_ctx[i]); }; for (i=0;i<=self->strings_index;i++) { if (self->strings[i] != NULL) { clone->strings[i] = savepv(self->strings[i]); curl_easy_setopt(clone->curl, 10000 + i, clone->strings[i]); } } clone->strings_index = self->strings_index; XSRETURN(1); char * curl_easy_version(...) CODE: RETVAL=curl_version(); OUTPUT: RETVAL int curl_easy_setopt(self, option, value, push=0) WWW::Curl::Easy self int option SV * value int push CODE: RETVAL=CURLE_OK; switch(option) { /* SV * to user contexts for callbacks - any SV (glob,scalar,ref) */ case CURLOPT_FILE: case CURLOPT_INFILE: perl_curl_easy_register_callback(self, &(self->callback_ctx[callback_index(option)]), value); break; case CURLOPT_WRITEHEADER: curl_easy_setopt(self->curl, CURLOPT_HEADERFUNCTION, SvOK(value) ? header_callback_func : NULL); curl_easy_setopt(self->curl, option, SvOK(value) ? self : NULL); perl_curl_easy_register_callback(self,&(self->callback_ctx[callback_index(option)]),value); break; case CURLOPT_PROGRESSDATA: curl_easy_setopt(self->curl, CURLOPT_PROGRESSFUNCTION, SvOK(value) ? progress_callback_func : NULL); curl_easy_setopt(self->curl, option, SvOK(value) ? self : NULL); perl_curl_easy_register_callback(self,&(self->callback_ctx[callback_index(option)]), value); break; case CURLOPT_DEBUGDATA: curl_easy_setopt(self->curl, CURLOPT_DEBUGFUNCTION, SvOK(value) ? debug_callback_func : NULL); curl_easy_setopt(self->curl, option, SvOK(value) ? self : NULL); perl_curl_easy_register_callback(self,&(self->callback_ctx[callback_index(option)]), value); break; /* SV * to a subroutine ref */ case CURLOPT_WRITEFUNCTION: case CURLOPT_READFUNCTION: perl_curl_easy_register_callback(self,&(self->callback[callback_index(option)]), value); break; case CURLOPT_HEADERFUNCTION: curl_easy_setopt(self->curl, option, SvOK(value) ? header_callback_func : NULL); curl_easy_setopt(self->curl, CURLOPT_WRITEHEADER, SvOK(value) ? self : NULL); perl_curl_easy_register_callback(self,&(self->callback[callback_index(option)]), value); break; case CURLOPT_PROGRESSFUNCTION: curl_easy_setopt(self->curl, option, SvOK(value) ? progress_callback_func : NULL); curl_easy_setopt(self->curl, CURLOPT_PROGRESSDATA, SvOK(value) ? self : NULL); perl_curl_easy_register_callback(self,&(self->callback[callback_index(option)]), value); break; case CURLOPT_DEBUGFUNCTION: curl_easy_setopt(self->curl, option, SvOK(value) ? debug_callback_func : NULL); curl_easy_setopt(self->curl, CURLOPT_DEBUGDATA, SvOK(value) ? self : NULL); perl_curl_easy_register_callback(self,&(self->callback[callback_index(option)]), value); break; /* slist cases */ case CURLOPT_HTTPHEADER: case CURLOPT_QUOTE: case CURLOPT_POSTQUOTE: #ifdef CURLOPT_RESOLVE case CURLOPT_RESOLVE: #endif { /* This is an option specifying a list, which we put in a curl_slist struct */ AV *array = (AV *)SvRV(value); struct curl_slist **slist = NULL; int last = av_len(array); int i; /* We have to find out which list to use... */ slist = &(self->slist[slist_index(option)]); /* free any previous list */ if (*slist && !push) { curl_slist_free_all(*slist); *slist=NULL; } /* copy perl values into this slist */ for (i=0;i<=last;i++) { SV **sv = av_fetch(array,i,0); STRLEN len = 0; char *string = SvPV(*sv, len); if (len == 0) /* FIXME: is this correct? */ break; *slist = curl_slist_append(*slist, string); } /* pass the list into curl_easy_setopt() */ RETVAL = curl_easy_setopt(self->curl, option, *slist); }; break; /* Pass in variable name for storing error messages. Yuck. */ case CURLOPT_ERRORBUFFER: { STRLEN dummy; if (self->errbufvarname) free(self->errbufvarname); self->errbufvarname = strdup((char *)SvPV(value, dummy)); }; break; /* tell curl to redirect STDERR - value should be a glob */ case CURLOPT_STDERR: RETVAL = curl_easy_setopt(self->curl, option, IoOFP(sv_2io(value)) ); break; /* not working yet... */ case CURLOPT_HTTPPOST: if (sv_derived_from(value, "WWW::Curl::Form")) { WWW__Curl__Form wrapper; IV tmp = SvIV((SV*)SvRV(value)); wrapper = INT2PTR(WWW__Curl__Form,tmp); RETVAL = curl_easy_setopt(self->curl, option, wrapper->post); } else croak("value is not of type WWW::Curl::Form"); break; /* Curl share support from Anton Fedorov */ #if (LIBCURL_VERSION_NUM>=0x070a03) case CURLOPT_SHARE: if (sv_derived_from(value, "WWW::Curl::Share")) { WWW__Curl__Share wrapper; IV tmp = SvIV((SV*)SvRV(value)); wrapper = INT2PTR(WWW__Curl__Share,tmp); RETVAL = curl_easy_setopt(self->curl, option, wrapper->curlsh); } else croak("value is not of type WWW::Curl::Share"); break; #endif /* default cases */ default: if (option < CURLOPTTYPE_OBJECTPOINT) { /* A long (integer) value */ RETVAL = curl_easy_setopt(self->curl, option, (long)SvIV(value)); } else if (option < CURLOPTTYPE_FUNCTIONPOINT) { /* An objectpoint - string */ /* FIXME: Does curl really want NULL for empty strings? */ STRLEN dummy = 0; /* Pre 7.17.0, the strings aren't copied by libcurl.*/ char* pv = SvOK(value) ? SvPV(value, dummy) : ""; I32 len = (I32)dummy; pv = savepvn(pv, len); if (self->strings[option-10000] != NULL) Safefree(self->strings[option-10000]); self->strings[option-10000] = pv; if (self->strings_index < option - 10000) self->strings_index = option - 10000; RETVAL = curl_easy_setopt(self->curl, option, SvOK(value) ? pv : NULL); } #ifdef CURLOPTTYPE_OFF_T else if (option < CURLOPTTYPE_OFF_T) { /* A function - notreached? */ croak("Unknown curl option of type function"); } else { /* A LARGE file option using curl_off_t, handling larger than 32bit sizes without 64bit integer support */ if (SvOK(value) && looks_like_number(value)) { STRLEN dummy = 0; char* pv = SvPV(value, dummy); char* pdummy; RETVAL = curl_easy_setopt(self->curl, option, (curl_off_t) strtoll(pv,&pdummy,10)); } else { RETVAL = 0; } } #endif ; break; }; OUTPUT: RETVAL int internal_setopt(self, option, value) WWW::Curl::Easy self int option int value CODE: croak("internal_setopt no longer supported - use a callback\n"); RETVAL = 0; OUTPUT: RETVAL int curl_easy_perform(self) WWW::Curl::Easy self CODE: /* perform the actual curl fetch */ RETVAL = curl_easy_perform(self->curl); if (RETVAL && self->errbufvarname) { /* If an error occurred and a varname for error messages has been specified, store the error message. */ SV *sv = perl_get_sv(self->errbufvarname, TRUE | GV_ADDMULTI); sv_setpv(sv, self->errbuf); } OUTPUT: RETVAL SV * curl_easy_getinfo(self, option, ... ) WWW::Curl::Easy self int option CODE: switch (option & CURLINFO_TYPEMASK) { case CURLINFO_STRING: { char * vchar; curl_easy_getinfo(self->curl, option, &vchar); RETVAL = newSVpv(vchar,0); break; } case CURLINFO_LONG: { long vlong; curl_easy_getinfo(self->curl, option, &vlong); RETVAL = newSViv(vlong); break; } case CURLINFO_DOUBLE: { double vdouble; curl_easy_getinfo(self->curl, option, &vdouble); RETVAL = newSVnv(vdouble); break; } #ifdef CURLINFO_SLIST case CURLINFO_SLIST: { struct curl_slist *vlist, *entry; AV *items = newAV(); curl_easy_getinfo(self->curl, option, &vlist); if (vlist != NULL) { entry = vlist; while (entry) { av_push(items, newSVpv(entry->data, 0)); entry = entry->next; } curl_slist_free_all(vlist); } RETVAL = newRV(sv_2mortal((SV *) items)); break; } #endif /* CURLINFO_SLIST */ default: { RETVAL = newSViv(CURLE_BAD_FUNCTION_ARGUMENT); break; } } if (items > 2) sv_setsv(ST(2),RETVAL); OUTPUT: RETVAL char * curl_easy_errbuf(self) WWW::Curl::Easy self CODE: RETVAL = self->errbuf; OUTPUT: RETVAL int curl_easy_cleanup(self) WWW::Curl::Easy self CODE: /* does nothing anymore - cleanup is automatic when a curl handle goes out of scope */ RETVAL = 0; OUTPUT: RETVAL void curl_easy_DESTROY(self) WWW::Curl::Easy self CODE: perl_curl_easy_delete(self); SV * curl_easy_strerror(self, errornum) WWW::Curl::Easy self int errornum CODE: { #if (LIBCURL_VERSION_NUM>=0x070C00) const char * vchar = curl_easy_strerror(errornum); #else const char * vchar = "Unknown because curl_easy_strerror function not available}"; #endif RETVAL = newSVpv(vchar,0); } OUTPUT: RETVAL MODULE = WWW::Curl PACKAGE = WWW::Curl::Form PREFIX = curl_form_ int constant(name) char * name void curl_form_new(...) PREINIT: perl_curl_form *self; char *sclass = "WWW::Curl::Form"; PPCODE: if (items>0 && !SvROK(ST(0))) { STRLEN dummy; sclass = SvPV(ST(0),dummy); } self=perl_curl_form_new(); ST(0) = sv_newmortal(); sv_setref_pv(ST(0), sclass, (void*)self); SvREADONLY_on(SvRV(ST(0))); XSRETURN(1); void curl_form_formadd(self,name,value) WWW::Curl::Form self char *name char *value CODE: curl_formadd(&(self->post),&(self->last), CURLFORM_COPYNAME,name, CURLFORM_COPYCONTENTS,value, CURLFORM_END); void curl_form_formaddfile(self,filename,description,type) WWW::Curl::Form self char *filename char *description char *type CODE: curl_formadd(&(self->post),&(self->last), CURLFORM_FILE,filename, CURLFORM_COPYNAME,description, CURLFORM_CONTENTTYPE,type, CURLFORM_END); void curl_form_DESTROY(self) WWW::Curl::Form self CODE: perl_curl_form_delete(self); MODULE = WWW::Curl PACKAGE = WWW::Curl::Multi PREFIX = curl_multi_ void curl_multi_new(...) PREINIT: perl_curl_multi *self; char *sclass = "WWW::Curl::Multi"; PPCODE: if (items>0 && !SvROK(ST(0))) { STRLEN dummy; sclass = SvPV(ST(0),dummy); } self=perl_curl_multi_new(); ST(0) = sv_newmortal(); sv_setref_pv(ST(0), sclass, (void*)self); SvREADONLY_on(SvRV(ST(0))); XSRETURN(1); void curl_multi_add_handle(curlm, curl) WWW::Curl::Multi curlm WWW::Curl::Easy curl CODE: #ifdef __CURL_MULTI_H curl_multi_add_handle(curlm->curlm, curl->curl); #endif void curl_multi_remove_handle(curlm, curl) WWW::Curl::Multi curlm WWW::Curl::Easy curl CODE: #ifdef __CURL_MULTI_H curl_multi_remove_handle(curlm->curlm, curl->curl); #endif void curl_multi_info_read(self) WWW::Curl::Multi self PREINIT: CURL *easy = NULL; CURLcode res; char *stashid; int queue; CURLMsg *msg; PPCODE: while ((msg = curl_multi_info_read(self->curlm, &queue))) { if (msg->msg == CURLMSG_DONE) { easy=msg->easy_handle; res=msg->data.result; break; } }; if (easy) { curl_easy_getinfo(easy, CURLINFO_PRIVATE, &stashid); curl_easy_setopt(easy, CURLINFO_PRIVATE, NULL); curl_multi_remove_handle(self->curlm, easy); XPUSHs(sv_2mortal(newSVpv(stashid,0))); XPUSHs(sv_2mortal(newSViv(res))); } else { XSRETURN_EMPTY; } SV * curl_multi_fdset(self) WWW::Curl::Multi self PREINIT: fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd; int i; AV *readset; AV *writeset; AV *excepset; PPCODE: FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); readset = newAV(); writeset = newAV(); excepset = newAV(); curl_multi_fdset(self->curlm, &fdread, &fdwrite, &fdexcep, &maxfd); if ( maxfd != -1 ) { for (i=0;i <= maxfd;i++) { if (FD_ISSET(i, &fdread)) { av_push(readset, newSViv(i)); } if (FD_ISSET(i, &fdwrite)) { av_push(writeset, newSViv(i)); } if (FD_ISSET(i, &fdexcep)) { av_push(excepset, newSViv(i)); } } } XPUSHs(sv_2mortal(newRV(sv_2mortal((SV *) readset)))); XPUSHs(sv_2mortal(newRV(sv_2mortal((SV *) writeset)))); XPUSHs(sv_2mortal(newRV(sv_2mortal((SV *) excepset)))); int curl_multi_perform(self) WWW::Curl::Multi self PREINIT: int remaining; CODE: #ifdef __CURL_MULTI_H while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(self->curlm, &remaining)); RETVAL = remaining; /* while(remaining) { struct timeval timeout; int rc; fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_fdset(self->curlm, &fdread, &fdwrite, &fdexcep, &maxfd); rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); switch(rc) { case -1: break; default: while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(self->curlm, &remaining)); break; } } */ #endif OUTPUT: RETVAL void curl_multi_DESTROY(self) WWW::Curl::Multi self CODE: perl_curl_multi_delete(self); SV * curl_multi_strerror(self, errornum) WWW::Curl::Multi self int errornum CODE: { #if (LIBCURL_VERSION_NUM>=0x070C00) const char * vchar = curl_multi_strerror(errornum); #else const char * vchar = "Unknown because curl_multi_strerror function not available}"; #endif RETVAL = newSVpv(vchar,0); } OUTPUT: RETVAL MODULE = WWW::Curl PACKAGE = WWW::Curl::Share PREFIX = curl_share_ PROTOTYPES: ENABLE int constant(name) char * name void curl_share_new(...) PREINIT: perl_curl_share *self; char *sclass = "WWW::Curl::Share"; PPCODE: if (items>0 && !SvROK(ST(0))) { STRLEN dummy; sclass = SvPV(ST(0),dummy); } self=perl_curl_share_new(); ST(0) = sv_newmortal(); sv_setref_pv(ST(0), sclass, (void*)self); SvREADONLY_on(SvRV(ST(0))); XSRETURN(1); void curl_share_DESTROY(self) WWW::Curl::Share self CODE: perl_curl_share_delete(self); int curl_share_setopt(self, option, value) WWW::Curl::Share self int option SV * value CODE: RETVAL=CURLE_OK; #if (LIBCURL_VERSION_NUM>=0x070a03) switch(option) { /* slist cases */ case CURLSHOPT_SHARE: case CURLSHOPT_UNSHARE: if (option < CURLOPTTYPE_OBJECTPOINT) { /* An integer value: */ RETVAL = curl_share_setopt(self->curlsh, option, (long)SvIV(value)); } else { /* A char * value: */ /* FIXME: Does curl really want NULL for empty strings? */ STRLEN dummy; char *pv = SvPV(value, dummy); RETVAL = curl_share_setopt(self->curlsh, option, *pv ? pv : NULL); }; break; }; #else croak("curl_share_setopt not supported in your libcurl version"); #endif OUTPUT: RETVAL SV * curl_share_strerror(self, errornum) WWW::Curl::Share self int errornum CODE: { #if (LIBCURL_VERSION_NUM>=0x070C00) const char * vchar = curl_share_strerror(errornum); #else const char * vchar = "Unknown because curl_share_strerror function not available}"; #endif RETVAL = newSVpv(vchar,0); } OUTPUT: RETVAL