AnyEvent-YACurl

 view release on metacpan or  search on metacpan

YACurl.xs  view on Meta::CPAN

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"
#define MY_CXT_KEY "AnyEvent::YACurl::_guts" XS_VERSION

#include <curl/curl.h>
#include "libcurl-symbols.h"

typedef struct {
    SV *watchset_fn;
    SV *timerset_fn;
    HV *curlopt;
} my_cxt_t;

typedef struct {
    CURLM *multi;
    SV *weak_self_ref;

    int needs_invoke_timeout;
    int needs_read_info;
    int last_running;
} AnyEvent__YACurl;

typedef struct {
    SV *self_rv;
    CURL *easy;
    curl_mime *mimepost;

    AV *held_references;
    FILE *redirected_stderr;
    int slists_count;
    struct curl_slist **slists;
    char errbuf[CURL_ERROR_SIZE];

    SV *callback;
} AnyEvent__YACurl__Response;

START_MY_CXT

struct curl_slist *slist_from_av(pTHX_ struct curl_slist *list, AV *input);

void maybe_warn_eval(pTHX)
{
    SV *error = ERRSV;
    if (SvTRUE(error)) {
        warn("Error in callback: %s", SvPV_nolen(error));
    }
}

int mcurl_socket_callback(CURL* easy,
                          curl_socket_t s,
                          int what,
                          void* userp,
                          void* socketp)
{
    dTHX;
    dMY_CXT;
    dSP;

    ENTER;
    SAVETMPS;

    PUSHMARK(SP);
    EXTEND(SP, 3);
    PUSHs((SV*)userp); /* XXX This is a weakened reference, will it ever be undef? */
    PUSHs(sv_2mortal(newSViv(s)));
    PUSHs(sv_2mortal(newSViv(what)));
    PUTBACK;

    call_sv(MY_CXT.watchset_fn, G_DISCARD | G_VOID);

    FREETMPS;
    LEAVE;

    return 0;
}

