On Mon Apr 28 18:56:35 2008, CRISB wrote:
Show quoted text> It's nothing you've done wrong - it's a side-effect of how the module
> diverts the output from STDOUT into PerlIO.
>
> By default, libcurl would send the headers to STDOUT, but perl really
> needs it's standard output to be fed through the PerlIO layer (which
> might have diversions and conversions plugged into it).
>
> The XS code in the module sets up a default callback function for the
> libcurl header and body callbacks. The function just does a PerlIO ouput
> instead of a libc output on the data.
So far, so good.
Show quoted text>
> It looks like the callback function is being called by libcurl even when
> CURLOPT_HEADER is set false/0 - this looks like libcurl is calling the
> callback function if it's set, even if you asked for no output.
Actually, I think the case is a bit different. To fully understand what
happens, let me elaborate a bit on how things are done atm, with
relation to the callbacks.
In 4.00, when the $curl object is created, the XS code sets up two
things: it assigns the callback function pointers to all of the libcurl
setopt parameters that would allow us to create callbacks and it assigns
the $curl object itself to all the options accepting filestreams.
There are two arrays of SVs internally to the XS module, one keeps track
of callbacks set from the Perl side, the other keeps track of
filehandles set from the Perl side.
Then, when setopt gets called from the Perl side and a function or
filehandle would be set, all that happens is that the two arrays track
the filehandle/coderef.
So, when libcurl actually performs the request, it calls the XS
functions we've set, with the stream (that is - "self") that we've set.
Our functions then check whether a function/filehandle callback exists
from the Perl side and if not, then things go to STDOUT.
The problem we have is, that libcurl sees that we've set
CURLOPT_HEADERFUNCTION, CURLOPT_WRITEHEADER, CURLOPT_DEBUGDATA, etc. and
it assumes we want the output. However, this is between XS<-->libcurl.
So when no callbacks are set between XS<-->Perl, then things end up on
STDOUT through PerlIO as the default catchall in the XS function is that.
This is why we've seen header and debug output on STDOUT even if
CURLOPT_HEADER is set to a false value.
Imo, the fix is to only set these callbacks (but both function and
filehandle at the same time - they depend on each other!) when they are
set from the Perl side, and appropriately unset them if the Perl side
assigns undef.
CURLOPT_READFUNCTION and CURLOPT_WRITEFUNCTION should still be set to
our custom XS function at object creation time, because this allows us
to feed the default libcurl output through PerlIO.
So, in the cases that interest us this would happen:
1. No curl option is set from the Perl side:
libcurl tries to output to STDOUT, the default WRITEFUNCTION redirects
to PerlIO.
2. CURLOPT_*DATA is set, but not CURLOPT_*FUNCTION:
libcurl tries to output data to the stream. The stream is set to the XS
$self, libcurl checks for the specific callback, which is executed,
which checks the internal array and writes to the appropriate filehandle.
3. Both *DATA and *FUNCTION are set:
Same as before, except instead of a filehandle being written to, the
Perl-side coderef gets executed and it's return value passed back to
libcurl as required.
What do you think?
If no objections, I'll modify the code to behave like this and release 4.01.