Page 1 of 1

Help with hbcurl

Posted: Wed Jul 07, 2021 3:10 am
by Rathinagiri
I want to use hbcurl to POST/GET to/from web especially https.

Can you please tell me what are the libraries required to be statically linked and working in HMG?

Re: Help with hbcurl

Posted: Wed Jul 07, 2021 6:11 am
by Rathinagiri
As of now, I am using hbtip successfully to send and receive data from https secured websites.

But in the Harbour distribution there is a warning which states like the one below. So, I want to switch over to others like hbcurl or MSXML2.ServerXMLHTTP

I have tried both. Both of them I am getting so many errors.

WARNING for HBTIP users
=======================

Due to the excessive amount of problem reports and long known (and unfixed)
problems and due to the non-trivial nature of internet protocols, this document
_strongly recommends to avoid_ using this library in anything production or
in fact anything more serious than simple test code for educational purposes.
Please notice that even if something happens to work in some specific
scenario, it's highly likely it's not a stable solution, nor is it a secure
solution.

The only reason hbtip hasn't been deleted altogether is compatibility
with 3.0, xHarbour and existing projects, plus the fact there are still some
low-level functions that do work fine (tip_MimeType()) or have no better
replacement yet (tip_MailAssemble()).

For internet protocol related tasks, the recommended and supported library
is _hbcurl_, which is a thin wrapper over libcurl's 'easy' API. libcurl is
a highly ubiquitious, very stable, actively and professionally developed,
secure communications library

Re: Help with hbcurl

Posted: Wed Jul 07, 2021 8:13 am
by edk
I have done communication with RESTAPI on the server with TLS 1.2 and I use both: cURL and "MSXML2.ServerXMLHTTP".

With "MSXML2.ServerXMLHTTP" I use json data exchange between my application and RESTAPI, while cURL for uploading image files ("MSXML2.ServerXMLHTTP" doesn't send form-data boundary correctly, at least I couldn't make him do it ;) )

Necessary are libraries that support TLS1.2 (those that were previously published on the forum did not work with TLS 1.2, I am attaching new ones - I do not know if they will work with TLS 1.3 also :roll: )
lib.zip
(1.19 MiB) Downloaded 288 times
My configuration:
HBP:

Code: Select all

Myapi.prg
hbziparc.hbc
hbcurl.hbc
HBC:

Code: Select all

inc=yes
head=native
libs=hbmxml mxml libeay32 ssleay32 libwinpthread-1 libcurl zlib1 libidn-11
HMG 3.4.4

Code snippets:

Code: Select all

//Init
BEGIN SEQUENCE WITH {|o| break(o)}
	oApi := Win_OleCreateObject( "MSXML2.ServerXMLHTTP" )
	oApi:setTimeouts(nTimeout * 1000 /* nResolve */ , nTimeout * 1000 /* nConnect*/ , nTimeout * 1000 /* nSend */, nTimeout * 1000 /* nReceive */ )

RECOVER
     MsgStop( "Microsoft XML Core Services (MSXML) 6.0 is not installed."+CRLF+;
          "Download and install MSXML 6.0 from http://msdn.microsoft.com/xml"+CRLF+;
          "before continuing.")
     oApi:=""
END SEQUENCE

IF EMPTY(oApi)
	MsgStop('Error while initialization')
	RETURN Nil
ENDIF

cResp := SendApi( cUrl, hb_jsonEncode( hData , .F. ), oApi )

Msgdebug ( cResp )

cResp := GetApi( cUrl, oApi )

Msgdebug ( cResp )

*********************************************************
Function SendApi( cUrl, cBody, oApi, cMethod )
Local cReturn, cAPIKey :="blablabla"

Default cMethod := "POST"

BEGIN SEQUENCE WITH {|o| break(o)}

	oApi:Open( cMethod, cUrl, .F. )
	oApi:setRequestHeader("Content-Type", "application/json;charset=utf-8")
	oApi:setRequestHeader("client-secret", cAPIKey)
	oApi:Send( cBody )

	IF oApi:Status <> 200
		BREAK "HTTPS status: " + hb_NToS(oApi:status) + " "  +oApi:statusText 
	ENDIF

	cReturn := oApi:ResponseBody()

RECOVER USING oErr
	cReturn := "!ERROR!" + CRLF + IF (ValType(oErr) = 'O', oErr:Description, oErr )
 
END SEQUENCE
 	
RETURN cReturn


**************************************
Function GetApi( cUrl, oApi)
Local cReturn, cAPIKey := "blablabla"

