If I run this curl
command:
curl -F "file=@test.txt" https://somewebsite.com/
curl
correctly sends a POST request to https://somewebsite.com/
, uploading test.txt
to it.
However, I can't figure out how I'm meant to achieve the same behaviour with curlpp
.
This is my code so far (adapted from an example in curlpp's github repository):
#include <cstdlib>
#include <cerrno>
#include <iostream>
#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
#include <curlpp/Exception.hpp>
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::cerr << "Wrong number of arguments!" << std::endl
<< "Usage: test2 [url]"
<< std::endl;
return EXIT_FAILURE;
}
char *url = argv[1];
try
{
curlpp::Easy request;
request.setOpt(new curlpp::options::Url(url));
//request.setOpt(new curlpp::options::Verbose(true));
std::list<std::string> header;
header.push_back("User-Agent: \"testing post_request\"");
request.setOpt(new curlpp::options::HttpHeader(header));
std::string POSTrequest = "file=@test.txt";
request.setOpt(new curlpp::options::PostFields(POSTrequest));
request.setOpt(new curlpp::options::PostFieldSize(POSTrequest.length()));
request.setOpt(new curlpp::options::WriteStream(&std::cout));
request.perform();
}
catch ( curlpp::LogicError & e )
{
std::cout << e.what() << std::endl;
}
catch ( curlpp::RuntimeError & e )
{
std::cout << e.what() << std::endl;
}
return EXIT_SUCCESS;
}
When I run my program, the server/website returns this:
Segmentation fault
(Bad request. Check POST parameters. Hint: The curl command line requires an @ before local file names.)
I've tried to not use @
in the file name, and spliting the fields into two. Both didn't help.
I've also tried different combinations of "seperating characters" (I'm meaning the character inbetween "file" and "test.txt"), such as /
, :
, and ;
. Have also tried using an absolute path. Nothing worked.
I'm using Fedora 41.
Thanks in advance.
EDIT: This is the code that this command:
curl -F "file=@test.txt" https://somewebsite.com/ --libcurl ./test.c
Generates:
/********* Sample code generated by the curl command line tool **********
* All curl_easy_setopt() options are documented at:
* https://curl.se/libcurl/c/curl_easy_setopt.html
************************************************************************/
#include <curl/curl.h>
int main(int argc, char *argv[])
{
CURLcode ret;
CURL *hnd;
curl_mime *mime1;
curl_mimepart *part1;
mime1 = NULL;
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "https://somewebsite.com/");
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
mime1 = curl_mime_init(hnd);
part1 = curl_mime_addpart(mime1);
curl_mime_filedata(part1, "test.txt");
curl_mime_name(part1, "file");
curl_easy_setopt(hnd, CURLOPT_MIMEPOST, mime1);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/8.9.1");
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
/* Here is a list of options the curl code used that cannot get generated
as source easily. You may choose to either not use them or implement
them yourself.
CURLOPT_WRITEDATA was set to an object pointer
CURLOPT_WRITEFUNCTION was set to a function pointer
CURLOPT_READDATA was set to an object pointer
CURLOPT_READFUNCTION was set to a function pointer
CURLOPT_SEEKDATA was set to an object pointer
CURLOPT_SEEKFUNCTION was set to a function pointer
CURLOPT_ERRORBUFFER was set to an object pointer
CURLOPT_STDERR was set to an object pointer
CURLOPT_HEADERFUNCTION was set to a function pointer
CURLOPT_HEADERDATA was set to an object pointer
*/
ret = curl_easy_perform(hnd);
curl_easy_cleanup(hnd);
hnd = NULL;
curl_mime_free(mime1);
mime1 = NULL;
return (int)ret;
}
/**** End of sample code ****/
So, correct me if I'm wrong, but according to this code, curl_mime
functions were used instead of POSTs. My question then: How can I do the same thing with curlpp?
If you're trying to upload a file with curlpp
, the PostFields
approach does not work. Instead you could use curlpp::FormParts
. This has the file attachment option. So instead of,
std::string POSTrequest = "file=@test.txt";
request.setOpt(new curlpp::options::PostFields(POSTrequest));
request.setOpt(new curlpp::options::PostFieldSize(POSTrequest.length()));
request.setOpt(new curlpp::options::WriteStream(&std::cout));
You would write the following,
std::string filename = "test.txt";
curlpp::Forms formParts;
formParts.push_back(new curlpp::FormParts::File("file", filename));
request.setOpt(new curlpp::Options::HttpPost(formParts));
For more information you should check out this StackOverflow post. This approach is based on that post.
Furthermore, you could also look at the official curlpp
forms example, although it doesn't demonstrate file uploading specifically.