Search code examples
c++httpreddit

How to log into Reddit API with cpp-httplib?


Logging into Reddit and authenticating with python works fine:

import requests
base_url = 'https://www.reddit.com/'
data = {'grant_type': 'password', 'username': 'glibg10b', 'password': '<login_password>'}

auth = requests.auth.HTTPBasicAuth('<app_key>', '<secret_key>')
res = requests.post(base_url + 'api/v1/access_token', data=data, headers={'user-agent': 'api-test by glibg10b'}, auth=auth)

print(res.status_code) # Prints 200

But doing the same in C++ with cpp-httplib doesn't work:

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "httplib.h"

int main()
{
    httplib::Client bot{ "https://www.reddit.com/" };
    bot.set_basic_auth("<app_key>", "<secret_key>");

    httplib::Headers headers{
        { "user-agent", "api-test by glibg10b" }
    };

    httplib::MultipartFormDataItems items{
        { "grant_type", "password", "", "" },
        { "username",   "glibg10b", "", "" },
        { "password",   "<login_password>", "", "" }
    };

    auto res{ bot.Post("/api/v1/access_token", headers, items) };
    if (res)
        std::cout << res->status << '\n';
    else
        std::cout << to_string(res.error()) << '\n'; // "Connection"
}

Am I missing something?

Edit: Full backtrace when error changes from Error::Success to Error::Connection:

#0  httplib::detail::create_client_socket(char const*, char const*, int, int, bool, std::function<void (int)>, long, long, long, long, long, long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, httplib::Error&) (
    host=0x55555564d4a0 "https://www.reddit.com/", ip=0x7fffffffd600 "", port=80, address_family=0, tcp_nodelay=false, socket_options=..., connection_timeout_sec=300, connection_timeout_usec=0, read_timeout_sec=5, read_timeout_usec=0, 
    write_timeout_sec=5, write_timeout_usec=0, intf="br0", error=@0x7fffffffd8c4: httplib::Error::Success) at /home/waldo/sources/reddit-api-test/httplib.h:2744
        sock = -1
#1  0x0000555555571b74 in httplib::ClientImpl::create_client_socket (this=0x55555564db80, error=@0x7fffffffd8c4: httplib::Error::Success) at /home/waldo/sources/reddit-api-test/httplib.h:5821
        ip = ""
        it = 
  {first = "", second = "\000\000\000\000UU\000\000\000\000\000\000\000\000\000\000\200\334dUUU\000\000\200\334dUUU\000\000\000\000\000\000\000\000\000\000\270\334dUUU", '\000' <repeats 11 times>, "\332\377\377\377\177\000\000\n\000\000\000\377\177(\000\330\334dUUU", '\000' <repeats 11 times>, "\003[UUU\000\000\300\332\377\377\022\000\000\000,\001", '\000' <repeats 14 times>, "\005", '\000' <repeats 15 times>, "\005", '\000' <repeats 15 times>, "\020\177dUUU\000\000\026\000\000\000\000\000\000\000\036\000\000\000\000\000\000\000\340\326\377\377\377\177\000\000@\214dUUU\000\000\036\000\000\000\000\000\000\000"...}
#2  0x0000555555571c27 in httplib::ClientImpl::create_and_connect_socket (this=0x55555564db80, socket=..., error=@0x7fffffffd8c4: httplib::Error::Success) at /home/waldo/sources/reddit-api-test/httplib.h:5830
        sock = 21845
#3  0x0000555555572473 in httplib::ClientImpl::send (this=0x55555564db80, req=..., res=..., error=@0x7fffffffd8c4: httplib::Error::Success) at /home/waldo/sources/reddit-api-test/httplib.h:5930
        guard = {_M_device = @0x55555564dbe0}
        is_alive = false
        request_mutex_guard = {_M_device = @0x55555564dc08}
        __PRETTY_FUNCTION__ = "bool httplib::ClientImpl::send(httplib::Request&, httplib::Response&, httplib::Error&)"
        close_connection = 62
        ret = false
#4  0x0000555555574e0b in httplib::ClientImpl::send_with_content_provider(httplib::Request&, char const*, unsigned long, std::function<bool (unsigned long, unsigned long, httplib::DataSink&)>, std::function<bool (unsigned long, httplib::DataSink&)>, char const*, httplib::Error&) (this=0x55555564db80, req=..., 
    body=0x55555564eef0 "----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\npassword\r\n----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"u"..., 
    content_length=385, content_provider=..., content_provider_without_length=..., content_type=0x55555564b170 "multipart/form-data; boundary=--cpp-httplib-multipart-data-icoEgIbPrIoB25S3", error=@0x7fffffffd8c4: httplib::Error::Success)
    at /home/waldo/sources/reddit-api-test/httplib.h:6342
        res = std::unique_ptr<httplib::Response> = {get() = 0x555555648c90}