BEGIN SEQUENCE WITH {|o| break(o)}

	oApi:Open( "GET", cUrl, .F. )
	oApi:setRequestHeader("client-secret", cAPIKey)
	
	oApi:Send()
	oApi:WaitForResponse()

	IF oApi:Status <> 200
		BREAK "HTTPS status: " + hb_NToS(oApi:status) + " "  +oApi:statusText 
	ENDIF

	cReturn := oApi:ResponseBody()

RECOVER USING oErr

	cReturn := "!ERORR!" + CRLF + IF (ValType(oErr) = 'O', oErr:Description, oErr )
 
END SEQUENCE
 	
RETURN cReturn

Code: Select all

***********************************************************
* cURL
***********************************************************

//Init
curlHandle := curl_easy_init()
IF EMPTY(curlHandle)
	MsgStop('Error while initialization')
	RETURN Nil
ENDIF

//upload pictures
cResp := SendCurlPictApi( curlHandle, cUrl, cImageFile, hb_HGetDef( hPrd [i0], "id", 0) /* ProductId */ , Str(nIdZdjecia) /* id */, hb_HGetDef( hPrd [i0], "name", "") + " [" + Left( hb_HGetDef( hPrd [i0], "code", ""), 5 ) + "]" /* desc */ )

Msgdebug ( cResp )

curl_global_cleanup( curlHandle )

*********************************************************
Function SendCurlPictApi( curlHandle, cUrl, cImage, idProd, idZdjecia, cOpis )
Local cReturn, cAPIKey := "blablabla"
Local cPlikPict:=hb_FNameNameExt ( cImage )
Local boundary:='------' + hb_StrToHex ( hb_TtoC( hb_DateTime(), 'YYYYMMDDhhmmssfff' ) ) 
Local cFormBody:='--' + boundary + CRLF
Local aHeaders, curlErr
Default cOpis:=""

Do Events

cFormBody+='Content-Disposition: form-data; name="id"' + CRLF + CRLF
cFormBody+=Alltrim(idZdjecia) + CRLF

cFormBody+='--' + boundary + CRLF
cFormBody+='Content-Disposition: form-data; name="productId"' + CRLF + CRLF
cFormBody+=Alltrim(Str(idProd)) + CRLF

cFormBody+='--' + boundary + CRLF
cFormBody+='Content-Disposition: form-data; name="version"' + CRLF + CRLF
cFormBody+='1' + CRLF

cFormBody+='--' + boundary + CRLF
cFormBody+='Content-Disposition: form-data; name="description"' + CRLF + CRLF
cFormBody+=Alltrim (cOpis) + CRLF

cFormBody+='--' + boundary + CRLF

cFormBody+='Content-Disposition: form-data; name="file"; filename="' + cPlikPict + '"' + CRLF
SWITCH Upper(hb_FNameExt ( cImage ))
	CASE "JPG"
		cContentType:='image/jpeg'
		EXIT
	CASE "JPEG"
		cContentType:='image/jpeg'
		EXIT
	CASE "BMP"
		cContentType:='image/bmp'
		EXIT
	CASE "PNG"
		cContentType:='image/png'
		EXIT
	OTHERWISE
		cContentType:='image/jpeg'
END SWITCH
	
cFormBody+='Content-Type: ' + cContentType + CRLF + CRLF

cFormBody+=FILESTR( cImage ) + CRLF

cFormBody+='--' + boundary + '--' + CRLF

DO EVENTS

curl_easy_reset( curlHandle )

aHeaders := {"client-secret: " + cAPIKey, ;
		   "Content-Length: " + Str(Len(cFormBody)) , ;
		   "Content-Type: " + "multipart/form-data; boundary=" + Boundary }


/* Specify the Header  data */
curl_easy_setopt( curlHandle, HB_CURLOPT_HTTPHEADER, aHeaders)

curl_easy_setopt( curlHandle, HB_CURLOPT_URL, cUrl )
curl_easy_setopt( curlHandle, HB_CURLOPT_FOLLOWLOCATION, .T. )
curl_easy_setopt( curlHandle, HB_CURLOPT_SSL_VERIFYPEER, .F. )

curl_easy_setopt( curlHandle, HB_CURLOPT_DOWNLOAD )
curl_easy_setopt( curlHandle, HB_CURLOPT_DL_BUFF_SETUP )
	
curl_easy_setopt( curlHandle, HB_CURLOPT_POST, .T. )
curl_easy_setopt( curlHandle, HB_CURLOPT_POSTFIELDSIZE, LEN( cFormBody ) )
curl_easy_setopt( curlHandle, HB_CURLOPT_POSTFIELDS, cFormBody )

