c++ccurlcurlpp

How to map PUT curl into CPP Curlpp?


I would like to map/write below curl (this curl works correctly in Linux terminal) into cpp code:

curl -X PUT -u "abc" \
    "https://api123.pl" \
    -d 'symbol=EB&side=ri&quantity=3'

Below is the CPP code using Curlpp library:

    #include <iostream>
    #include <sstream>
    #include <curlpp/cURLpp.hpp>
    #include <curlpp/Easy.hpp>
    #include <curlpp/Options.hpp>
    using namespace curlpp::options;
    using namespace std;
    /*
    curl -X PUT -u "abc" \
        "https://api123.pl" \
        -d 'symbol=EB&side=ri&quantity=3'
    g++ name1.cpp -lcurl -lcurlpp -o name1 && ./name1
    */
    string test(const std::string &url) {
        try {
            curlpp::Cleanup cleanup;
            curlpp::Easy request;
            request.setOpt<curlpp::Options::Url>(url);
            request.setOpt(new curlpp::options::UserPwd("abc"));
            request.setOpt(new curlpp::options::CustomRequest{"PUT"});
//    /*
    //does not compile
            std::list<std::string> postContent;
            postContent.push_back("symbol:EB");
            postContent.push_back("side:ri");
            postContent.push_back("quantity:3");
            request.setOpt(new curlpp::options::PostFields(postContent));
//    */     
            std:stringstream content;
            content << request;        
            return content.str().c_str();
        }
        catch (const curlpp::RuntimeError &e) {
            std::cout << "CURLpp runtime error: " << e.what() << std::endl;
        }
        catch (const curlpp::LogicError &e) {
            std::cout << "CURLpp logic error: " << e.what() << std::endl;
        }
        throw std::string("Error");
    }
    int main(int, char **) {
        try {
            cout << test("https://api123.pl");
        }
        catch(curlpp::RuntimeError & e) {
            std::cout << e.what() << std::endl;
        }
        catch(curlpp::LogicError & e)   {
            std::cout << e.what() << std::endl;
        }
        return 0;
    }

I have got error during compilation:

1.2putStackoverflow.cpp: In function ‘std::string getJSONAPIResultFromURL(const string&)’:
1.2putStackoverflow.cpp:31:67: error: no matching function for call to ‘curlpp::OptionTrait<std::__cxx11::basic_string<char>, CURLOPT_POSTFIELDS>::OptionTrait(std::__cxx11::list<std::__cxx11::basic_string<char> >&)’
   31 |         request.setOpt(new curlpp::options::PostFields(postContent));
      |                                                                   ^
In file included from /usr/include/curlpp/Option.hpp:251,
                 from /usr/include/curlpp/Easy.hpp:31,
                 from 1.2putStackoverflow.cpp:4:
/usr/include/curlpp/Option.inl:129:1: note: candidate: ‘curlpp::OptionTrait<OptionType, opt>::OptionTrait() [with OptionType = std::__cxx11::basic_string<char>; CURLoption opt = CURLOPT_POSTFIELDS]’
  129 | OptionTrait<OptionType, option>::OptionTrait()
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/curlpp/Option.inl:129:1: note:   candidate expects 0 arguments, 1 provided
/usr/include/curlpp/Option.inl:123:1: note: candidate: ‘curlpp::OptionTrait<OptionType, opt>::OptionTrait(typename curlpp::Option<OptionType>::ParamType) [with OptionType = std::__cxx11::basic_string<char>; CURLoption opt = CURLOPT_POSTFIELDS; typename curlpp::Option<OptionType>::ParamType = const std::__cxx11::basic_string<char>&]’
  123 | OptionTrait<OptionType, option>::OptionTrait(typename Option<OptionType>::ParamType value)
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/curlpp/Option.inl:123:85: note:   no known conversion for argument 1 from ‘std::__cxx11::list<std::__cxx11::basic_string<char> >’ to ‘curlpp::Option<std::__cxx11::basic_string<char> >::ParamType’ {aka ‘const std::__cxx11::basic_string<char>&’}
  123 | OptionTrait<OptionType, option>::OptionTrait(typename Option<OptionType>::ParamType value)
      |                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
