cURL / Mailing Lists / curl-library / Single Mail

curl-library

RE: known problem with write progress callback?

From: Max L. Eidswick <max_at_eidswick.com>
Date: Wed, 30 Jan 2008 06:29:53 -0700

From: curl-library-bounces_at_cool.haxx.se [mailto:curl-library-bounces_at_cool.haxx.se] On Behalf Of Daniel Stenberg
Sent: Wednesday, January 30, 2008 4:32 AM
To: libcurl development
Subject: Re: known problem with write progress callback?

On Tue, 29 Jan 2008, Max L. Eidswick wrote:

> I am testing the progress callback for an updated win32 app. The progress
> callback gets hit, but there is no write callback data until the last call.
> The last call values are not correct either.
>
> Are there known problems with the progress callback on a simple HTTP post
> for a file send?

No.

AFAIK, this works and the code for this really hasn't been modified in a
number of years so I'm suspecting you have these problems for some other
reasons.

Can you show us a full stand-alone source code that repeats this behaviour
when run?

----- snip

Here is an example of the test code ...

// ---------------------------------------------------------------------
// module to test progress callback during http file upload -- 25.01.08 //
// the symptom I am experiencing in this test that I don't understand
// is that the SendfileProgressCallback proc is called about 90 times
// in the 15 seconds it takes to upload the ~1.3mb test file. It then
// reports 1,075,576,832 bytes uploaded for a file that is
// 1,338,460 bytes big (the upload is successful, I can re-download it
// and test the RAR file's integrity).
//
// obviously, I am doing something wrong, either with the callback
// data or I need to use the CURLOPT_PROGRESSDATA pointer, but I
// am unclear as to what type of structure it is supposed to point to
// and the format of the data that gets pointed to by it. I have gone
// through the current examples and several others I have found on the
// web, but most seem to do with the multi-interface.
//
// I am confident this libcurl version works fine with this feature,
// so this must be a simple mis-implementation of this test code.
//
// Thanks for any direction. The last run output follows together
// with a directory listing of the source sendfile test file ...
//
/* ----- snip: output from command line stdout:

Uploading now:
Call count: 90, dltotal: 0, dlnow: 0, ultotal: 0,ulnow: 1075576832 curl sendfile time: 15281 msecs

 ----- End of test of libcurl sendfile ----- Press any key to exit.

----- end snip */

/* ----- snip: dir size of test file:

">"dir c:\sendfiletest.rar

01/24/2008 11:08 AM 1,338,460 SendfileTest.rar
               1 File(s) 1,338,460 bytes

----- end snip */

// see SendfileProgressCallback for this test module.
// ---------------------------------------------------------------------
// standard c and windows includes
#include <conio.h>

// ---------------------------------------------------------------------
// cURL inclusions (winsock2.h is before windows.h) // ---------------------------------------------------------------------
#define _WIN32_WINNT 0x0500 // for icon notification size
#pragma warning( disable : 4996 ) // eliminate vs2005 security bs

// ---------------------------------------------------------------------
// libcurl includes in ..\RedPawComms\libcURL\curl-7.17.1\include
#include <curl/curl.h>

// ---------------------------------------------------------------------
// test module storage allocations and structures
struct curl_httppost *formPostSendfile = NULL ; // for formadd
struct curl_httppost *lastPtr = NULL ; // for libcurl curl_formadd

// ---------------------------------------------------------------------
UCHAR ucCURLErrorBuffer[CURL_ERROR_SIZE] ; // used by libcurl errors
ULONG ulStartClick = 0 ; // millisecond counter before easy perform
ULONG ulStopClick = 0 ; // millisecond counter after easy perform
UCHAR szTmpBuf[2048] ; // plenty of space for string output
BOOL bDone = FALSE ; // exit flag, when done

// ---------------------------------------------------------------------
CURL *curlhSendfile ; // libcurl sendfile test handle
CURLcode res ; // result code from libcurl

// =====================================================================
// libcurl file transfer callback -
//
// the docs say to look at the prototype in curl.h, but it doesn't say
// much about what the clientp pointer is for ... maybe testing will
// help clear this up ...
// =====================================================================
int SendfileProgressCallback (
          void *clientp, // CURLOPT_PROGRESSDATA pointer
          double dltotal, // download total bytes
          double dlnow, // downloaded bytes so far
          double ultotal, // uploaded total bytes
          double ulnow // uploaded bytes so far
                                                         )
{
        static BOOL bFirstTime = TRUE ;
        static ULONG ulCallCount = 0 ;

        // write a command line window header for the test, then display
        // the callback data as called ..
        if ( bFirstTime )
        {
                printf ( "\nUploading now:\n" ) ;
                bFirstTime = FALSE ;
        }

        printf (
                "\rCall count: %d, dltotal: %ld, dlnow: %ld, ultotal: %ld,"
                "ulnow: %ld",
                ++ulCallCount, dltotal, dlnow, ultotal, ulnow ) ;

        return 0 ;
}
// end of progress callback test
// =====================================================================