curlErr := curl_easy_perform( curlHandle )		/* Do everything */

IF !EMPTY( curlErr )	/* Report any errors */
	cReturn := "!ERROR!" + CRLF + curl_easy_strerror(curlErr)
ELSE
	cReturn := curl_easy_dl_buff_get( curlHandle )
ENDIF
 	
RETURN cReturn
************************************

Re: Help with hbcurl

Posted: Wed Jul 07, 2021 8:36 am
by Rathinagiri
OMG! You are a true saviour man!

Let me revert back with my experience. Thanks a lot.

Re: Help with hbcurl

Posted: Wed Jul 07, 2021 12:34 pm
by Rathinagiri
I am getting the following errors.

Code: Select all

d:/hmg.3.5/mingw/bin/../lib/gcc/i686-w64-mingw32/9.3.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -llibwinpthread-1
d:/hmg.3.5/mingw/bin/../lib/gcc/i686-w64-mingw32/9.3.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -llibcurl
d:/hmg.3.5/mingw/bin/../lib/gcc/i686-w64-mingw32/9.3.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lzlib1
d:/hmg.3.5/mingw/bin/../lib/gcc/i686-w64-mingw32/9.3.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -llibidn-11
Can you give me the .a library files also?

Re: Help with hbcurl

Posted: Wed Jul 07, 2021 2:08 pm
by edk
Unfortunately, I don't have these files. They are not needed if you are compiling with build.bat. I don't compile with the IDE.

Re: Help with hbcurl

Posted: Wed Jul 07, 2021 3:05 pm
by Rathinagiri
Ok. Let me try with build.bat then.

Re: Help with hbcurl

Posted: Wed Jul 28, 2021 10:35 am
by vagblad
i am going to hijack Rathi's thread here (sorry Rathi) .

I am trying to communicate with a Wordpress/Woocommerce website. Now WooCommerce has a fully functional rest api which you can use to communicate.
So my next thought was curl. I used Edward's example and knowledge(thank you once more Edward) and i am starting the communication like this:
i am trying to get the list of all the products in the WooCommerce installation.Woocommerce API documentation says you need to send a GET request at your website's URL + "/wp-json/wc/v3/products" and you will receive a response in json format.

Code: Select all

curlHandle := curl_easy_init()
aHeaders := { "Content-Type: application/json", "Accept: application/json"}
curl_easy_setopt( curlHandle, HB_CURLOPT_HTTPHEADER, aHeaders)
curl_easy_setopt( curlHandle, HB_CURLOPT_SSL_VERIFYPEER, .F. ) //because i am currently running a non-SSl test server
curl_easy_setopt( curlHandle, HB_CURLOPT_USERPWD, cAPIKey + ":" + cAPIKey2) //the woocommerce consumer_key and consumer_secret
curl_easy_setopt( curlHandle, HB_CURLOPT_URL, cUrl ) //The url i mentioned above
curl_easy_setopt( curlHandle, HB_CURLOPT_HTTPGET, .T. )
curlErr := curl_easy_perform( curlHandle )

IF !EMPTY( curlErr )	/* Report any errors */
  	cReturn := curl_easy_strerror(curlErr)
ELSE
	cReturn := curl_easy_dl_buff_get( curlHandle )
ENDIF
Now, curlErr returns 0 which means everything went ok. cReturn returns "". Anyone has any idea where can i capture the response in json?Ive been trying to figure it out but to no avail.
In php is easy as $curlErr = curl_exec($curlHandle);

Re: Help with hbcurl

Posted: Wed Jul 28, 2021 11:26 am
by edk
vagblad wrote: Wed Jul 28, 2021 10:35 am i am going to hijack Rathi's thread here (sorry Rathi) .

I am trying to communicate with a Wordpress/Woocommerce website. Now WooCommerce has a fully functional rest api which you can use to communicate.
So my next thought was curl. I used Edward's example and knowledge(thank you once more Edward) and i am starting the communication like this:
i am trying to get the list of all the products in the WooCommerce installation.Woocommerce API documentation says you need to send a GET request at your website's URL + "/wp-json/wc/v3/products" and you will receive a response in json format.

Code: Select all