int mcurl_timer_callback(CURLM* multi,
                         long timeout_ms,
                         void *userp)
{
    dTHX;

    if (timeout_ms == 0) {
        /* We short-circuit timeout_ms==0, as we're very likely to call do_post_work shortly
         * after reaching this code path. A timer of 0sec in AnyEvent would almost always turn
         * into a 1ms wait, which is unnecessary and slow. Same goes for AE::postpone. */
        IV tmp = SvIV((SV*)SvRV((SV*)userp));
        AnyEvent__YACurl *client = INT2PTR(AnyEvent__YACurl*, tmp);

YACurl.xs  view on Meta::CPAN


            char *str_copy;
            Newx(str_copy, len+1, char);
            strncpy(str_copy, str, len);
            str_copy[len] = 0x00;

            result = curl_easy_setopt(request->easy, option, str_copy);

            Safefree(str_copy);
            break;
        }

        /* Longs */
#include "curlopt-long.inc"
        {
            long param = SvIV(parameter);
            result = curl_easy_setopt(request->easy, option, param);
            break;
        }

        /* off_t's */
#include "curlopt-off-t.inc"
        {
            curl_off_t param = SvIV(parameter);
            result = curl_easy_setopt(request->easy, option, param);
            break;
        }

        /* string lists */
#include "curlopt-slist.inc"
        {
            if (!SvROK(parameter) || SvTYPE(SvRV(parameter)) != SVt_PVAV) {
                croak("Cannot convert %s to ARRAY reference", SvPV_nolen(parameter));

            } else {
                struct curl_slist *list = slist_from_av(aTHX_ NULL, (AV*)SvRV(parameter));
                result = curl_easy_setopt(request->easy, option, list);

                Renew(request->slists, request->slists_count+1, struct curl_slist*);
                request->slists[request->slists_count] = list;
                request->slists_count++;
            }
            break;
        }

#ifdef CURL_BLOB_COPY
        /* blobs */
#include "curlopt-blob.inc"
        {
            struct curl_blob blob;
            blob.data = SvPV(parameter, blob.len);
            blob.flags = CURL_BLOB_COPY;
            result = curl_easy_setopt(request->easy, option, &blob);
            break;
        }
#endif

        /* File handles */
        case CURLOPT_STDERR:
        {
            if (request->redirected_stderr) {
                fclose(request->redirected_stderr);
            }
            request->redirected_stderr = fdopen(dup(SvIV(parameter)), "a");
            if (!request->redirected_stderr) {
                croak("Cannot set CURLOPT_STDERR: fdopen failed");
            }

            result = curl_easy_setopt(request->easy, option, request->redirected_stderr);
            break;
        }

        /* Special functions */
        case CURLOPT_WRITEFUNCTION:
        case CURLOPT_HEADERFUNCTION:
        case CURLOPT_READFUNCTION:
        case CURLOPT_DEBUGFUNCTION:
        case CURLOPT_TRAILERFUNCTION:
        {
            SV* fn_copy = newSVsv(parameter);
            av_push(request->held_references, fn_copy);

            switch (option) {
                case CURLOPT_WRITEFUNCTION: {
                    result = curl_easy_setopt(request->easy, CURLOPT_WRITEFUNCTION, mcurl_write_callback);
                    result = curl_easy_setopt(request->easy, CURLOPT_WRITEDATA, fn_copy);
                    break;
                }
                case CURLOPT_HEADERFUNCTION: {
                    result = curl_easy_setopt(request->easy, CURLOPT_HEADERFUNCTION, mcurl_write_callback);
                    result = curl_easy_setopt(request->easy, CURLOPT_HEADERDATA, fn_copy);
                    break;
                }
                case CURLOPT_READFUNCTION: {
                    result = curl_easy_setopt(request->easy, CURLOPT_READFUNCTION, mcurl_read_callback);
                    result = curl_easy_setopt(request->easy, CURLOPT_READDATA, fn_copy);
                    break;
                }
                case CURLOPT_DEBUGFUNCTION: {
                    result = curl_easy_setopt(request->easy, CURLOPT_DEBUGFUNCTION, mcurl_debug_callback);
                    result = curl_easy_setopt(request->easy, CURLOPT_DEBUGDATA, fn_copy);
                    break;
                }
                case CURLOPT_TRAILERFUNCTION: {
                    result = curl_easy_setopt(request->easy, CURLOPT_TRAILERFUNCTION, mcurl_trailer_callback);
                    result = curl_easy_setopt(request->easy, CURLOPT_TRAILERDATA, fn_copy);
                    break;
                }
                default: { result = CURLE_OK; } /* To keep compilers quiet */
            }
            break;
        }

        /* Post fields are a bit special because of how they are copied (and can contain zero-bytes) */
        case CURLOPT_POSTFIELDS:
        {
            STRLEN pvlen;
            char *pv = SvPV(parameter, pvlen);

            result = curl_easy_setopt(request->easy, CURLOPT_POSTFIELDSIZE, pvlen);
            result = curl_easy_setopt(request->easy, CURLOPT_COPYPOSTFIELDS, pv);
            break;
        }

        /* MIME posts are specified as an arrayref of hashes with a 'name' and a 'value' or 'file' */
        case CURLOPT_MIMEPOST:
        {
            if (!SvROK(parameter) || SvTYPE(SvRV(parameter)) != SVt_PVAV) {
                croak("Cannot convert %s to ARRAY reference", SvPV_nolen(parameter));

YACurl.xs  view on Meta::CPAN

        if (opt == CURLINFO_PRIVATE) {
            /* These would be meaningless to access, so don't bother */
            croak("Refusing access to private CURL data");

        } else if ((opt & CURLINFO_TYPEMASK) == CURLINFO_STRING) {
            char *result;
            CURLcode ccode = curl_easy_getinfo(response->easy, opt, &result);
            if (ccode != CURLE_OK) {
                croak("%s", curl_easy_strerror(ccode));
            }
            RETVAL = newSVpv(result, 0);

        } else if ((opt & CURLINFO_TYPEMASK) == CURLINFO_LONG) {
            long result;
            CURLcode ccode = curl_easy_getinfo(response->easy, opt, &result);
            if (ccode != CURLE_OK) {
                croak("%s", curl_easy_strerror(ccode));
            }
            RETVAL = newSViv(result);

        } else if ((opt & CURLINFO_TYPEMASK) == CURLINFO_OFF_T) {
            curl_off_t result;
            CURLcode ccode = curl_easy_getinfo(response->easy, opt, &result);
            if (ccode != CURLE_OK) {
                croak("%s", curl_easy_strerror(ccode));
            }
            RETVAL = newSViv(result);

        } else if ((opt & CURLINFO_TYPEMASK) == CURLINFO_DOUBLE) {
            double result;
            CURLcode ccode = curl_easy_getinfo(response->easy, opt, &result);
            if (ccode != CURLE_OK) {
                croak("%s", curl_easy_strerror(ccode));
            }
            RETVAL = newSVnv(result);

        } else if (opt_from_str) {
            croak("Don't know what to do with curl's %d (%s)", opt, SvPV_nolen(option));
        } else {
            croak("Don't know what to do with curl's %d", opt);
        }

    OUTPUT:
        RETVAL

void
DESTROY(self)
        SV* self
    CODE:
        AnyEvent__YACurl__Response *response = sv_to_response(aTHX_ self);

        if (response->easy) {
            curl_easy_cleanup(response->easy);
        }
        if (response->mimepost) {
            curl_mime_free(response->mimepost);
        }
        if (response->held_references) {
            SvREFCNT_dec(response->held_references);
        }
        if (response->redirected_stderr) {
            fclose(response->redirected_stderr);
        }
        if (response->slists) {
            int i;
            for (i = 0; i < response->slists_count; i++) {
                curl_slist_free_all(response->slists[i]);
            }
            Safefree(response->slists);
        }
        if (response->callback) {
            SvREFCNT_dec(response->callback);
        }

        Safefree(response);



( run in 2.204 seconds using v1.01-cache-2.11-cpan-5b529ec07f3 )