C++ Requests: Curl for People, a spiritual port of Python Requests

Overview

C++ Requests: Curl for People

Documentation CI

Announcements

The cpr project has new maintainers: Fabian Sauter and Tim Stack.

TLDR

C++ Requests is a simple wrapper around libcurl inspired by the excellent Python Requests project.

Despite its name, libcurl's easy interface is anything but, and making mistakes misusing it is a common source of error and frustration. Using the more expressive language facilities of C++11, this library captures the essence of making network calls into a few concise idioms.

Here's a quick GET request:

#include <cpr/cpr.h>

int main(int argc, char** argv) {
    cpr::Response r = cpr::Get(cpr::Url{"https://api.github.com/repos/whoshuu/cpr/contributors"},
                      cpr::Authentication{"user", "pass"},
                      cpr::Parameters{{"anon", "true"}, {"key", "value"}});
    r.status_code;                  // 200
    r.header["content-type"];       // application/json; charset=utf-8
    r.text;                         // JSON text string
}

And here's less functional, more complicated code, without cpr.

Documentation

Documentation
You can find the latest documentation here. It's a work in progress, but it should give you a better idea of how to use the library than the tests currently do.

Features

C++ Requests currently supports:

  • Custom headers
  • Url encoded parameters
  • Url encoded POST values
  • Multipart form POST upload
  • File POST upload
  • Basic authentication
  • Bearer authentication
  • Digest authentication
  • NTLM authentication
  • Connection and request timeout specification
  • Timeout for low speed connection
  • Asynchronous requests
  • 🍪 support!
  • Proxy support
  • Callback interfaces
  • PUT methods
  • DELETE methods
  • HEAD methods
  • OPTIONS methods
  • PATCH methods
  • Thread Safe access to libCurl
  • OpenSSL and WinSSL support for HTTPS requests

Planned

For a quick overview about the planed features, have a look at the next Milestones.

Usage

If you already have a project you need to integrate C++ Requests with, the primary way is to use CMake fetch_content. Add the following to your CMakeLists.txt.

include(FetchContent)
FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/whoshuu/cpr.git GIT_TAG c8d33915dbd88ad6c92b258869b03aba06587ff9) # the commit hash for 1.5.0
FetchContent_MakeAvailable(cpr)

This will produce the target cpr::cpr which you can link against the typical way:

target_link_libraries(your_target_name PRIVATE cpr::cpr)

That should do it! There's no need to handle libcurl yourself. All dependencies are taken care of for you.

Requirements

The only explicit requirements are:

  • a C++11 compatible compiler such as Clang or GCC. The minimum required version of GCC is unknown, so if anyone has trouble building this library with a specific version of GCC, do let me know
  • If you would like to perform https requests OpenSSL and its development libraries are required.

Building cpr - Using vcpkg

You can download and install cpr using the vcpkg dependency manager:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install cpr

The cpr port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

Building cpr - Using Conan

You can download and install cpr using the Conan package manager. Setup your CMakeLists.txt (see Conan documentation on how to use MSBuild, Meson and others) like this:

project(myproject CXX)

add_executable(${PROJECT_NAME} main.cpp)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) # Include Conan-generated file
conan_basic_setup(TARGETS) # Introduce Conan-generated targets

target_link_libraries(${PROJECT_NAME} CONAN_PKG::cpr)

Create conanfile.txt in your source dir:

[requires]
cpr/1.5.0

[generators]
cmake

Install and run Conan, then build your project as always:

pip install conan
mkdir build
cd build
conan install ../ --build=missing
cmake ../
cmake --build .

The cpr package in Conan is kept up to date by Conan contributors. If the version is out of date, please create an issue or pull request on the conan-center-index repository.