curlHandle := curl_easy_init()
aHeaders := { "Content-Type: application/json", "Accept: application/json"}
curl_easy_setopt( curlHandle, HB_CURLOPT_HTTPHEADER, aHeaders)
curl_easy_setopt( curlHandle, HB_CURLOPT_SSL_VERIFYPEER, .F. ) //because i am currently running a non-SSl test server
curl_easy_setopt( curlHandle, HB_CURLOPT_USERPWD, cAPIKey + ":" + cAPIKey2) //the woocommerce consumer_key and consumer_secret
curl_easy_setopt( curlHandle, HB_CURLOPT_URL, cUrl ) //The url i mentioned above
curl_easy_setopt( curlHandle, HB_CURLOPT_HTTPGET, .T. )
curlErr := curl_easy_perform( curlHandle )

IF !EMPTY( curlErr )	/* Report any errors */
  	cReturn := curl_easy_strerror(curlErr)
ELSE
	cReturn := curl_easy_dl_buff_get( curlHandle )
ENDIF
Now, curlErr returns 0 which means everything went ok. cReturn returns "". Anyone has any idea where can i capture the response in json?Ive been trying to figure it out but to no avail.
In php is easy as $curlErr = curl_exec($curlHandle);
Try something like this (not tested):

Code: Select all

Local aHeaders := { "Content-Type: application/json", "Accept: application/json"}
Local cContent := "", cMethod := "GET"
Local nResult, cResultCode, nResultCode, nCodeHTTP := 0

Local cUrl := "https://your_url" +  "/wp-json/wc/v3/products"
Local cAPIKey := "your consumer_key"
Local cAPIKey2 := "your consumer_secret"

curlHandle := curl_easy_init()

curl_easy_reset( curlHandle )

curl_easy_setopt( curlHandle, HB_CURLOPT_URL, cUrl ) //The url i mentioned above
curl_easy_setopt( curlHandle, HB_CURLOPT_HTTPHEADER, aHeaders)
curl_easy_setopt( curlHandle, HB_CURLOPT_SSL_VERIFYPEER, 0 ) //because i am currently running a non-SSl test server
curl_easy_setopt( curlHandle, HB_CURLOPT_USERPWD, cAPIKey + ":" + cAPIKey2) //the woocommerce consumer_key and consumer_secret

/* Setup response data */
curl_easy_setopt( curlHandle, HB_CURLOPT_DOWNLOAD )
curl_easy_setopt( curlHandle, HB_CURLOPT_DL_BUFF_SETUP )

DO CASE
	CASE cMethod = "POST"
		/* Specify the POST method & data */
		curl_easy_setopt(curlHandle, HB_CURLOPT_POST, 1)
		IF !EMPTY( cContent )
			curl_easy_setopt(curlHandle, HB_CURLOPT_POSTFIELDS, cContent)
		ENDIF
	CASE cMethod = "GET"
		/* Specify the GET method */
		curl_easy_setopt(curlHandle, HB_CURLOPT_HTTPGET, 1)

	CASE cMethod = "PUT"
		/* Specify the PUT method & data */
		curl_easy_setopt(curlHandle, HB_CURLOPT_CUSTOMREQUEST, "PUT")
		IF !EMPTY( cContent )
			curl_easy_setopt(curlHandle, HB_CURLOPT_POSTFIELDS, cContent)
		ENDIF
ENDCASE

 
nResult     := curl_easy_perform( curlHandle )
cResultCode := curl_easy_strerror( nResult )
nCodeHTTP   := curl_easy_getinfo( curlHandle, HB_CURLINFO_RESPONSE_CODE, @nResultCode )

IF nResult <> HB_CURLE_OK .OR. nCodeHTTP <> 200

	ShowWarning ( "Getting products", "Error while getting products.", nResult, cResultCode, nCodeHTTP )

ENDIF

cResponse := curl_easy_dl_buff_get( curlHandle )
msgdebug ( cResponse )


***********************************************************************************************
FUNCTION ShowWarning ( cMessage, cTitle, nResult, cResultCode, nCodeHTTP )
Local nTimeOut := 5000		//5 sekund
MessageBoxTimeout ( cMessage + CRLF + CRLF + "Something went wrong: " + ;
					cResultCode + " (" + AllTrim( Str ( nResult ) ) + ;
					")   HTTP code: " + AllTrim( Str ( nCodeHTTP ) ), cTitle, ;
					MB_OK + MB_ICONERROR + MB_SYSTEMMODAL , nTimeOut )
RETURN

Re: Help with hbcurl

Posted: Wed Jul 28, 2021 11:31 am
by vagblad
Thank you Edward.
The problem was that i was missing those 2 options:

Code: Select all

curl_easy_setopt( curlHandle, HB_CURLOPT_DOWNLOAD )
curl_easy_setopt( curlHandle, HB_CURLOPT_DL_BUFF_SETUP )
Now i am getting the json response just fine. Thanks once more time!