Curl with -F option

387 views
Skip to first unread message

cod...@outlook.com

unread,
Apr 3, 2025, 3:52:04 PMApr 3
to Harbour Users

Hi.

I had to write Harbour program to send this type of Curl command, using hbcurl:

 

curl -X 'POST' \  'https://api.test.aa/docxml' \

  -H 'accept: */*' \

  -H 'Api-key: 11111111-faf9-2222-3333-4564564564' \

  -H 'Content-Type: multipart/form-data' \

  -F 'RequestId=6767567856795' \

  -F 'File=@test.XML;type=text/xml'

 

In Harbour-users group I found a few posts about this type of Curl command but with no definite solution. 

 My problem is that I can not figure out what is the right way to prepare -F parts of command. Header parts are not problem, but -F parts confuses me.

 I found this example:

 cFilexml:="D:\path\to\test.xml"   (is it right way to use slash  D:/path/to/test.xml  or backslash  ?)

cBoundary:='XX'+HB_STRTOHEX(HB_TTOC(HB_DATETIME(),'YYYYMMDDhhmmssfff'))

   sPost:="--"+cBoundary + CRLF

   sPost := sPost+'Content-Disposition: form-data; name="RequestId"' + CRLF

   sPost := sPost+cRequestId + CRLF

   sPost := sPost+"--"+cBoundary + CRLF

   sPost := sPost+'Content-Disposition: form-data; name="File"; filename=@' + cFilexml +';type=text/xml' + CRLF

sPost := sPost+"--"+cBoundary + "--" + CRLF

*

curl_easy_setopt(curl,HB_CURLOPT_POSTFIELDS, sPost)

 

Somewhere I found next example that do not use cBoundary:

       fpParams:={}

      AADD(fpParams,{"RequestId",cRequestId})

      AADD(fpParams,{"File",cFilexml})

      requestParams:=""

      FOR EACH param IN fpParams

         requestParams += param[1] + "=" + curl_easy_escape(curl, AllTrim(HB_ValToStr(param[2]))) + "&"

      NEXT

      // Removes trailing znak &

      IF(LEN(requestParams) > 0)

         requestParams := LEFT(requestParams, LEN(requestParams) - 1)

      ENDIF

      *

      curl_easy_setopt(curl,HB_CURLOPT_POSTFIELDS, requestParams)

 

There are several variations of this two examples, but I did not found unquestionable example.

 If someone have experience with this type of Curl command using hbcurl, please explain  what is the right and in practice verified  way to prepare and use -F parts. I prefer to send command using hbcurl, not with HB_RUN from command lice.  

 I had a few attempts but with no success. Now I do not know was it because I did not prepared -F parts correctly or error is somewhere else in my program.

 Thank you in advance.

 Regards,

Simo.


Rodrigo Rossi

unread,
Apr 4, 2025, 9:46:59 PMApr 4
to Harbour Users
Hi Simo.

Recently, I had this same issue.

I think the relevant piece of code in your case is:

cFilexml:="D:\path\to\test.xml"
curl_easy_setopt( xCurl, HB_CURLOPT_MIMEPOST, { { "File", cFilexml }, { "ending", "-----011000010111000001101001--" } } )

That "ending" part is kind of a dummy part I had to send, because the server was responding with something like "Unexpected end of Stream".
I randomly chose the name "ending", and its content was the boundary shown in the API examples.
I didn't do any further tests, but I'm pretty sure the name and content of this second part doesn't matter. They just force hbcurl to send the end (boundary) of the first (File) part, or maybe the "end of line" sequence, avoiding the mentioned server error.

Let me know, please, if this solved your issue.

Regards,
Rodrigo

Rodrigo Rossi

unread,
Apr 4, 2025, 10:00:03 PMApr 4
to Harbour Users
Sorry... Just for clarity...
Your curl command sends two fields. You can send as many fields as you want, of course.

cFilexml:="D:\path\to\test.xml"
curl_easy_setopt( xCurl, HB_CURLOPT_MIMEPOST, { { "RequestId", "6767567856795" }, { "File", cFilexml }, { "ending", "-----011000010111000001101001--" } } )

Regards,
Rodrigo