In file included from /usr/include/curlpp/Easy.hpp:31,
                 from 1.2putStackoverflow.cpp:4:
/usr/include/curlpp/Option.hpp:145:8: note: candidate: ‘curlpp::OptionTrait<std::__cxx11::basic_string<char>, CURLOPT_POSTFIELDS>::OptionTrait(const curlpp::OptionTrait<std::__cxx11::basic_string<char>, CURLOPT_POSTFIELDS>&)’
  145 |  class OptionTrait : public Option<OptionType>
      |        ^~~~~~~~~~~
/usr/include/curlpp/Option.hpp:145:8: note:   no known conversion for argument 1 from ‘std::__cxx11::list<std::__cxx11::basic_string<char> >’ to ‘const curlpp::OptionTrait<std::__cxx11::basic_string<char>, CURLOPT_POSTFIELDS>&’
/usr/include/curlpp/Option.hpp:145:8: note: candidate: ‘curlpp::OptionTrait<std::__cxx11::basic_string<char>, CURLOPT_POSTFIELDS>::OptionTrait(curlpp::OptionTrait<std::__cxx11::basic_string<char>, CURLOPT_POSTFIELDS>&&)’
/usr/include/curlpp/Option.hpp:145:8: note:   no known conversion for argument 1 from ‘std::__cxx11::list<std::__cxx11::basic_string<char> >’ to ‘curlpp::OptionTrait<std::__cxx11::basic_string<char>, CURLOPT_POSTFIELDS>&&’

The problem is with:

        std::list<std::string> postContent;
        postContent.push_back("symbol:EB");
        postContent.push_back("side:ri");
        postContent.push_back("quantity:3");
        request.setOpt(new curlpp::options::PostFields(postContent));

To compile program:

g++ name1.cpp -lcurl -lcurlpp -o name1 && ./name1

I do not know how to write code to map/write curl into cpp using curlpp. Thank you for help.


Solution

  • PostFields is just a typedef for cURLpp::OptionTrait<std::string, cURL::CURLOPT_POSTFIELDS>, I'm simplifying things below.

    If you read the error messages carefully, they tell you exactly what is wrong:

    error: no matching function for call to 'curlpp::OptionTrait<std::__cxx11::basic_string<char>, CURLOPT_POSTFIELDS>::OptionTrait(std::__cxx11::list<std::__cxx11::basic_string<char> >&)'

    What that is basically saying is that you can't pass a std::list<std::string> to the constructor of PostFields. There are 4 candidate constructors reported in the error details, none of which take a std::list as input:

    PostFields()
    PostFields(const std::string&)
    PostFields(const PostFields&)
    PostFields(PostFields&&)
    

    Indeed, if you read the cURLpp documentation, you can't create a PostFields from a std::list. Which makes sense, per the cURL documentation for CURLOPT_POSTFIELDS:

    Pass a char * as parameter, pointing to the full data to send in an HTTP POST operation. You must make sure that the data is formatted the way you want the server to receive it. libcurl will not convert or encode it for you in any way. For example, the web server may assume that this data is url-encoded.

    CURLOPT_POSTFIELDS expects a single char* as input (which cURLpp wraps using std::string), so you have to pass your PUT data as a single url-encoded string, just like you do on the command line, eg:

    request.setOpt(new curlpp::Options::PostFields("symbol=EB&side=ri&quantity=3"));
    

    Where did you ever get the idea that you can use a std::list with PostFields?


    BTW, per the cURLpp documentation, you do not really need to use new when adding options to the curlpp::Easy object:

    curlpp::Easy request;
    request.setOpt(curlpp::Options::Url(url));
    request.setOpt(curlpp::Options::UserPwd("abc"));
    request.setOpt(curlpp::Options::CustomRequest("PUT"));
    request.setOpt(curlpp::Options::PostFields("symbol=EB&side=ri&quantity=3"));