Comments
  • cmake config

    cmake config

    I'm still creating a FreeBSD port, and it would be great to have a cmake config for cpr in order to do stuff like find_package(cpr).

    Thank you very much in advance.

    opened by part1zano 30
  • progress callback draft

    progress callback draft

    Hi! I added an issue here #432 a few minutes ago, but then i realised that there was an already existing issue that's been open for quite a while sadly #111.

    This is a quick draft / example of adding a progress callback option, and it works 😄 . This allows us to create progress bars and also cancel any request early by returning a non zero value from the callback!

    If there's any chance of adding this and you want me to clean up anything, let me know! Thanks

    Tests Needed :rotating_light: Feature :sparkles: Documentation Needed :green_book: 
    opened by ITotalJustice 20
  • "free(): invalid pointer" when using CPR with conan

    Description

    When using CPR with conan I get this error when trying to run the binary

    free(): invalid pointer
    Aborted
    

    Expected Behavior

    Should work

    Actual Behavior

    It breaks

    Possible Fix

    Steps to Reproduce

    1. Use CPR with conan

    Context

    I was trying to reach out to a website and get the response body/text.

    Your Environment

    • Version used: 1.6.2
    • Where did you get it from (e.g. conan, vcpkg, master, ...): conan
    • Operating System and version: Linux ari-gentoo 5.14.2-gentoo #1 SMP Thu Sep 9 18:26:44 EEST 2021 x86_64 Intel(R) Core(TM) i3-8130U CPU @ 2.20GHz GenuineIntel GNU/Linux
    • Link to a small example: https://replit.com/@B00bleaTea/ghufhuerhyur4gyfghryfhryhfyufhurehufberfhberhbfhuerbfhuerf#main.cpp

    Run this when trying the example (in the shell tab):

    chmod a+rx ./build.sh
    
    ./build.sh
    
    ./bin/conantest 'https://google.com'
    
    Bug :bug: Needs Investigation :mag: 
    opened by TruncatedDinosour 17
  • Static linking (Windows)

    Static linking (Windows)

    Hello. I am trying to use a static version of the library installed through VCPKG using the command./vcpkg install cpr:x86-windows-static but i am getting many errors. image

    This are my settings: image image

    Bug :bug: Build :construction_worker: Windows :tv: 
    opened by John4266 17
  • Provide CPRConfig.cmake to allow easy find_package()

    Provide CPRConfig.cmake to allow easy find_package()

    I'm all but a cmake expert but if I interpret this http://www.cmake.org/cmake/help/git-master/manual/cmake-packages.7.html#creating-packages link and my cmake output correctly, supplying CPRConfig.cmake would allow downstream projects to include cpr as a dependency like this:

     set ( CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} vendor/cpr/)
     find_package ( CPR REQUIRED )
     include_directories ( ${CPR_INCLUDE_DIRS} )
    

    and then use ${CPR_LIBRARIES} in target_link_libraries(). Instead of vendoring it could also be installed in the system path getting rid of the first line in the snippet above.

    Documentation :books: Build :construction_worker: 
    opened by niklas88 17
  • Empty response text and status code 0 at example code

    Empty response text and status code 0 at example code

    Code

    #include <cpr/cpr.h>
    #include <iostream>
    
    int main(int argc, char** argv) {
        cpr::Response r = cpr::Get(cpr::Url{"https://api.github.com/repos/whoshuu/cpr/contributors"},
                          cpr::Authentication{"user", "pass"},
                          cpr::Parameters{{"anon", "true"}, {"key", "value"}});
        std::cout << r.status_code << std::endl << r.text;
        return 0;
    }
    

    Expected Behavior

    It should print the status code and the response body

    Actual Behavior

    It prints 0

    Your Environment

    • Where did you get it from (e.g. conan, vcpkg, master, ...): master
    • Operating System and version: MacOS 12.1
    • Build System: g++/clang++
    Needs Investigation :mag: 
    opened by Pxddyk45 16
  • How can I use cpr as a static linked library on Windows?

    How can I use cpr as a static linked library on Windows?

    Hiya. I got cpr and libcurl from vcpkg

    ./vcpkg install libcurl:x86-windows-static
    ./vcpkg install cpr:x86-windows-static
    

    Due to vcpkg having a static package for cpr, I just assume that it exists and works.

    Now.. it works. However, requires libcurl.dll and zlib1.dll in the app's directory. When I try to build with the runtime library as Multi-threaded (/MT), I get a bunch of errors from cpr

    1>cpr.lib(session.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    1>cpr.lib(auth.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    1>cpr.lib(cookies.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    1>cpr.lib(digest.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    1>cpr.lib(proxies.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    1>cpr.lib(error.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    1>cpr.lib(timeout.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    1>cpr.lib(util.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    1>cpr.lib(cprtypes.cpp.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in CMainWindow.obj
    

    Am I doing something wrong?

    Build :construction_worker: Question :question: Help Needed :tipping_hand_man: Windows :tv: 
    opened by shavitush 15
  • Add ability to install library and headers through CMake

    Add ability to install library and headers through CMake

    There are three competing pull requests right now that implement this. My laziness has unfortunately resulted in some duplicate work 😥 .

    #176 #132 #56

    Unbiased discussion on the pros and cons of each approach would be appreciated. The immediate goal is to make make install in a sane way. The long term goal is to make packaging the library (for something like Homebrew for instance) feasible so it can be distributed without git.

    Build :construction_worker: Discussion :interrobang: 
    opened by whoshuu 15
  • Problems with HTTPS requests.

    Problems with HTTPS requests.

    Description

    The problem occurs when I'm trying to send any type of request to an https server. With http it works just fine. If server supports both, http and https it also works when I'm trying to send https request. To make sure that issue is actual I tried to install libcpr on another computer, and it did the same. Moreover, I used libcpr for a month and there were no problems ever, but as soon as I reinstalled the library, this happened. Also, I tried to test libCurl, and it sends https requests to any server.

    Expected Behavior

    Sending HTTPS requests as always.

    Actual Behavior

    Does send only HTTP requests and returns code 0 when trying to send HTTPS.

    Your Environment

    • Version used: 1.7.2
    • Where did you get it from (e.g. conan, vcpkg, master, ...): vcpkg
    • Operating System and version: Windows 10 Pro 21H1, Build 19043.1526
    • Link to a small example: https://imgur.com/4TOPax9
    curl :globe_with_meridians: 
    opened by 1Klas 14
  • CPR on Raspberry Pi

    CPR on Raspberry Pi

    Hi there,

    For a home project I would like to use CPR on the raspberry pi 2b+. I made a small test program to read and write data to a Rest Api, but the POST request hangs forever and is not executed on the Rest Api. The GET request works fine. I build the the same code also on my desktop(Ubuntu 20.04 amd64) and that gives no problems. My first attempt was cross-compiling with various toolchains, but it always hangs on the POST/PUT request. Finally I did a local build on the raspberry pi and it kept hanging on the POST request.

    The c++ code is:

    #include <iostream>
    #include <cpr/cpr.h>
    #include "nlohmann/json.hpp"
    
    using json = nlohmann::json;
    
    int main()
    {
    	std::cout << "Hello World\n";
    
    	auto r = cpr::Get(cpr::Url("http://192.168.10.188:3001/environment?select=location,pressure"));
    
    		std::cout << r.status_code << std::endl;
    		std::cout << r.header["content-type"] << std::endl;
    		std::cout << r.text << std::endl;
    
    	json msg;
    	msg["location"] = "livingroom";
    	msg["temperature"] = 27.5;
    	msg["pressure"] = 1006.1;
    	msg["humidity"] = 61;
    	msg["time"] = "2020-07-01T13:21:22.18542+00:00";
    	std::cout << msg.dump() << std::endl;
    	r = cpr::Post(cpr::Url("http://192.168.10.188:3001/environment"),
    				  cpr::Header{{"Content-Type", "application/json"},
    							  {"Content-Length", std::to_string(msg.dump().length())}},
    				  cpr::Body(msg.dump()));
    
    	std::cout << r.status_code << std::endl;
    	std::cout << r.header["content-type"] << std::endl;
    	std::cout << r.text << std::endl;
    
    	return 0;
    }
    

    my makefile is:

    OBJECTS=build/main.o 
    
    BUILDDIR=build/
    SOURCEDIR=src/
    LIB=-L/usr/local/lib/ -L/usr/local/lib
    # include the src directory for rapidjson and spdlog includes
    INC=-Isrc
    MKDIR_P = mkdir -p
    
    .PHONY : all
    all: $(BUILDDIR)testCprSimple
    
    $(BUILDDIR)testCprSimple : $(OBJECTS)
    	g++ -o $(BUILDDIR)testCprSimple $(OBJECTS) $(LIB) -latomic -lcpr -lcurl
    
    $(BUILDDIR)main.o : $(SOURCEDIR)main.cpp
    	g++ -o $(BUILDDIR)main.o $(SOURCEDIR)main.cpp -std=c++14 $(INC) -g3 -O2 -Wall -c -fmessage-length=0
    
    # There are two reasons to use a phony target: 
    # to avoid a conflict with a file of the same name, and to improve performance. 	
    .PHONY: clean
    clean :
    	rm $(BUILDDIR)testCprSimple $(OBJECTS)
    # Tab must be used as indentation
    

    I am using 2020-02-13-raspbian-buster-lite as OS on the raspberry pi with gcc (Raspbian 8.3.0-6+rpi1) 8.3.0

    I have installed and build CPR successfully on the raspberry pi with:

    git clone https://github.com/whoshuu/cpr.git
    cd cpr
    git submodule update --init
    mkdir build; cd build
    cmake -DCMAKE_USE_OPENSSL=OFF ..
    make
    sudo make install
    

    The curl program itself is working with POST request on the pi: curl http://192.168.10.188:3001/environment -X POST -H "Content-Type: application/json" -d '{"location":"livingroom", "temperature":23.2,"pressure":1002.5, "humidity":49, "time":"2020-07-01T13:21:22.18542+00:00"}'

    Am i forgetting something for the raspberry pi / arm build or is it a bug? Thanks in advance for your help.

    Bug :bug: 
    opened by skipper85 14
  • HTTP Error 411 while making POST request to Microsoft Azure Workspace

    HTTP Error 411 while making POST request to Microsoft Azure Workspace

    I am trying to set up a remote log system on the Microsoft Azure Workspace. I am using cpr POST request to send sample JSON data over to the server. The code I used is as follows:

    #include <iostream>
    #include <map>
    #include <utility>
    #include <nlohmann/json.hpp>
    using json = nlohmann::json;
    #include <cpr/cpr.h>
    #include <time.h>
    using std::cout;
    using std::cerr;
    using std::endl;
    
    #include <string>
    using std::string;
    
    #include "cryptopp/cryptlib.h"
    using CryptoPP::Exception;
    
    #include "cryptopp/hmac.h"
    using CryptoPP::HMAC;
    
    #include "cryptopp/sha.h"
    using CryptoPP::SHA256;
    
    #include "cryptopp/base64.h"
    using CryptoPP::Base64Encoder;
    using CryptoPP::Base64Decoder;
    
    #include "cryptopp/filters.h"
    using CryptoPP::StringSink;
    using CryptoPP::StringSource;
    using CryptoPP::HashFilter;
    
    
    
    typedef unsigned char byte;
    
    string CUSTOMER_ID = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
    string SHARED_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    string METHOD = "POST";
    string CONTENT_TYPE = "application/json";
    string RESOURCE = "/api/logs";
    string uri = "https://" + CUSTOMER_ID + ".ods.opinsights.azure.com/api/logs?api-version=2016-04-01";
    string uri2 = "https://postman-echo.com/post";
    
    string sign(string key, string plain)
    {
        string mac, encoded;
        try
        {
    
            HMAC< SHA256 > hmac((byte*)key.c_str(), key.length());
    
            StringSource(plain, true,
                         new HashFilter(hmac,
                                        new StringSink(mac)
                         ) // HashFilter
            ); // StringSource
        }
        catch(const CryptoPP::Exception& e)
        {
            cerr << e.what() << endl;
        }
    
        encoded.clear();
        StringSource(mac, true,
                     new Base64Encoder(
                             new StringSink(encoded)
                     ) // Base64Encoder
        ); // StringSource
    
        return encoded;
    }
    
    string getTimestamp()
    {
        char buf[1000];
        time_t now = time(0);
        //struct tm tm = *localtime(&now);
        struct tm *tm = gmtime(&now);
        strftime(buf, sizeof buf, "%a, %d %b %Y %H:%M:%S GMT", tm);
        cout << buf << endl;
        return buf;
    
    }
    
    string getSignature(const string& customer_id, const string& shared_key, const string& date, size_t content_length,
                        const string& method, const string& content_type, const string& resource)
    {
        string x_headers = "x-ms-date:" + date;
        string string_to_hash = (method + "\n" + std::to_string(content_length) + "\n" + content_type + "\n" + x_headers + "\n" + resource);
        string decoded_share_key;
        decoded_share_key.clear();
        StringSource(shared_key,true, new Base64Decoder( new StringSink(decoded_share_key)));
        string encoded_hash = sign(decoded_share_key,string_to_hash);
    
        string signature = "SharedKey "+ customer_id + ":" +encoded_hash;
                //SharedKey {customer_id}:{encoded_hash}
    
        cout << signature << endl;
    
        return signature;
    }
    
    
    void post(string customer_id, string shared_key, string body, string log_type)
    {
        string date = getTimestamp();
    
        string signature = getSignature(CUSTOMER_ID, SHARED_KEY, date,
                                        body.length(), METHOD,
                                        CONTENT_TYPE, RESOURCE);
    
        auto response = cpr::Post(cpr::Url(uri),
                                    cpr::Header{{"content-type",CONTENT_TYPE},
                                                {"Authorization",signature},
                                                {"log-type",log_type},
                                                {"x-ms-date", date},
                                                {"content-length",std::to_string(body.length())}},
                                    cpr::Body(body));
    
    
    
        cout << response.url << endl;
        try {
            json j = json::parse(response.text);
            cout << j.dump(4) << endl;
        }
        catch (std::exception& e) {
            cout << e.what() << endl << endl;
            cout << response.text << endl;
        }
        cout << response.status_code << endl;
        if(response.status_code!=200)
        {
           cout << response.error.message << endl;
        }
        cout << response.elapsed << endl;
    }
    
    
    int main() {
        
        string log_type = "LoggingTest";
    
        json log_msg;
        json msg;
        log_msg["property1"] = "value1";
    
        msg = {log_msg};
    
        post(CUSTOMER_ID, SHARED_KEY, msg.dump(), log_type);
    
    
        return 0;
    }
    

    However, I'm always getting the same error like this (from response.text) :

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
    <HTML><HEAD><TITLE>Length Required</TITLE>
    <META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
    <BODY><h2>Length Required</h2>
    <hr><p>HTTP Error 411. The request must be chunked or have a content length.</p>
    </BODY></HTML>
    

    Things I have tried and the results:

    1. Added "content-length" header: Same error
    2. Tried sending empty body with content length zero: Same error
    3. Made POST request to Postman-echo service to see if the library is unable to forward all data: Results as follows -

    3.1 Sending JSON data with authorization header:

    {
        "args": {},
        "data": {},
        "files": {},
        "form": {},
        "headers": {
            "accept": "*/*",
            "authorization": "SharedKey xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "host": "postman-echo.com",
            "user-agent": "curl/7.47.0",
            "x-amzn-trace-id": "Root=1-5ebe2da5-2275dd11f1b39c54c33fa6df",
            "x-forwarded-port": "443",
            "x-forwarded-proto": "https"
        },
        "json": null,
        "url": "https://postman-echo.com/post"
    }
    

    Notice that even though I'm sending JSON data with the POST request, Postman-echo does not show it. This is strange because when I did the same thing using a Python script, the result showed me both the data as well as the authorization signature.

    3.2 Sending JSON data without authorization header:

    {
         "args": {},
        "data": [
            {
                "property1": "value1"
            }
        ],
        "files": {},
        "form": {},
        "headers": {
            "accept": "*/*",
            "content-length": "24",
            "content-type": "application/json",
            "host": "postman-echo.com",
            "log-type": "LoggingTest",
            "user-agent": "curl/7.47.0",
            "x-amzn-trace-id": "Root=1-5ebe2f54-bfcef7b08ee37ca8efe47d90",
            "x-forwarded-port": "443",
            "x-forwarded-proto": "https",
            "x-ms-date": "Fri, 15 May 2020 05:57:40 GMT"
        },
        "json": [
            {
                "property1": "value1"
            }
        ],
        "url": "https://postman-echo.com/post"
    }
    

    Then Postman-echo is showing me the json data sent.

    In my understanding, generated key is not wrong, since in that case, authorization failure is the first error. The same code above, written in Python3 and Python2 worked correctly. This was the link I was following: https://docs.microsoft.com/de-de/azure/azure-monitor/platform/data-collector-api

    Is there any known issue of similar kind in the cpr library? Please help.

    Bug :bug: curl :globe_with_meridians: 
    opened by prat33kg 14
  • PKCS#12 files for client authentication

    PKCS#12 files for client authentication

    Is your feature request related to a problem?

    curl built with SecureTransport

    https://github.com/curl/curl/blob/master/lib/vtls/sectransp.c#L1896 SSL: The Security framework only supports loading identities that are in PKCS#12 format.

    Possible Solution

    https://github.com/libcpr/cpr/blob/master/cpr/session.cpp#L495 If cert_type is p12 add CURLOPT_KEYPASSWD

    Alternatives

    No response

    Additional Context

    No response

    Feature :sparkles: Needs Investigation :mag: 
    opened by ioxuy 1
  • Load client cert from a buffer

    Load client cert from a buffer

    Is your feature request related to a problem?

    I have not found possibility to specify client SSL certificate from a buffer. Is there really no way of doing that?

    Possible Solution

    Add this possibility as for CaBuffer

    Alternatives

    No response

    Additional Context

    No response

    Feature :sparkles: Needs Investigation :mag: 
    opened by Chrys4lisfag 1
  • File Upload to S3 via Presigned URL

    File Upload to S3 via Presigned URL

    I am trying to write a function to upload a file to Amazon S3 using a presigned URL. I have written two implementations to do so, one using CPR and one using libcurl. The libcurl one is based on this file_upload.c example from curl's documentation.

    CPR:

    bool uploadToPresignedURL(std::string url, std::filesystem::path filePath) 
    {
    
        auto r = cpr::Put(cpr::Url{url.c_str()},
                          cpr::Multipart{{"file", cpr::File{filePath.c_str()}}});
        printf("Status code: %lu\n", r.status_code);
    
        return r.status_code == 200;
    
    }
    

    libcurl:

    bool uploadToPresignedURL_libcurl(std::string url, std::filesystem::path filePath) 
    {
    
        CURL *curl;
        CURLcode res;
        struct stat file_info;
        curl_off_t speed_upload, total_time;
        FILE *fd;
        bool uploaded = false;
    
        fd = fopen(filePath.c_str(), "rb"); /* open file to upload */
        if (!fd)
            return uploaded; /* cannot continue */
    
        /* to get the file size */
        if (fstat(fileno(fd), &file_info) != 0)
            return uploaded; /* cannot continue */
    
        curl = curl_easy_init();
        if (curl)
        {
            /* upload to this place */
            curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    
            /* tell it to "upload" to the URL */
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            /* set where to read from (on Windows you need to use READFUNCTION too) */
            curl_easy_setopt(curl, CURLOPT_READDATA, fd);
    
            /* and give the size of the upload (optional) */
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
    
            /* enable verbose for easier tracing */
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    
            res = curl_easy_perform(curl);
            /* Check for errors */
            if (res != CURLE_OK)
            {
                fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
            }
            else
            {
                uploaded = true;
                /* now extract transfer info */
                curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD_T, &speed_upload);
                curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &total_time);
    
                fprintf(
                    stderr,
                    "Speed: %lu bytes/sec during %lu.%06lu seconds\n",
                    (unsigned long)speed_upload,
                    (unsigned long)(total_time / 1000000),
                    (unsigned long)(total_time % 1000000));
            }
            /* always cleanup */
            curl_easy_cleanup(curl);
        }
        fclose(fd);
    
        return uploaded;
    
    }
    

    The libcurl implementation uploads the file properly with a 200. However, with the CPR implementation I am consistently getting a 403. The AWS keys are encoded in the URL in the Presigned URL. Is there something special I need to do to get the Url constructor to deal with them properly? When using the curl CLI, I need to surround the URL with 's or it also 403s.

    Bug :bug: Needs Investigation :mag: 
    opened by pwolfe1 10
  • MultiperformTenSessionsGetTest Test Case Fails on macOS Nondeterministic

    MultiperformTenSessionsGetTest Test Case Fails on macOS Nondeterministic

    Description

    On macOS systems the MultiperformTenSessionsGetTest test case fails nondeterministic. In case it fails, it gets an error indicating that the connection establishment failed inside curl.

    This issue still exists, even in case we update to curl 7.85.0.

    Example/How to Reproduce

    Execute the MultiperformTenSessionsGetTest test case on macOS. For this one first has to enable it again in the source code since I disabled it in #863 for macOS for now.

    TEST(MultiperformGetTests, MultiperformTenSessionsGetTest) {
        const size_t sessionCount = 10;
    
        MultiPerform multiperform;
        Url url{server->GetBaseUrl() + "/hello.html"};
        for (size_t i = 0; i < sessionCount; ++i) {
            std::shared_ptr<Session> session = std::make_shared<Session>();
            session->SetUrl(url);
            multiperform.AddSession(session);
        }
    
        std::vector<Response> responses = multiperform.Get();
    
        EXPECT_EQ(responses.size(), sessionCount);
        for (Response& response : responses) {
            EXPECT_EQ(std::string{"Hello world!"}, response.text);
            EXPECT_EQ(url, response.url);
            EXPECT_EQ(std::string{"text/html"}, response.header["content-type"]);
            EXPECT_EQ(200, response.status_code);
            EXPECT_EQ(ErrorCode::OK, response.error.code);
        }
    }
    

    Possible Fix

    Unknown.

    Where did you get it from?

    GitHub (branch e.g. master)

    Additional Context/Your Environment

    • OS: macOS 12
    • Version: 1.9.x
    Bug :bug: curl :globe_with_meridians: CI :bricks: Needs Investigation :mag: 
    opened by COM8 0
  • Feature Request: Add method to easily add parameters to what's already in the session

    Feature Request: Add method to easily add parameters to what's already in the session

    Is your feature request related to a problem? Please describe. I'm currently implementing a client to communicate with the Binance api. Authentication on Binance involves doing an hmac sha256 hash on the query string and request body and then adding the hash to the query string. I determined that using an Interceptor is the best way to go about this, and here is my intercept function:

      cpr::Response BinanceClient::AuthInterceptor::intercept(cpr::Session& session)
      {
        spdlog::trace("AuthInterceptor");
        auto url = session.GetFullRequestUrl();
        std::string queryStr;
        auto found = url.find('?');
        if (found != std::string::npos)
        {
          queryStr = url.substr(found + 1) + "&";
          url = url.substr(0, found);
        }
        queryStr += "timestamp=" + std::to_string(getTimestamp_ms());
        auto hmac(utils::hmacSha256(queryStr, m_secretKey));
        session.SetParameters({});
        session.SetUrl(cpr::Url{url + "?" + queryStr + "&signature=" + hmac});
        session.SetHeader(cpr::Header{{"X-MBX-APIKEY", m_apiKey}});
    
        return proceed(session);
      }
    

    As you can see, I have to add the signature and the timestamp in a kinda janky way. Instead of adding the parameter, I instead clear the parameters and I add the signature onto the end of the Url. It works... it's just janky.

    Describe the solution you'd like It would be wonderful if there was an AddParameters() method so that instead of clearing the parameters and modifying the Url I could just do session.AddParameters({{"signature", hmac}});. Note: The parameter(s) would need to be added in a way that they are guaranteed to be in the query string in the order in which they're given, so just adding the one parameter would result in it beingat the end of the resultant query string.

    Describe alternatives you've considered We could be given access the the Parameters member ourselves, and then cpr::Parameters could be given a method to allow us to add parameters to it.

    Additional context Nope.

    Feature :sparkles: 
    opened by Triasmus 1
Releases(1.9.3)
  • 1.9.3(Nov 24, 2022)

    In this release we fixed a CMake crash caused by us adding custom build types for sanitizer builds. They now got replaced by CMake flags.

    • CPR_DEBUG_SANITIZER_FLAG_THREAD
    • CPR_DEBUG_SANITIZER_FLAG_ADDR
    • CPR_DEBUG_SANITIZER_FLAG_LEAK
    • CPR_DEBUG_SANITIZER_FLAG_UB
    • CPR_DEBUG_SANITIZER_FLAG_ALL

    What's Changed

    • Replaced build types with flags by @rumgot in https://github.com/libcpr/cpr/pull/853

    Full Changelog: https://github.com/libcpr/cpr/compare/1.9.2...1.9.3

    Source code(tar.gz)
    Source code(zip)
  • 1.9.2(Sep 3, 2022)

    What's Changed

    • Fixed thread pool not creating enough new threads by @COM8 in https://github.com/libcpr/cpr/pull/802
    • Add std::map based constructors to Proxies and ProxyAuthentication by @kp-cat in https://github.com/libcpr/cpr/pull/814

    Full Changelog: https://github.com/libcpr/cpr/compare/1.9.1...1.9.2

    Source code(tar.gz)
    Source code(zip)
  • 1.9.1(Jul 31, 2022)

  • 1.9.0(Jul 18, 2022)

    This will be the last release where the minimum required C++ standard is cpp11. With the next major release (1.10.0) in ~late 2022/early 2023 we will increase the minimum C++ standard to cpp17 (Issue). This release (1.9.0) will still receive bug fixes, at least until the end of 2023, but all new features require from now on a cpp17 compatible compiler.

    Thanks to everyone who helped making this next release of cpr possible 🎉! Especially I would like to thank @simon-berger, @saendigPhilip @leviliangtw .

    In case everything goes like planed we will even offer a .deb package and a NuGet package soon. So stay tuned!

    What's Changed

    • Improve usability for ResponseStringReserve by @WorkingRobot in https://github.com/libcpr/cpr/pull/726
    • Make sure mutex is properly initialized by @cordbleibaum in https://github.com/libcpr/cpr/pull/728
    • Only use CURLOPT_SSLKEY_BLOB on curl 7.71.0+ by @alebcay in https://github.com/libcpr/cpr/pull/737
    • Unified basic, digest and ntlm authentication into one authenticaton class by @simon-berger in https://github.com/libcpr/cpr/pull/735
    • Use UpdateHeader to allow header updates from different sources by @simon-berger in https://github.com/libcpr/cpr/pull/738
    • Added function to get the full request URL by @simon-berger in https://github.com/libcpr/cpr/pull/741
    • Improved range requests and added support for multiple ranges by @simon-berger in https://github.com/libcpr/cpr/pull/742
    • Use thread pool to instead of std::async (#633) by @ithewei in https://github.com/libcpr/cpr/pull/734
    • Add Interceptors by @simon-berger in https://github.com/libcpr/cpr/pull/744
    • Support for CURLOPT_LOCALPORT and CURLOPT_LOCALPORTRANGE by @jmhersc in https://github.com/libcpr/cpr/pull/748
    • Add CaBuffer to enable loading of CA certificates from buffers by @simon-berger in https://github.com/libcpr/cpr/pull/750
    • Add method SetAcceptEncoding for customized Accept-Encoding header (#683) by @leviliangtw in https://github.com/libcpr/cpr/pull/746
    • Add support of customized filename for Multipart (#642) by @leviliangtw in https://github.com/libcpr/cpr/pull/755
    • Added CI script for automatically building a debian package by @saendigPhilip in https://github.com/libcpr/cpr/pull/760
    • Add unit tests for file uploading using buffer of rvalue/lvalue reference (#216) by @leviliangtw in https://github.com/libcpr/cpr/pull/764
    • Add async methods to the Session object interface by @simon-berger in https://github.com/libcpr/cpr/pull/756
    • Add support of file and buffer for the POST Body (#581) by @leviliangtw in https://github.com/libcpr/cpr/pull/763
    • Securely remove sensitive data from memory by @Garfield96 in https://github.com/libcpr/cpr/pull/776
    • secureStringClear Fix for Empty Strings by @COM8 in https://github.com/libcpr/cpr/pull/779
    • New certificates for HTTPS tests by @saendigPhilip in https://github.com/libcpr/cpr/pull/773
    • MacOS and Windows OpenSSL CI fixes by @COM8 in https://github.com/libcpr/cpr/pull/783
    • Refactor cpr::Cookies for storing more fields (#777) by @leviliangtw in https://github.com/libcpr/cpr/pull/778
    • Fix certificate information extraction from the response (#769) by @leviliangtw in https://github.com/libcpr/cpr/pull/781
    • Workaround for PUT requests with a read callback by @COM8 in https://github.com/libcpr/cpr/pull/787

    New Contributors

    • @WorkingRobot made their first contribution in https://github.com/libcpr/cpr/pull/726
    • @cordbleibaum made their first contribution in https://github.com/libcpr/cpr/pull/728
    • @alebcay made their first contribution in https://github.com/libcpr/cpr/pull/737
    • @simon-berger made their first contribution in https://github.com/libcpr/cpr/pull/735
    • @ithewei made their first contribution in https://github.com/libcpr/cpr/pull/734
    • @jmhersc made their first contribution in https://github.com/libcpr/cpr/pull/748
    • @leviliangtw made their first contribution in https://github.com/libcpr/cpr/pull/746
    • @saendigPhilip made their first contribution in https://github.com/libcpr/cpr/pull/760

    Full Changelog: https://github.com/libcpr/cpr/compare/1.8.4...1.9.0

    Source code(tar.gz)
    Source code(zip)
  • 1.8.4(Jul 6, 2022)

    This release addresses a security concern, where an attacker could extract sensitive information from cpr after the application had been exited.

    Changes:

    • Explicit removal of sensitive data from memory (@Garfield96)

    Full Changelog: https://github.com/libcpr/cpr/compare/1.8.3...1.8.4

    Source code(tar.gz)
    Source code(zip)
  • 1.8.3(May 5, 2022)

    This release disables setting SSL-Key blobs for older versions of curl below 7.71.0, since it was not available previously to that. More information on that can be found here: https://github.com/libcpr/cpr/issues/732

    Full Changelog: https://github.com/libcpr/cpr/compare/1.8.2...1.8.3

    Source code(tar.gz)
    Source code(zip)
  • 1.8.2(Apr 27, 2022)

    What's Changed

    • Downgraded curl to 1.80.0 to fix #709 and #732 by @COM8 in https://github.com/libcpr/cpr/pull/733

    Full Changelog: https://github.com/libcpr/cpr/compare/1.8.1...1.8.2

    Source code(tar.gz)
    Source code(zip)
  • 1.8.1(Mar 25, 2022)

  • 1.8.0(Mar 25, 2022)

    Changes

    • Added DownloadAsync(...) #696
    • Added basic range support via SetRange(...) #701
    • Added support for setting the private key blob directly #699
    • Added Mbed TLS support #714
    • Added an option to reserve space before downloading the response string #712
    • Updated the build in curl to 7.81.0
    • Fixed CA-Path for Android #707
    • Fix overwriting of ca bundle #717
    • Fix build with OpenSSL on Ubuntu bionic #696
    • Fixed installing DLLs to binary directory
    Source code(tar.gz)
    Source code(zip)
  • 1.7.2(Dec 9, 2021)

  • 1.7.1(Dec 9, 2021)

    Small bug fix release.

    Changes

    • Fixed setting headers when calling cpr::Session::Download(...).

    Now something like this should work:

    cpr::Url url{server->GetBaseUrl() + "/download_gzip.html"};
    cpr::Session session;
    session.SetUrl(url);
    session.SetHeader(cpr::Header{{"Accept-Encoding", "gzip"}}); // Works now
    cpr::Response response = session.Download(cpr::WriteCallback{write_data, 0});
    
    Source code(tar.gz)
    Source code(zip)
  • 1.7.0(Nov 24, 2021)

    • Added a Cppcheck CI run
    • Fixed automated libcurl ca path detection
    • Fixed missing raw_header in cpr::Response
    • Fixed bugprone narrowing conversions
    • Fixed MaxRedirects exceeded should be treated as error
    • Updated libcurl from 7.75.0 to 7.79.1
    • Fixed cprConfig.cmake when building cpr as a submodule
    • Added cpr version macros in cprver.h
    • Fixed CMake paths for subprojects
    • Updated zlib-ng from 2.0.0-RC2 to 2.0.5
    • Fixed usage of CPR_USE_SYSTEM_GTEST
    • Added CMake find-package support
    • Added more redirect options:
      • cont_send_cred: Continue to send authentication (user+password) credentials when following locations, even when hostname changed.
    • Added an option to specify the HTML version with SetHttpVersion(...)
    • Fixed respecting system proxy configuration
    • Added an option to select the outgoing interface with SetInterface(...)
    • Added an option to get the file download length GetDownloadFileLength(...)
    • Updated Google Tests from 1.10.0 to 1.11.0
    • Added proxy authentication
    • Don't forcibly override user setting for FETCHCONTENT_QUIET
    Source code(tar.gz)
    Source code(zip)
  • 1.6.2(Apr 27, 2021)

  • 1.6.1(Apr 27, 2021)

    Minor feature and bugfix release with the following changes:

    • Added MacOS darwin-ssl support #549
    • Added an option to split a request preparation from its execution #533
    • cpr::Session is now movable #544
    • Not overriding BUILD_TESTING as cache variable any more #561
    • Avoid recursive template instantiation in priv::set_option() #540
    • Do not move targets in to a bin if cpr is a sub project #531
    Source code(tar.gz)
    Source code(zip)
  • 1.6.0(Mar 19, 2021)

    In this release the CMake integration has been refactored to fix a bunch of SSL issues. During this change all relevant CMake variable names changed. Here are the new ones:

    -- =======================================================
    --   CPR_GENERATE_COVERAGE: OFF
    --   CPR_CURL_NOSIGNAL: OFF
    --   CPR_USE_SYSTEM_GTEST: OFF
    --   CPR_FORCE_USE_SYSTEM_CURL: OFF
    --   CPR_ENABLE_SSL: ON
    --   CPR_FORCE_OPENSSL_BACKEND: OFF
    --   CPR_FORCE_WINSSL_BACKEND: OFF
    --   CPR_BUILD_TESTS: ON
    --   CPR_BUILD_TESTS_SSL: ON
    -- =======================================================
    

    Documentation for those can be found here: https://github.com/whoshuu/cpr/blob/aac5058a15e9ad5ad393973dc6fe44d7614a7f55/CMakeLists.txt#L30-L40

    If neither CPR_FORCE_OPENSSL_BACKEND nore CPR_FORCE_WINSSL_BACKEND has been set to ON, CMake will try to automatically detect the best SSL backend for your system (WinSSL - Windows, OpenSSL - Linux & Mac, ...).

    How to build on Windows

    With WinSSL

    mkdir build
    cd build
    cmake .. -DCPR_BUILD_TESTS_SSL=OFF # SSL test are only supported with OpenSSL
    cmake --build .
    

    With OpenSSL

    mkdir build
    cd build
    cmake .. -DCPR_FORCE_OPENSSL_BACKEND=ON # Disable auto detect and force OpenSSL
    cmake --build .
    

    Changes

    • Added support for GCC10 static analysis
    • Added an option to retrieve the std::shared_ptr<CurlHolder> from a session
    • Added UpdateHeader(const Header& header) support #506
    • Added support for retrieving certificate information #453
    • Added urlDecode(std::string) for url decoding
    • Add BearerToken support #465
    • Explicit move operator for StringHolder
    • cpr::Session cleanup and allow the compiler to generate the needed constructor
    • Updated curl from 7.69.1 to 7.75.0 #529
    • Compatibility for libcurl <= 7.60
    • Less auto and more explicit types
    • Refactored the CMake variables #529
    • Change listening ports used for tests
    • Fixed AbstractServer data race
    • Fixed Windows OpenSSL builds #529
    • Fixed Windows SSL backend detection #529
    • Fixed ReadCallback will reset Header #517
    • Fixed the Windows OpenSSL CI build
    Source code(tar.gz)
    Source code(zip)
  • 1.5.2(Oct 20, 2020)

    This hotfix for v1.5.1 includes the following fixes:

    • Fixed: cpr::Post wrong content length (#450, #456, #458)
    • Fixed: Mutex for multithreaded access not being static
    • Fixed: No const rvalue references (#424)
    Source code(tar.gz)
    Source code(zip)
  • v1.5.1(Jul 8, 2020)

    Changes

    • CMake add ability to use WINSSL (#404)
    • Thread save access to libCurl (#313)
    • Allow implicit creation of cpr:Url, cpr:Body and cpr:UserAgent (#411)
    • Payload with string variables (#409)
    • Cleanup (#407, #408)
    Source code(tar.gz)
    Source code(zip)
  • 1.5.0(Jun 22, 2020)

    Changes

    • Updated CURL to curl-7_69_1 (#343)
    • Updated mongoose to 6.18
    • Updated googletest to release-1.10.0
    • Refactored the mongoose test server setup
    • Added SSL options (#276)
    • Fixed URL encoding (#379)
    • Fixed Windows std::min type deduction
    • GitHub Actions CI (#393)
    • Refactored all the CMake stuff (#383)
    • Fixed passing correct data type when setting CURLOPT_POSTFIELDSIZE_LARGE
    • Switched Body, UserAgent and Url from std::string derivation classes to string holder classes (#303)
    • General cleanup of the code base
    Source code(tar.gz)
    Source code(zip)
An object oriented C++ wrapper for CURL (libcurl)

curlcpp An object-oriented C++ wrapper for cURL tool If you want to know a bit more about cURL and libcurl, you should go on the official website http

Giuseppe Persico 543 Nov 23, 2022
Free software for cancelling people and organizations

cancel Free and open source cancelling! Use this to cancel anything, like freedom of speech, or even creators of the free software movement! You can s

null 59 Aug 1, 2022
A C library for asynchronous DNS requests

c-ares This is c-ares, an asynchronous resolver library. It is intended for applications which need to perform DNS queries without blocking, or need t

c-ares 1.5k Nov 29, 2022
C++ client for making HTTP/REST requests

REST client for C++ About This is a simple REST client for C++. It wraps libcurl for HTTP requests. Usage restclient-cpp provides two ways of interact

Daniel Schauenberg 1.4k Dec 1, 2022
Application that sends custom requests to League of Legends LCU api

More screenshots For fun project made in the span of 2 nights back in February 2021, which I'm now updating Technologies used No external libraries, o

null 168 Nov 29, 2022
requests-like networking library using boost for C++

cq == C++ Requests cq == C++ Requests is a "Python Requests"-like C++ header-only library for sending HTTP requests. The library is inspired a lot by

null 11 Dec 15, 2021
Filter Garry'sMod built-in HTTP requests with a lua hook

Filter Garry'sMod built-in HTTP requests with a lua hook

Earu 3 Jul 28, 2022
traces tcp requests in kernel. allow to set up IPs to filter dynamically using bpf-map.

ttcp cilium/ebpf/examples/tcprtt에다가 BPF_MAP_TYPE_HASH를 추가해서 srcAddr을 필터링하도록 수정함. 어플리케이션에는 Http API를 추가해서 필터링할 IP를 추가, 삭제, 조회할 수 있도록 함. Getting Startd

null 8 May 20, 2022
Sonic the Hedgehog (1991, Sega Genesis / MegaDrive) C Port

SoniCPort Sonic the Hedgehog (1991, Sega Genesis / MegaDrive) C Port Dependencies SDL2 (if COMPILE_SDL2 is set to ON) pkg-config (for builds that requ

CuckyDev 103 Nov 18, 2022
Doom classic port to lightweight RISC‑V

Doom classic port to lightweight RISC-V This is a port to try and make adapting/running doom to simple RISC-V platform easier with the code to adapt w

Sylvain 55 Nov 11, 2022
Dynamic patch `wslhost.exe` to listen port on any interface.

WSLHostPatcher Dynamic patch wslhost.exe to listen port on any interfaces. How it work The localhost port actually forward by wslhost.exe on Windows,

CzBiX 391 Nov 23, 2022
TCP Port Redirection Utility

Overview PortBender is a TCP port redirection utility that allows a red team operator to redirect inbound traffic destined for one TCP port (e.g., 445

Praetorian 459 Nov 21, 2022
Chocolate Doom WebAssembly port with WebSockets support

Wasm Doom This is a Chocolate Doom WebAssembly port with WebSockets support. Requirements You need to install Emscripten and a few other tools first:

Cloudflare 185 Nov 29, 2022
TCP port scanner, spews SYN packets asynchronously, scanning entire Internet in under 5 minutes.

TCP port scanner, spews SYN packets asynchronously, scanning entire Internet in under 5 minutes.

Robert David Graham 20.2k Dec 1, 2022
Encapsulates the two protocols of OpenVpn and Ikev2, you only need to enter the server IP and port number to realize the connection and status display, and the specific situation of the connection can be displayed at the same time。

NewVpnCore 封装了OpenVpn和Ikev2两种协议,只需要输入服务器IP和端口号即可实现连接和状态显示,同时可以显示连接的具体情况。 UniteVpn Core(第一版) 1. 模块说明 unitevpn:封装了vpn的操作和统一不同协议信息的模块 ikev2:IKEV2协议的源码 op

ZFashion 3 Jun 8, 2022
ScummVM (UWP Port) with improvements for stability

ScummVM UWP port with few improvements for stability Source | Original Project Features Resolve crash issue when (folder removed or moved) Add loading

Bashar Astifan 4 Jul 21, 2022
Multi-protocol Port Mapping client library

libplum - Multi-protocol Port Mapping client library libplum (Port Lightweight and Universal Mapping) is a library allowing to forward ports on Networ

Paul-Louis Ageneau 16 Oct 21, 2022
📡 TCP/UDP port redirector

rinetd, by Thomas Boutell and Sam Hocevar. Released under the terms of the GNU General Public License, version 2 or later. This program is used to eff

Sam Hocevar 494 Nov 27, 2022
TCP port scanner, spews SYN packets asynchronously, scanning entire Internet in under 5 minutes.

MASSCAN-NG: Mass IP port scanner This is an Internet-scale port scanner. It can scan the entire Internet in under 5 minutes, transmitting 10 million p

BI.ZONE 61 Dec 1, 2022