diff --git a/harbour/ChangeLog b/harbour/ChangeLog index f9e78c0528..2fc5ce52dd 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,26 @@ 2008-12-31 13:59 UTC+0100 Foo Bar */ +2008-06-04 18:55 UTC+0100 Viktor Szakats (harbour.01 syenar hu) + * contrib/hbcurl/hbcurl.ch + * contrib/hbcurl/hbcurl.c + * contrib/hbcurl/tests/ftp_uldl.prg + + Added some more test for downloading to memory, + uploading from memory. + + Added possibility to download to memory, and upload + from memory: + + CURL_EASY_SETOPT() / HB_CURLOPT_UL_BUFF_SETUP + + CURL_EASY_SETOPT() / HB_CURLOPT_DL_BUFF_SETUP + + CURL_EASY_SETOPT() / HB_CURLOPT_DL_BUFF_GET + + CURL_EASY_DL_BUFF_GET() -> + * Changed a few old Harbour setopt defines: + (old ones are still working to retain compatibility) + * HB_CURLOPT_SETUPLOADFILE -> HB_CURLOPT_UL_FILE_SETUP + * HB_CURLOPT_CLOSEUPLOADFILE -> HB_CURLOPT_UL_FILE_CLOSE + * HB_CURLOPT_SETDOWNLOADFILE -> HB_CURLOPT_DL_FILE_SETUP + * HB_CURLOPT_CLOSEDOWNLOADFILE -> HB_CURLOPT_DL_FILE_CLOSE + * HB_CURLOPT_SETPROGRESS -> HB_CURLOPT_PROGRESSBLOCK + 2008-06-04 17:32 UTC+0100 Viktor Szakats (harbour.01 syenar hu) * contrib/hbcurl/hbcurl.c * Changed all logical options to default to .T.. This diff --git a/harbour/contrib/hbcurl/hbcurl.c b/harbour/contrib/hbcurl/hbcurl.c index 0a8d350243..155c4b896a 100644 --- a/harbour/contrib/hbcurl/hbcurl.c +++ b/harbour/contrib/hbcurl/hbcurl.c @@ -99,9 +99,18 @@ typedef struct _HB_CURL BYTE * ul_name; FHANDLE ul_handle; + BYTE * dl_name; FHANDLE dl_handle; + BYTE * ul_ptr; + size_t ul_len; + size_t ul_pos; + + BYTE * dl_ptr; + size_t dl_len; + size_t dl_pos; + PHB_ITEM pProgressBlock; } HB_CURL, * PHB_CURL; @@ -168,7 +177,7 @@ HB_FUNC( CURL_GLOBAL_CLEANUP ) /* ---------------------------------------------------------------------------- */ /* Callbacks */ -size_t hb_curl_read_callback( void * buffer, size_t size, size_t nmemb, void * Cargo ) +size_t hb_curl_read_file_callback( void * buffer, size_t size, size_t nmemb, void * Cargo ) { PHB_CURL hb_curl = ( PHB_CURL ) Cargo; @@ -192,7 +201,29 @@ size_t hb_curl_read_callback( void * buffer, size_t size, size_t nmemb, void * C return -1; } -size_t hb_curl_write_callback( void * buffer, size_t size, size_t nmemb, void * Cargo ) +size_t hb_curl_read_buff_callback( void * buffer, size_t size, size_t nmemb, void * Cargo ) +{ + PHB_CURL hb_curl = ( PHB_CURL ) Cargo; + + if( hb_curl ) + { + ULONG nTodo = ( ULONG ) ( size * nmemb ); + ULONG nLeft = hb_curl->ul_len - hb_curl->ul_pos; + + if( nTodo > nLeft ) + nTodo = nLeft; + + hb_xmemcpy( buffer, hb_curl->ul_ptr + hb_curl->ul_pos, nTodo ); + + hb_curl->ul_pos += nTodo; + + return ( size_t ) nTodo; + } + + return -1; +} + +size_t hb_curl_write_file_callback( void * buffer, size_t size, size_t nmemb, void * Cargo ) { PHB_CURL hb_curl = ( PHB_CURL ) Cargo; @@ -212,6 +243,34 @@ size_t hb_curl_write_callback( void * buffer, size_t size, size_t nmemb, void * return -1; } +#define HB_CURL_DL_BUFF_SIZE_INIT ( CURL_MAX_WRITE_SIZE * 2 ) +#define HB_CURL_DL_BUFF_SIZE_INCR ( CURL_MAX_WRITE_SIZE * 4 ) + +size_t hb_curl_write_buff_callback( void * buffer, size_t size, size_t nmemb, void * Cargo ) +{ + PHB_CURL hb_curl = ( PHB_CURL ) Cargo; + + if( hb_curl ) + { + ULONG nTodo = ( ULONG ) ( size * nmemb ); + ULONG nLeft = hb_curl->dl_len - hb_curl->dl_pos; + + if( nTodo > nLeft ) + { + hb_curl->dl_len += HB_CURL_DL_BUFF_SIZE_INCR; + hb_curl->dl_ptr = hb_xrealloc( hb_curl->dl_ptr, hb_curl->dl_len ); + } + + hb_xmemcpy( hb_curl->dl_ptr + hb_curl->dl_pos, buffer, nTodo ); + + hb_curl->dl_pos += nTodo; + + return ( size_t ) nTodo; + } + + return -1; +} + int hb_curl_progress_callback( void * Cargo, double dltotal, double dlnow, double ultotal, double ulnow ) { if( Cargo ) @@ -282,6 +341,28 @@ static void hb_curl_file_dl_free( PHB_CURL hb_curl ) } } +static void hb_curl_buff_ul_free( PHB_CURL hb_curl ) +{ + if( hb_curl && hb_curl->ul_ptr ) + { + hb_xfree( hb_curl->ul_ptr ); + hb_curl->ul_ptr = NULL; + hb_curl->ul_len = 0; + hb_curl->ul_pos = 0; + } +} + +static void hb_curl_buff_dl_free( PHB_CURL hb_curl ) +{ + if( hb_curl && hb_curl->dl_ptr ) + { + hb_xfree( hb_curl->dl_ptr ); + hb_curl->dl_ptr = NULL; + hb_curl->dl_len = 0; + hb_curl->dl_pos = 0; + } +} + /* ---------------------------------------------------------------------------- */ /* Constructor/Destructor */ @@ -317,6 +398,9 @@ static void PHB_CURL_free( PHB_CURL hb_curl, BOOL bFree ) hb_curl_file_ul_free( hb_curl ); hb_curl_file_dl_free( hb_curl ); + hb_curl_buff_ul_free( hb_curl ); + hb_curl_buff_dl_free( hb_curl ); + if( hb_curl->pProgressBlock ) { hb_itemRelease( hb_curl->pProgressBlock ); @@ -1072,7 +1156,7 @@ HB_FUNC( CURL_EASY_SETOPT ) /* Harbour specials */ - case HB_CURLOPT_SETPROGRESS: + case HB_CURLOPT_PROGRESSBLOCK: { PHB_ITEM pProgressBlock = hb_param( 3, HB_IT_BLOCK ); @@ -1095,7 +1179,7 @@ HB_FUNC( CURL_EASY_SETOPT ) } break; - case HB_CURLOPT_SETUPLOADFILE: + case HB_CURLOPT_UL_FILE_SETUP: { hb_curl_file_ul_free( hb_curl ); @@ -1104,20 +1188,18 @@ HB_FUNC( CURL_EASY_SETOPT ) hb_curl->ul_name = ( BYTE * ) hb_strdup( hb_parc( 3 ) ); hb_curl->ul_handle = FS_ERROR; - curl_easy_setopt( hb_curl->curl, CURLOPT_READFUNCTION, hb_curl_read_callback ); + curl_easy_setopt( hb_curl->curl, CURLOPT_READFUNCTION, hb_curl_read_file_callback ); res = curl_easy_setopt( hb_curl->curl, CURLOPT_READDATA, ( void * ) hb_curl ); } } break; - case HB_CURLOPT_CLOSEUPLOADFILE: - { - hb_curl_file_ul_free( hb_curl ); - res = CURLE_OK; - } + case HB_CURLOPT_UL_FILE_CLOSE: + hb_curl_file_ul_free( hb_curl ); + res = CURLE_OK; break; - case HB_CURLOPT_SETDOWNLOADFILE: + case HB_CURLOPT_DL_FILE_SETUP: { hb_curl_file_dl_free( hb_curl ); @@ -1126,24 +1208,70 @@ HB_FUNC( CURL_EASY_SETOPT ) hb_curl->dl_name = ( BYTE * ) hb_strdup( hb_parc( 3 ) ); hb_curl->dl_handle = FS_ERROR; - curl_easy_setopt( hb_curl->curl, CURLOPT_WRITEFUNCTION, hb_curl_write_callback ); + curl_easy_setopt( hb_curl->curl, CURLOPT_WRITEFUNCTION, hb_curl_write_file_callback ); res = curl_easy_setopt( hb_curl->curl, CURLOPT_WRITEDATA, ( void * ) hb_curl ); } } break; - case HB_CURLOPT_CLOSEDOWNLOADFILE: + case HB_CURLOPT_DL_FILE_CLOSE: + hb_curl_file_dl_free( hb_curl ); + res = CURLE_OK; + break; + + case HB_CURLOPT_UL_BUFF_SETUP: { - hb_curl_file_dl_free( hb_curl ); - res = CURLE_OK; + hb_curl_buff_ul_free( hb_curl ); + + if( ISCHAR( 3 ) ) + { + hb_curl->ul_pos = 0; + hb_curl->ul_len = hb_parclen( 3 ); + hb_curl->ul_ptr = ( BYTE * ) hb_xgrab( hb_curl->ul_len ); + + hb_xmemcpy( hb_curl->ul_ptr, hb_parc( 3 ), hb_parclen( 3 ) ); + + curl_easy_setopt( hb_curl->curl, CURLOPT_READFUNCTION, hb_curl_read_buff_callback ); + res = curl_easy_setopt( hb_curl->curl, CURLOPT_READDATA, ( void * ) hb_curl ); + } } break; + + case HB_CURLOPT_DL_BUFF_SETUP: + { + hb_curl_buff_dl_free( hb_curl ); + + hb_curl->dl_pos = 0; + hb_curl->dl_len = ISNUM( 3 ) ? hb_parnl( 3 ) : HB_CURL_DL_BUFF_SIZE_INIT; + hb_curl->dl_ptr = ( BYTE * ) hb_xgrab( hb_curl->dl_len ); + + curl_easy_setopt( hb_curl->curl, CURLOPT_WRITEFUNCTION, hb_curl_write_buff_callback ); + res = curl_easy_setopt( hb_curl->curl, CURLOPT_WRITEDATA, ( void * ) hb_curl ); + } + break; + + case HB_CURLOPT_DL_BUFF_GET: + hb_storclen( ( char * ) hb_curl->dl_ptr, hb_curl->dl_pos, 3 ); + if( hb_curl->dl_ptr ) + res = CURLE_OK; + break; } } hb_retnl( ( long ) res ); } +/* Harbour extension. */ +HB_FUNC( CURL_EASY_DL_BUFF_GET ) +{ + PHB_CURL hb_curl = PHB_CURL_par( 1 ); + + if( hb_curl ) + hb_retclen( ( char * ) hb_curl->dl_ptr, hb_curl->dl_pos ); + else + hb_retc_null(); +} + #define HB_CURL_INFO_TYPE_INVALID 0 #define HB_CURL_INFO_TYPE_STR 1 #define HB_CURL_INFO_TYPE_PTR 2 diff --git a/harbour/contrib/hbcurl/hbcurl.ch b/harbour/contrib/hbcurl/hbcurl.ch index bcde9d6542..01c3730d03 100644 --- a/harbour/contrib/hbcurl/hbcurl.ch +++ b/harbour/contrib/hbcurl/hbcurl.ch @@ -219,12 +219,21 @@ #define HB_CURLOPT_PROXY_TRANSFER_MODE 166 #define HB_CURLOPT_SEEKFUNCTION 167 #define HB_CURLOPT_SEEKDATA 168 -#define HB_CURLOPT_SETUPLOADFILE 1001 /* Harbour special ones */ -#define HB_CURLOPT_CLOSEUPLOADFILE 1002 -#define HB_CURLOPT_SETDOWNLOADFILE 1003 -#define HB_CURLOPT_CLOSEDOWNLOADFILE 1004 -#define HB_CURLOPT_SETPROGRESS 1005 -#define HB_CURLOPT_DOWNLOAD 1006 +#define HB_CURLOPT_DOWNLOAD 1001 /* Harbour special ones */ +#define HB_CURLOPT_PROGRESSBLOCK 1002 +#define HB_CURLOPT_UL_FILE_SETUP 1003 +#define HB_CURLOPT_UL_FILE_CLOSE 1004 +#define HB_CURLOPT_DL_FILE_SETUP 1005 +#define HB_CURLOPT_DL_FILE_CLOSE 1006 +#define HB_CURLOPT_UL_BUFF_SETUP 1007 +#define HB_CURLOPT_DL_BUFF_SETUP 1008 +#define HB_CURLOPT_DL_BUFF_GET 1009 +/* Compatibility ones. Please don't use these. */ +#define HB_CURLOPT_SETUPLOADFILE HB_CURLOPT_UL_FILE_SETUP +#define HB_CURLOPT_CLOSEUPLOADFILE HB_CURLOPT_UL_FILE_CLOSE +#define HB_CURLOPT_SETDOWNLOADFILE HB_CURLOPT_DL_FILE_SETUP +#define HB_CURLOPT_CLOSEDOWNLOADFILE HB_CURLOPT_DL_FILE_CLOSE +#define HB_CURLOPT_SETPROGRESS HB_CURLOPT_PROGRESSBLOCK /* HB_CURLOPT_PROXYTYPE option */ #define HB_CURLPROXY_HTTP 0 /* added in 7.10 */ diff --git a/harbour/contrib/hbcurl/tests/ftp_uldl.prg b/harbour/contrib/hbcurl/tests/ftp_uldl.prg index 2be89662fd..2203050bbd 100644 --- a/harbour/contrib/hbcurl/tests/ftp_uldl.prg +++ b/harbour/contrib/hbcurl/tests/ftp_uldl.prg @@ -7,9 +7,11 @@ #include "hbcurl.ch" #include "common.ch" +#include "fileio.ch" #define UPLOAD_FILE_AS "test_ul.bin" #define REMOTE_URL "ftp://harbour:power@localhost/" + UPLOAD_FILE_AS +#define REMOTE_URL_MEM "ftp://harbour:power@localhost/from_mem.txt" #define RENAME_FILE_TO "test_ul_renamed.bin" FUNCTION Main( cDL, cUL ) @@ -17,6 +19,7 @@ FUNCTION Main( cDL, cUL ) LOCAL info LOCAL tmp LOCAL tmp1 + LOCAL f ? curl_version() ? curl_getdate( "Sun, 1 Jun 2008 02:10:58 +0200" ) @@ -34,6 +37,7 @@ FUNCTION Main( cDL, cUL ) ENDIF NEXT + ? "Press key..." Inkey( 0 ) ? "INIT:", curl_global_init() @@ -43,22 +47,23 @@ FUNCTION Main( cDL, cUL ) ? "ESCAPE:", tmp := curl_easy_escape( curl, "http://domain.com/my dir with space&more/" ) ? "UNESCAPE:", curl_easy_unescape( curl, tmp ) + ? "Press key..." Inkey( 0 ) DEFAULT cUL TO "ftp_uldl.prg" ? curl_easy_setopt( curl, HB_CURLOPT_UPLOAD ) ? curl_easy_setopt( curl, HB_CURLOPT_URL, REMOTE_URL ) - ? curl_easy_setopt( curl, HB_CURLOPT_SETUPLOADFILE, cUL ) + ? curl_easy_setopt( curl, HB_CURLOPT_UL_FILE_SETUP, cUL ) ? curl_easy_setopt( curl, HB_CURLOPT_INFILESIZE, hb_FSize( cUL ) ), hb_FSize( cUL ) // ? curl_easy_setopt( curl, HB_CURLOPT_INFILESIZE_LARGE, hb_FSize( cUL ) ), hb_FSize( cUL ) // TOFIX // ? curl_easy_setopt( curl, HB_CURLOPT_USERPWD, "harbour:power" ) /* May use this instead of embedding in URL */ - ? curl_easy_setopt( curl, HB_CURLOPT_SETPROGRESS, {| nPos, nLen | a := CurGet(), DispOutAt( 10, 10, Str( ( nPos / nLen ) * 100, 6, 2 ) + "%" ), CurSet( a ) } ) + ? curl_easy_setopt( curl, HB_CURLOPT_PROGRESSBLOCK, {| nPos, nLen | a := CurGet(), DispOutAt( 10, 10, Str( ( nPos / nLen ) * 100, 6, 2 ) + "%" ), CurSet( a ) } ) ? curl_easy_setopt( curl, HB_CURLOPT_NOPROGRESS, .F. ) ? curl_easy_setopt( curl, HB_CURLOPT_POSTQUOTE, { "RNFR " + UPLOAD_FILE_AS, "RNTO " + RENAME_FILE_TO } ) ? curl_easy_setopt( curl, HB_CURLOPT_VERBOSE, .F. ) - ? "UPLOAD:", curl_easy_perform( curl ) + ? "UPLOAD FILE:", curl_easy_perform( curl ) ? curl_easy_getinfo( curl, HB_CURLINFO_EFFECTIVE_URL ) ? curl_easy_getinfo( curl, HB_CURLINFO_TOTAL_TIME ) @@ -71,46 +76,108 @@ FUNCTION Main( cDL, cUL ) curl_easy_reset( curl ) + ? "Press key..." + Inkey( 0 ) + + /* Upload file from memory */ + + tmp := "This will be the content of the file" + + ? curl_easy_setopt( curl, HB_CURLOPT_UPLOAD ) + ? curl_easy_setopt( curl, HB_CURLOPT_URL, REMOTE_URL_MEM ) + ? curl_easy_setopt( curl, HB_CURLOPT_UL_BUFF_SETUP, tmp ) + ? curl_easy_setopt( curl, HB_CURLOPT_INFILESIZE, Len( tmp ) ), Len( tmp ) +// ? curl_easy_setopt( curl, HB_CURLOPT_USERPWD, "harbour:power" ) /* May use this instead of embedding in URL */ + ? curl_easy_setopt( curl, HB_CURLOPT_PROGRESSBLOCK, {| nPos, nLen | a := CurGet(), DispOutAt( 10, 10, Str( ( nPos / nLen ) * 100, 6, 2 ) + "%" ), CurSet( a ) } ) + ? curl_easy_setopt( curl, HB_CURLOPT_NOPROGRESS, .F. ) + ? curl_easy_setopt( curl, HB_CURLOPT_VERBOSE, .F. ) + + ? "UPLOAD FILE FROM MEMORY:", curl_easy_perform( curl ) + + ? curl_easy_getinfo( curl, HB_CURLINFO_EFFECTIVE_URL ) + ? curl_easy_getinfo( curl, HB_CURLINFO_TOTAL_TIME ) + + info := curl_easy_getinfo( curl, HB_CURLINFO_SSL_ENGINES ) + ? + FOR tmp := 1 TO Len( info ) + ?? info[ tmp ] + " " + NEXT + + curl_easy_reset( curl ) + + ? "Press key..." Inkey( 0 ) DEFAULT cDL TO "ftp://ftp.cisco.com/README" - /* Now let's download something */ + /* Now let's download to a file */ ? curl_easy_setopt( curl, HB_CURLOPT_DOWNLOAD ) ? curl_easy_setopt( curl, HB_CURLOPT_URL, cDL ) ? curl_easy_setopt( curl, HB_CURLOPT_SSL_VERIFYPEER, .F. ) ? curl_easy_setopt( curl, HB_CURLOPT_SSL_VERIFYHOST, .F. ) - ? curl_easy_setopt( curl, HB_CURLOPT_SETDOWNLOADFILE, "test_dl.bin" ) - ? curl_easy_setopt( curl, HB_CURLOPT_SETPROGRESS, {| nPos, nLen | a := CurGet(), DispOutAt( 11, 10, Str( ( nPos / nLen ) * 100, 6, 2 ) + "%" ), CurSet( a ) } ) + ? curl_easy_setopt( curl, HB_CURLOPT_DL_FILE_SETUP, "test_dl.bin" ) + ? curl_easy_setopt( curl, HB_CURLOPT_PROGRESSBLOCK, {| nPos, nLen | a := CurGet(), DispOutAt( 11, 10, Str( ( nPos / nLen ) * 100, 6, 2 ) + "%" ), CurSet( a ) } ) ? curl_easy_setopt( curl, HB_CURLOPT_NOPROGRESS, .F. ) ? curl_easy_setopt( curl, HB_CURLOPT_VERBOSE, .F. ) - ? "DOWNLOAD:", curl_easy_perform( curl ) + ? "DOWNLOAD FILE:", curl_easy_perform( curl ) curl_easy_reset( curl ) + ? "Press key..." + Inkey( 0 ) + + /* Now let's download to memory */ + + ? curl_easy_setopt( curl, HB_CURLOPT_DOWNLOAD ) + ? curl_easy_setopt( curl, HB_CURLOPT_URL, "http://kent.dl.sourceforge.net/sourceforge/harbour-project/harbour-static-0.99.2-0mdk20070.i586.rpm" ) + ? curl_easy_setopt( curl, HB_CURLOPT_SSL_VERIFYPEER, .F. ) + ? curl_easy_setopt( curl, HB_CURLOPT_SSL_VERIFYHOST, .F. ) + ? curl_easy_setopt( curl, HB_CURLOPT_DL_BUFF_SETUP ) + ? curl_easy_setopt( curl, HB_CURLOPT_PROGRESSBLOCK, {| nPos, nLen | a := CurGet(), DispOutAt( 11, 10, Str( ( nPos / nLen ) * 100, 6, 2 ) + "%" ), CurSet( a ) } ) + ? curl_easy_setopt( curl, HB_CURLOPT_NOPROGRESS, .F. ) + ? curl_easy_setopt( curl, HB_CURLOPT_VERBOSE, .F. ) + + ? "DOWNLOAD FILE TO MEM:", curl_easy_perform( curl ) + + tmp := "test_dlm.bin" + ? "WRITING TO FILE: ", tmp + f := FCreate( tmp, FC_NORMAL ) + IF f != F_ERROR + FWrite( f, curl_easy_dl_buff_get( curl ) ) + FClose( f ) + ENDIF + + curl_easy_reset( curl ) + + ? "Press key..." Inkey( 0 ) DEFAULT cDL TO "ftp://ftp.cisco.com/" - /* Now let's download a dirlist */ + /* Now let's download a dirlist to memory */ ? curl_easy_setopt( curl, HB_CURLOPT_DOWNLOAD ) ? curl_easy_setopt( curl, HB_CURLOPT_DIRLISTONLY ) ? curl_easy_setopt( curl, HB_CURLOPT_URL, cDL ) ? curl_easy_setopt( curl, HB_CURLOPT_SSL_VERIFYPEER, .F. ) ? curl_easy_setopt( curl, HB_CURLOPT_SSL_VERIFYHOST, .F. ) - ? curl_easy_setopt( curl, HB_CURLOPT_SETDOWNLOADFILE, "test_in.txt" ) - ? curl_easy_setopt( curl, HB_CURLOPT_SETPROGRESS, {| nPos, nLen | a := CurGet(), DispOutAt( 11, 10, Str( ( nPos / nLen ) * 100, 6, 2 ) + "%" ), CurSet( a ) } ) + ? curl_easy_setopt( curl, HB_CURLOPT_DL_BUFF_SETUP ) + ? curl_easy_setopt( curl, HB_CURLOPT_PROGRESSBLOCK, {| nPos, nLen | a := CurGet(), DispOutAt( 11, 10, Str( ( nPos / nLen ) * 100, 6, 2 ) + "%" ), CurSet( a ) } ) ? curl_easy_setopt( curl, HB_CURLOPT_NOPROGRESS, .F. ) ? curl_easy_setopt( curl, HB_CURLOPT_VERBOSE, .F. ) - ? "DOWNLOAD:", curl_easy_perform( curl ) + ? "DOWNLOAD DIRLIST TO STRING:", curl_easy_perform( curl ) + + ? "RESULT 1: " + curl_easy_dl_buff_get( curl ) + ? curl_easy_setopt( curl, HB_CURLOPT_DL_BUFF_GET, @tmp ) + ? "RESULT 2: " + tmp /* Cleanup session */ curl_easy_cleanup( curl ) + ENDIF curl_global_cleanup()