I have a file to upload to a server API and found this thread which I followed – in my case, I have to add some headers too which are working with different API methods from this server. But everything I tried – taking the direct approach as in the link
curl.FormAdd curl.kFormFilename, log.name, curl.kFormFile, log.URLPath
or being a bit more verbose
curl.FormAdd curl.kFormFilename, log.name, curl.kFormFileContent, s, curl.kFormContentsLength, s.bytes, curl.kFormContentType, "text/csv"
(where s is the content of log)
being followed by a curl.FormFinish
of course
results in just a handful of bytes being transferred, and so no file arrives in the API.
Apparently I must be doing something wrong. But what?
More details here?
Well, in general you may want to move to CURLSMimePartMBS class.
See example here:
https://www.monkeybreadsoftware.net/example-curl-curlmime.shtml
Thank you, I’ll try it!
More details are like follows:
Public Sub SendErrorLog(serialnumber as string, log as FolderItem)
Const ListId = "error_feedback"
var url As String = makeCallURL(ListId)
var now As DateTime = DateTime.now
var key As EinhugurSecureString = EncryptionKey(now)
var curl As New CurlServerTransfer(ListId)
curl.OptionURL = url
curl.OptionPost = True
curl.OptionVerbose = True
curl.DebugWithData = True
curl.CollectDebugMessages = True
var s As String
If log.ReadFileMBS(s) Then
s = s.DefineEncoding(encodings.utf8)
AddHeaders(curl, now, key, "userid_sequence: " + serialnumber)
curl.FormAdd curl.kFormFilename, log.name, curl.kFormFile, log.URLPath
//curl.FormAdd curl.kFormFilename, log.name, curl.kFormFileContent, s, curl.kFormContentsLength, s.bytes, curl.kFormContentType, "text/csv"
curl.FormFinish
If Not Me.AddTransfer(curl) Then
Me.RaiseError(curl, New RuntimeException("Could not send curl to server", -1))
End If
End If
End Sub
curl.FormAdd curl.kFormFilename, log.name, curl.kFormFile, log.URLPath
for this, please use native path.
Also not working, neither native path nor MIME. Curl will only upload the header and cancel transmission after expect: continue. Could it be that chunked transfer is interfering? Do I have to do something when a continue appears in CurlSMBS?
Or is it the reuse of transmissions?
What does the curl log show?
You can include “Expect:” in the HTTP Header option to disable chunked upload. It should not interfere as that has been standard for 10+ years.
If the log shows reuse of connection, you can use OptionFreshConnect = true
to ask for a new connection. But in general POST connections are not reused.
Thank you for your support, Christian!
Log is like this:
MBS Xojo Plugins 25.0 with CURL 8.11.1 on macOS.
URL: https://api.serveraddress.com/admin/common/error_feedback
Hostname api.serveraddress.com was found in DNS cache
Trying xxx.xxx.xxx.xxx:443…
ALPN: curl offers http/1.1
TLSv1.3 (OUT), TLS handshake, Client hello (1):
TLSv1.3 (IN), TLS handshake, Server hello (2):
TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
TLSv1.3 (IN), TLS handshake, Certificate (11):
TLSv1.3 (IN), TLS handshake, CERT verify (15):
TLSv1.3 (IN), TLS handshake, Finished (20):
TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
TLSv1.3 (OUT), TLS handshake, Finished (20):
SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / x25519 / RSASSA-PSS
ALPN: server accepted http/1.1
Server certificate:
subject: CN=api.serveraddress.com
start date: Dec 12 02:35:15 2024 GMT
expire date: Mar 12 02:35:14 2025 GMT
issuer: C=US; O=Let’s Encrypt; CN=R10
SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
Connected to api.serveraddress.com (xxx.xxx.xxx.xxx) port 443
using HTTP/1.x
POST /admin/common/error_feedback HTTP/1.1
Host: api.serveraddress.com
Accept: /
Transfer-Encoding: chunked
times: 2025-01-23 08:53:29
secret_key: 572FFxxxxxx
userid_sequence: 31259xxxxx
Content-Type: application/x-www-form-urlencoded
Expect: 100-continue
HTTP/1.1 100 Continue
0
upload completely sent off: 5 bytes
HTTP/1.1 200 OK
Connection: Keep-Alive
Keep-Alive: timeout=5, max=100
access-control-allow-origin: *
access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept
access-control-allow-methods: GET, POST, PUT
content-type: text/html; charset=UTF-8
content-length: 343
date: Thu, 23 Jan 2025 07:53:29 GMT
server: LiteSpeed
Array ( [/admin/common/error_feedback] => ) ====================Array ( [Host] => api.serveraddress.com [Accept] => */* [Content-Length] => 0 [times] => 2025-01-23 08:53:29 [secret_key] => 572FFC5CFBDxxxxxxx [userid_sequence] => 31259xxxxx [Content-Type] => application/x-www-form-urlencoded ) Connection #2 to host api.serveraddress.com left intact
From trying to send a log with a few 100 bytes with
Const ListId = "error_feedback"
var url As String = makeCallURL(ListId)
var now As DateTime = DateTime.now
var key As EinhugurSecureString = EncryptionKey(now)
var curl As New CurlServerTransfer(ListId)
curl.OptionFreshConnect = True
curl.OptionURL = url
curl.OptionPost = True
curl.OptionVerbose = True
curl.DebugWithData = True
curl.CollectDebugMessages = True
var s As String
If log.ReadFileMBS(s) Then
s = s.DefineEncoding(encodings.utf8)
AddHeaders(curl, now, key, "userid_sequence: " + serialnumber)
var mime As CURLSMimePartMBS = curl.AddMimePart
mime.File = log
mime.SetHeaders(Array ("content-length: " + log.Length.ToString))
mime.MimeType = "text/csv"
mime.Name = log.Name
curl.FinishMime
curl.OptionInFileSize = log.Length
If Not Me.AddTransfer(curl) Then
Me.RaiseError(curl, New RuntimeException("Could not send curl to server", -1))
End If
End If
I was not sure if I need to add MIME headers. Tried without, without InFileSize or with full headers in MIME, which gives same result.
With an “Expect:” added to the headers, I still see a
Transfer-Encoding: chunked
in the log.
Sorry for feeling kinda stupid – I wish I’d understand more of curl …
What is log there? A folder item?
Why do you use ReadFileMBS, but not use s for the content?
Why do you overwrite the curl.OptionInFileSize? Please remove!
The size is set by the mime stuff.
Why do you use SetHeaders for the CURLSMimePartMBS? You may put the wrong number there as you don’t handle the base64 encoding. Setting an option too much is often bad.
Yes. A tab separated text file.
This is from trying FormAdd. Or do I have to add Mime.Content even if I address the file directly?
As written, I tried without and got the same result. But I’ll try again without.
Same as above.
Removed all stuff, tried with just setting the MIME file or different combinations like below. Content-Length is set automatically, but still no file is being transferred. I must be missing something, but really have no clue.
AddHeaders(curl, now, key, "Expect:", "userid_sequence: " + serialnumber)
var mime As CURLSMimePartMBS = curl.AddMimePart
mime.File = log
mime.MimeType = "text/csv"
mime.FileName = log.Name
mime.Encoding = CURLSMimePartMBS.kEncodingQuotedPrintable
curl.FinishMime
Sorry, you could of course send me a test project later.
You could try DataString property with the content instead of file property.
What is the new curl messages log?