#5  0x000055555557500a in httplib::ClientImpl::send_with_content_provider(char const*, char const*, std::multimap<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, httplib::detail::ci, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&, char const*, unsigned long, std::function<bool (unsigned long, unsigned long, httplib::DataSink&)>, std::function<bool (unsigned long, httplib::DataSink&)>, char const*) (this=0x55555564db80, method=0x5555555d9a48 "POST", 
    path=0x5555555da36f "/api/v1/access_token", headers=std::multimap with 1 element = {...}, 
    body=0x55555564eef0 "----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\npassword\r\n----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"u"..., 
    content_length=385, content_provider=..., content_provider_without_length=..., content_type=0x55555564b170 "multipart/form-data; boundary=--cpp-httplib-multipart-data-icoEgIbPrIoB25S3") at /home/waldo/sources/reddit-api-test/httplib.h:6361
        req = {method = "POST", path = "/api/v1/access_token", headers = std::multimap with 2 elements = {["Content-Type"] = "multipart/form-data; boundary=--cpp-httplib-multipart-data-icoEgIbPrIoB25S3", ["user-agent"] = "api-test by glibg10b"}, 
          body = "----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\npassword\r\n----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"u"..., remote_addr = "", 
          remote_port = -1, version = "", target = "", params = std::multimap with 0 elements, files = std::multimap with 0 elements, ranges = std::vector of length 0, capacity 0, 
          matches = {<std::vector<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >> = std::vector of length 0, capacity 0, _M_begin = non-dereferenceable iterator for std::vector}, 
          response_handler = {<std::_Maybe_unary_or_binary_function<bool, httplib::Response const&>> = {<std::unary_function<httplib::Response const&, bool>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, 
              static _M_max_align = 8, _M_functor = {_M_unused = {_M_object = 0x0, _M_const_object = 0x0, _M_function_pointer = 0x0, _M_member_pointer = NULL}, _M_pod_data = '\000' <repeats 15 times>}, _M_manager = 0x0}, _M_invoker = 0x0}, 
          content_receiver = {<std::_Maybe_unary_or_binary_function<bool, char const*, unsigned long, unsigned long, unsigned long>> = {<No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, _M_functor = {
                _M_unused = {_M_object = 0x0, _M_const_object = 0x0, _M_function_pointer = 0x0, _M_member_pointer = NULL}, _M_pod_data = '\000' <repeats 15 times>}, _M_manager = 0x0}, _M_invoker = 0x0}, 
          progress = {<std::_Maybe_unary_or_binary_function<bool, unsigned long, unsigned long>> = {<std::binary_function<unsigned long, unsigned long, bool>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, 
              static _M_max_align = 8, _M_functor = {_M_unused = {_M_object = 0x0, _M_const_object = 0x0, _M_function_pointer = 0x0, _M_member_pointer = NULL}, _M_pod_data = '\000' <repeats 15 times>}, _M_manager = 0x0}, _M_invoker = 0x0}, ssl = 0x0, 
          redirect_count_ = 20, content_length_ = 0, content_provider_ = {<std::_Maybe_unary_or_binary_function<bool, unsigned long, unsigned long, httplib::DataSink&>> = {<No data fields>}, <std::_Function_base> = {static _M_max_size = 16, 
              static _M_max_align = 8, _M_functor = {_M_unused = {_M_object = 0x0, _M_const_object = 0x0, _M_function_pointer = 0x0, _M_member_pointer = NULL}, _M_pod_data = '\000' <repeats 15 times>}, _M_manager = 0x0}, _M_invoker = 0x0}, 
          is_chunked_content_provider_ = false, authorization_count_ = 0}
        error = httplib::Error::Success
        res = std::unique_ptr<httplib::Response> = {get() = 0xc9c0073e}
#6  0x0000555555575ae3 in httplib::ClientImpl::Post (this=0x55555564db80, path=0x5555555da36f "/api/v1/access_token", headers=std::multimap with 1 element = {...}, 
    body="----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\npassword\r\n----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"u"..., 
    content_type=0x55555564b170 "multipart/form-data; boundary=--cpp-httplib-multipart-data-icoEgIbPrIoB25S3") at /home/waldo/sources/reddit-api-test/httplib.h:6622
No locals.
#7  0x0000555555576166 in httplib::ClientImpl::Post (this=0x55555564db80, path=0x5555555da36f "/api/v1/access_token", headers=std::multimap with 1 element = {...}, items=std::vector of length 3, capacity 3 = {...}, 
    boundary="--cpp-httplib-multipart-data-icoEgIbPrIoB25S3") at /home/waldo/sources/reddit-api-test/httplib.h:6702
        body = "----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\npassword\r\n----cpp-httplib-multipart-data-icoEgIbPrIoB25S3\r\nContent-Disposition: form-data; name=\"u"...
        content_type = "multipart/form-data; boundary=--cpp-httplib-multipart-data-icoEgIbPrIoB25S3"
#8  0x0000555555575ba4 in httplib::ClientImpl::Post (this=0x55555564db80, path=0x5555555da36f "/api/v1/access_token", headers=std::multimap with 1 element = {...}, items=std::vector of length 3, capacity 3 = {...})
    at /home/waldo/sources/reddit-api-test/httplib.h:6671
No locals.
#9  0x0000555555578d53 in httplib::Client::Post (this=0x7fffffffde30, path=0x5555555da36f "/api/v1/access_token", headers=std::multimap with 1 element = {...}, items=std::vector of length 3, capacity 3 = {...})
    at /home/waldo/sources/reddit-api-test/httplib.h:7945
No locals.
#10 0x000055555555f178 in main () at main.cpp:20
        bot = {cli_ = std::unique_ptr<httplib::ClientImpl> = {get() = 0x55555564db80}, is_ssl_ = false}
        headers = std::multimap with 1 element = {["user-agent"] = "api-test by glibg10b"}
        items = std::vector of length 3, capacity 3 = {{name = "grant_type", content = "password", filename = "", content_type = ""}, {name = "username", content = "glibg10b", filename = "", content_type = ""}, {name = "password", content = "<login_password>", 
            filename = "", content_type = ""}}
        res = {res_ = std::unique_ptr<httplib::Response> = {get() = 0x5b0000006e}, err_ = 4158279269, request_headers_ = std::multimap with 564 elements<error reading variable: Cannot access memory at address 0xffffffffffffffb0>}

Solution

  • After a whole day of searching for the answer, it turns out that I had to remove the trailing slash from "www.reddit.com/".