Rodrigo Rossi

unread,
Apr 4, 2025, 10:48:50 PMApr 4
to Harbour Users
Although hbcurl only uses the curl_mime_filedata function from libcurl when using HB_CURLOPT_MIMEPOST.
To send the "RequestId" field, it would make sense to use curl_mime_data, but hbcurl doesn't use it at all.
I really don't know what happens in this case.

cod...@outlook.com

unread,
Apr 5, 2025, 3:34:01 AMApr 5
to Harbour Users

Hi Rodrigo.

Thank you for your reply !

I work with Harbour 3.2.0dev, Windows environment.

I tried what you suggested but got error:

Variable does not exist: HB_CURLOPT_MIMEPOST

When I look at  \contrib\hbcur\hbcurl.ch I could not find  any ...MIME... value. It looks like HB_CURLOPT_MIMEPOST does not exist in my Harbour version.

Regards,

Simo.

Rodrigo Rossi

unread,
Apr 5, 2025, 6:11:17 AMApr 5
to harbou...@googlegroups.com

Hi Simon.

Please, replace HB_CURLOPT_MIMEPOST by HB_CURLOPT_HTTPPOST.

HB_CURLOPT_MIMEPOST was added later to hbcurl offering support for a new libcurl multipart post API.

Regards,
Rodrigo


--
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com
Web: https://groups.google.com/group/harbour-users
---
You received this message because you are subscribed to a topic in the Google Groups "Harbour Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/harbour-users/Zl5AQvj6pag/unsubscribe.
To unsubscribe from this group and all its topics, send an email to harbour-user...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/harbour-users/66c1b078-cab6-404f-be1d-20fc50ad5618n%40googlegroups.com.

Rodrigo Rossi

unread,
Apr 5, 2025, 6:16:49 AMApr 5
to harbou...@googlegroups.com

Sorry for the typo in your name Simo ;)

cod...@outlook.com

unread,
Apr 5, 2025, 6:57:05 AMApr 5
to Harbour Users

Hi Rodrigo.

I replaced HB_CURLOPT_MIMEPOST with HB_CURLOPT_HTTPPOST :

      curl_easy_setopt( curl, HB_CURLOPT_HTTPPOST, { { "RequestId", "6767567856795" }, ;

         { "File", cFilexml }, { "ending", "-----011000010111000001101001--" } } )

Also included  curl_easy_setopt(curl,HB_CURLOPT_VERBOSE,.T.)  to see more information.

In verbose output I got this:

* couldn't open file "6767567856795"

* Connection #0 to host https://api.test.aa/docxml left intact

* Failed to open/read local data from file/application

It looks like HB_CURLOPT_HTTPPOST every parameter observes as file.  RequestId is just an Id parameter, not a file.

 Regards,

Simo.


Rodrigo Rossi

unread,
Apr 5, 2025, 7:56:47 AMApr 5
to harbou...@googlegroups.com

Hi Simo.

Yeah... That was my fear when I realized that hbcurl was only using curl_mime_filedata.
This is also true with HB_CURLOPT_HTTPPOST. They only implemented file uploads through CURL_FORM_FILE.
Unfortunately, that's what we have in hbcurl right now regarding multipart/form-data, as far as I know.


--
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com
Web: https://groups.google.com/group/harbour-users
---
You received this message because you are subscribed to a topic in the Google Groups "Harbour Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/harbour-users/Zl5AQvj6pag/unsubscribe.
To unsubscribe from this group and all its topics, send an email to harbour-user...@googlegroups.com.

cod...@outlook.com

unread,
Apr 5, 2025, 8:36:45 AMApr 5
to Harbour Users

Hi Rodrigo.

Anyhow, thank you very much for your kind suggestions.

I will try to find some other way to realize this POST call.

To mention, I use other POST and GET API calls without any problem. Even one to send XML data where data are not referenced in file but are part of request body as string. This POST call in my first message is troublesome.

Regards,

Simo.

Rodrigo Rossi

unread,
Apr 5, 2025, 2:47:55 PMApr 5
to harbou...@googlegroups.com
Hi Simo.

You're welcome. I'm glad I could help.
Using ChatGPT and the options you provided in your first curl command example, the following code was produced:

#include "hbcurl.ch"

#define CRLF Chr(13)+Chr(10)

PROCEDURE Main()

LOCAL xCurl, cBoundary, cPostData, cResponse, cRequestId, cFilexml, cApiKey

cBoundary := "X" + hb_StrToHex( hb_TToC( hb_DateTime(), "YYYYMMDDhhmmssfff" ) )
cRequestId := "6767567856795"
cFilexml := "test.XML"
cApiKey := "11111111-faf9-2222-3333-4564564564"

cPostData := ""
cPostData += "--" + cBoundary + CRLF
cPostData += 'Content-Disposition: form-data; name="RequestId"' + CRLF + CRLF
cPostData += cRequestId + CRLF
cPostData += "--" + cBoundary + CRLF
cPostData += 'Content-Disposition: form-data; name="File"; filename="' + cFilexml + '"' + CRLF
cPostData += "Content-Type: text/xml" + CRLF + CRLF
cPostData += hb_MemoRead( cFilexml ) + CRLF
cPostData += "--" + cBoundary + "--" + CRLF

xCurl := curl_easy_init()
curl_easy_setopt( xCurl, HB_CURLOPT_URL, cUrl )
curl_easy_setopt( xCurl, HB_CURLOPT_POST, .T. )
curl_easy_setopt( xCurl, HB_CURLOPT_POSTFIELDS, cPostData )
curl_easy_setopt( xCurl, HB_CURLOPT_HTTPHEADER, { ;
"Accept: */*", ;
"Api-key: " + cApiKey, ;
"Content-Type: multipart/form-data; boundary=" + cBoundary, ;
"Content-Length: " + LTrim( Str( Len( cPostData ) ) ) } )

cResponse := curl_easy_perform( xCurl )
? cResponse
curl_easy_cleanup( xCurl )

RETURN

I used "https://httpbin.org/post" to send the request, and it worked.

Regards,
Rodrigo

--
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com
Web: https://groups.google.com/group/harbour-users
---
You received this message because you are subscribed to a topic in the Google Groups "Harbour Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/harbour-users/Zl5AQvj6pag/unsubscribe.
To unsubscribe from this group and all its topics, send an email to harbour-user...@googlegroups.com.

cod...@outlook.com

unread,
Apr 6, 2025, 2:30:23 AMApr 6
to Harbour Users

Hi Rodrigo.

Thank you for your code example.

I will try to implement it in my place. But these days my server for testing is out of work, so I must wait.  

I am also thinking to make newest version of Harbour 3.2, my version is from year 2019. As it works good I did not want to change it. I saw that in newest version there is HB_CURLOPT_MIMEPOST.

It is in my mind to try also with Harbour 3.4 .  

I will inform you what was the end result. Thanks again for your effort.

Regards,

Simo.

cod...@outlook.com

unread,
Apr 8, 2025, 1:50:39 PMApr 8
to Harbour Users
Hi.
Just to inform what I did. 

At he end I did not succeeded  to send XML using Curl lib.
But I succeeded to send it using Curl command line , described on  https://groups.google.com/g/harbour-users/c/KG8nHIJfTRM/m/dQkUtl9PBAAJ  .

For now I will work this way. 

Regards,
Simo.

cod...@outlook.com

unread,
Dec 13, 2025, 3:05:35 PM (yesterday) Dec 13
to Harbour Users

Hi Rodrigo.

Better late than never.

As I said  I ended up with POST sending XML by calling external Curl.exe.

Meanwhile from time to time I asked for solution with libcurl.

These days our colleague sent me his example with Win_OleCreateObject( "MSXML2.ServerXMLHTTP.6.0" ). His name is Branislav Milosevic, and I thank him. His example works ! In his example I learned how to prepare form-data cBody in proper way, especially File part of body.  Then I used his method in libcurl and it also works.

Then I again read your example in procedure Main and realized that it is perfectly good ! Your example is correct, with proper code for  cPostData . 

That is what I wanted to say. It is reliable to use your example to work with multipart/form-data cases in libcurl.

Best Regards,

Simo.

Reply all
Reply to author
Forward
0 new messages