|
| 1 | +#include <chimbuko/util/curlJsonSender.hpp> |
| 2 | +#include <chimbuko/util/error.hpp> |
| 3 | +#include <chimbuko/util/string.hpp> |
| 4 | + |
| 5 | +namespace chimbuko{ |
| 6 | + |
| 7 | + struct curlGlobal{ |
| 8 | + curlGlobal(){ curl_global_init(CURL_GLOBAL_ALL); } |
| 9 | + ~curlGlobal(){ curl_global_cleanup(); } |
| 10 | + }; |
| 11 | + |
| 12 | + //Initialize the curl global setup and ensure it is cleaned up at application end |
| 13 | + //Subsequent calls do nothing |
| 14 | + //Not thread safe |
| 15 | + static void curlGlobalInit(){ |
| 16 | + static curlGlobal c; |
| 17 | + } |
| 18 | + |
| 19 | + |
| 20 | + curlJsonSender::curlJsonSender(const std::string &url): curl(nullptr), headers(nullptr){ |
| 21 | + curlGlobalInit(); |
| 22 | + |
| 23 | + curl = curl_easy_init(); |
| 24 | + if (curl == nullptr) fatal_error("Failed to initialize curl easy handler"); |
| 25 | + |
| 26 | + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); |
| 27 | + // Dont bother trying IPv6, which would increase DNS resolution time |
| 28 | + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); |
| 29 | + // Don't wait forever, time out after 10 seconds |
| 30 | + //curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); |
| 31 | + // Follow HTTP redirects if necessary |
| 32 | + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); |
| 33 | + // header |
| 34 | + headers = curl_slist_append(headers, "Content-Type: application/json"); |
| 35 | + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); |
| 36 | + } |
| 37 | + |
| 38 | + |
| 39 | + struct curl_fetch_str { |
| 40 | + std::string m_payload; |
| 41 | + bool m_do_fetch; |
| 42 | + curl_fetch_str(bool do_fetch) : m_do_fetch(do_fetch) |
| 43 | + { |
| 44 | + |
| 45 | + } |
| 46 | + }; |
| 47 | + |
| 48 | + static size_t _curl_writefunc(char *ptr, size_t size, size_t nmemb, void* userp) |
| 49 | + { |
| 50 | + // std::cout << "curl_writefunc: " << std::string(ptr) << std::endl; |
| 51 | + struct curl_fetch_str *p = (struct curl_fetch_str *) userp; |
| 52 | + |
| 53 | + if (ptr && p->m_do_fetch) { |
| 54 | + p->m_payload = std::string(ptr); |
| 55 | + } |
| 56 | + |
| 57 | + return size * nmemb; |
| 58 | + } |
| 59 | + |
| 60 | + |
| 61 | + void curlJsonSender::send(const std::string &json_str, std::string *response) const{ |
| 62 | + bool do_fetch = response != nullptr; |
| 63 | + |
| 64 | + curl_fetch_str fetch(do_fetch); //request callback if |
| 65 | + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_str.c_str()); |
| 66 | + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, json_str.size()); |
| 67 | + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); |
| 68 | + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &_curl_writefunc); |
| 69 | + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&fetch); |
| 70 | + |
| 71 | + CURLcode res = curl_easy_perform(curl); |
| 72 | + if (res != CURLE_OK) fatal_error(stringize("curl_easy_perform() failed: %s", curl_easy_strerror(res))); |
| 73 | + |
| 74 | + long httpCode(0); |
| 75 | + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); |
| 76 | + |
| 77 | + if(do_fetch) *response = std::move(fetch.m_payload); |
| 78 | + } |
| 79 | + |
| 80 | + curlJsonSender::~curlJsonSender(){ |
| 81 | + if (headers) curl_slist_free_all(headers); |
| 82 | + curl_easy_cleanup(curl); |
| 83 | + } |
| 84 | + |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | + |
| 89 | + |
| 90 | + |
| 91 | +} |
0 commit comments