// =====================================================================
// start of main test win32 procedure
//
// Testing: libcurl call to send a test file using a callback // //
=====================================================================
int main ( int argc, char *argv[] ) // test for comms dvlmt {
        // ----- local data definitions for main proc ---------------------

        // -----------------------------------------------------------------
        // verify the file exists on client workstation, exit with error msg
        // if not

        // -----------------------------------------------------------------
        // setup libcurl global info for win32, global cleanup on exit
        if ( curl_global_init ( CURL_GLOBAL_ALL | CURL_GLOBAL_WIN32 ) )
        {
                // report and ABEND!
                MessageBox ( NULL, "libcurl global init error",
                        "libcurl global init error", MB_OK ) ;
        } // end of call to curl global init failed
        

        // -----------------------------------------------------------------
        // initialize the easy interface
        curlhSendfile = curl_easy_init ( ) ; // get curl handle
        if ( !curlhSendfile ) // zero means no handle, failed
        {
                // failed to get easy handle, so global cleanup and ABEND
                curl_global_cleanup ( ) ; // clean up environment
                MessageBox ( NULL, "libcurl easy init failure",
                        "libcurl easy init failure", MB_OK ) ;
                ExitProcess ( 101 ) ; // ABEND ABEND ABEND ABEND ABEND ABEND
        } // end of if !curl call to curl init failed

        // -------------------------------------------------------------
        // curl fails on 400+ error codes from the server - it's unclear
        // if this does anything useful for our ping example, but it is
        // in the planned production design, so it is here too ...
        // -------------------------------------------------------------
        curl_easy_setopt ( curlhSendfile, CURLOPT_FAILONERROR, TRUE ) ;

        // ------------------------------------------------------------
        // if there are any errors, make sure we know what libcurl says
        // is going on
        // ------------------------------------------------------------
        curl_easy_setopt (
                                curlhSendfile, // for our sendfile test handle
                                CURLOPT_ERRORBUFFER, // ask libcurl to keep us
                                ucCURLErrorBuffer // informed about errors
                                                ) ;

        // -------------------------------------------------------------
        // setup our test URL
        // -------------------------------------------------------------
        curl_easy_setopt ( // setup URL to touch
                curlhSendfile,
                CURLOPT_URL,
                "http://redpawsys.com/RPV7CommServices/"
                "RPV7SendfileViaHTTPPost.php"
                                                ) ;

        // =================================================================
        // -----------------------------------------------------------------
        // THIS IS WHAT WE ARE TESTING IN THIS MODULE
        // -----------------------------------------------------------------
        // turn on progress callback
        curl_easy_setopt(curlhSendfile, CURLOPT_NOPROGRESS, FALSE ) ;

        // set progress callback
        curl_easy_setopt (
                curlhSendfile,
                CURLOPT_PROGRESSFUNCTION,
                SendfileProgressCallback
                                          ) ;

        // =================================================================

        // -----------------------------------------------------------------
        // setup a simple sendfile form, the php script simply copies the
        // uploaded file and creates an upload logfile entry for testing
        // -----------------------------------------------------------------
        curl_formadd ( // add field/value for sendfile/callback test
                &formPostSendfile, // libcurl form for sendfile
                &lastPtr, // managed by formadd
                CURLFORM_COPYNAME, "sendfile", // field name
                CURLFORM_FILE, "C:\\SendfileTest.rar", // HTTP upload
                CURLFORM_END
                                  ) ; // per libcurl spec

        // -------------------------------------------------------------
        // Tells libcurl you want a multipart/formdata HTTP POST to be
        // made and you instruct what data to pass on to the server.
        // -------------------------------------------------------------
        curl_easy_setopt (
                curlhSendfile,
                CURLOPT_HTTPPOST,
                formPostSendfile
                                         ) ;

        // -------------------------------------------------------------
        // DO IT. This should trigger the progress callback under test
        // check the msecs before and after the call to easy perform
        // -------------------------------------------------------------
        ulStartClick = GetTickCount ( ) ;
        res = curl_easy_perform ( curlhSendfile ) ; // << --- send it!
        ulStopClick = GetTickCount ( ) ;
        if ( res ) // libcurl call failed for some reason, so let's see
        {

                sprintf ( szTmpBuf, "cURL error: %d, %s",
                                                                curlhSendfile, ucCURLErrorBuffer ) ;
                printf ( "\n ----- %s ----- \n", szTmpBuf ) ;

        } // end of if libcurl perform call failed
        else // the libcurl call was successful, so let's just see the
        { // click count and some of the PHP script response ...
                printf ( "\nlibcurl sendfile time: %d msecs",
                                                                        ulStopClick - ulStartClick ) ;
        
        } // end of else libcurl perform call was successful

        // -----------------------------------------------------------------
        // clean up allocations for the sendfile form
        curl_formfree ( formPostSendfile ) ; // free the form

        // -----------------------------------------------------------------
        // standard libcurl cleanup
        // -----------------------------------------------------------------
        curl_easy_cleanup ( curlhSendfile ) ; // end of easy session
        curl_global_cleanup ( ) ; // clean up environment
        
        // -----------------------------------------------------------------
        printf ( "\n\n ----- End of test of libcurl sendfile ----- "
                                "Press any key to exit." ) ;
        res = _getch ( ) ;

        // -----------------------------------------------------------------
        // end of this test program
        // -----------------------------------------------------------------

        return TRUE ;

} // ~~~~~ end of main procedure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Received on 2008-01-30