#include #include "handling.h" #include #include const char* ciniterror = "cannot initialise CURL"; static size_t write_callback(void* contents, size_t size, size_t nmemb, void *userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } class HTTPRequest { private: csnd::Csound* csound; CURL* curl; char* url; void curl_reset() { curl_easy_reset(curl); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); } public: CURLcode curlResult; char* curlError; long httpResponseCode; std::string response; HTTPRequest(csnd::Csound* csound, char* url) : csound(csound), url(url) { curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if (!curl) { curl_global_cleanup(); throw std::runtime_error((char*) ciniterror); } } ~HTTPRequest() { curl_easy_cleanup(curl); curl_global_cleanup(); } void post(char* postdata) { curl_reset(); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata); curlResult = curl_easy_perform(curl); if (curlResult != CURLE_OK) { curlError = (char*) curl_easy_strerror(curlResult); } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpResponseCode); } void get() { curl_reset(); curlResult = curl_easy_perform(curl); if (curlResult != CURLE_OK) { curlError = (char*) curl_easy_strerror(curlResult); } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpResponseCode); } }; class RequestThread : public csnd::Thread { std::atomic_bool spinlock; std::atomic_bool on; int sleepTime; public: HTTPRequest* req; char* postdata; bool dopost; char* error; bool errored; bool done; bool pending; RequestThread(csnd::Csound* csound, char* url, bool dopost, char* postdata=NULL) : Thread(csound), done(false), pending(false), on(true), spinlock(false), postdata(postdata), dopost(dopost), sleepTime(10) { try { req = new HTTPRequest(csound, url); } catch (const std::exception &e) { errored = true; error = csound->strdup(req->curlError); } }; uintptr_t run() { while (on) { lock(); if (pending) { try { if (dopost) { req->post(postdata); } else { req->get(); } if (req->curlResult != CURLE_OK) { errored = true; error = csound->strdup(req->curlError); } done = true; pending = false; } catch (const std::exception &e) { errored = true; done = true; pending = false; error = csound->strdup((char*) e.what()); } } unlock(); csound->sleep(sleepTime); } return 0; } void lock() { while (spinlock == true) { csound->sleep(sleepTime); } spinlock = true; } void unlock() { spinlock = false; } void stop() { on = false; } }; struct curlpostk : csnd::Plugin<3, 2> { static constexpr char const *otypes = "kkS"; static constexpr char const *itypes = "SS"; RequestThread request; int init() { csound->plugin_deinit(this); STRINGDAT &url = inargs.str_data(0); STRINGDAT &postdata = inargs.str_data(1); csnd::constr(&request, csound, url.data, true, postdata.data); return OK; } int deinit() { request.stop(); request.join(); csnd::destr(&request); return OK; } int kperf() { outargs[0] = FL(0); if (request.done) { if (request.errored) { return csound->perf_error(request.error, this); } outargs[0] = FL(1); } else if (!request.pending) { request.lock(); request.pending = true; request.unlock(); } outargs[1] = (MYFLT) request.req->httpResponseCode; STRINGDAT &resultstring = outargs.str_data(2); resultstring.data = csound->strdup((char*) request.req->response.c_str()); resultstring.size = request.req->response.size(); return OK; } }; struct curlgetk : csnd::Plugin<3, 1> { static constexpr char const *otypes = "kkS"; static constexpr char const *itypes = "S"; RequestThread request; int init() { csound->plugin_deinit(this); STRINGDAT &url = inargs.str_data(0); csnd::constr(&request, csound, url.data, false); return OK; } int deinit() { request.stop(); request.join(); csnd::destr(&request); return OK; } int kperf() { outargs[0] = FL(0); if (request.done) { if (request.errored) { return csound->perf_error(request.error, this); } outargs[0] = FL(1); } else if (!request.pending) { request.lock(); request.pending = true; request.unlock(); } outargs[1] = (MYFLT) request.req->httpResponseCode; STRINGDAT &resultstring = outargs.str_data(2); resultstring.data = csound->strdup((char*) request.req->response.c_str()); resultstring.size = request.req->response.size(); return OK; } }; struct curlpost : csnd::Plugin<2, 2> { static constexpr char const *otypes = "iS"; static constexpr char const *itypes = "SS"; int init() { STRINGDAT &url = inargs.str_data(0); STRINGDAT &postdata = inargs.str_data(1); HTTPRequest* req; try { req = new HTTPRequest(csound, url.data); } catch (const std::exception &e) { csound->init_error(csound->strdup((char*) e.what())); } req->post(postdata.data); if (req->curlResult != CURLE_OK) { return csound->init_error(csound->strdup(req->curlError)); } outargs[0] = (MYFLT) req->httpResponseCode; STRINGDAT &resultstring = outargs.str_data(1); resultstring.data = csound->strdup((char*) req->response.c_str()); resultstring.size = req->response.size(); return OK; } }; struct curlget : csnd::Plugin<2, 1> { static constexpr char const *otypes = "iS"; static constexpr char const *itypes = "S"; int init() { STRINGDAT &url = inargs.str_data(0); HTTPRequest* req; try { req = new HTTPRequest(csound, url.data); } catch (const std::exception &e) { csound->init_error(csound->strdup((char*) e.what())); } req->get(); if (req->curlResult != CURLE_OK) { return csound->init_error(csound->strdup(req->curlError)); } outargs[0] = (MYFLT) req->httpResponseCode; STRINGDAT &resultstring = outargs.str_data(1); resultstring.data = csound->strdup((char*) req->response.c_str()); resultstring.size = req->response.size(); return OK; } }; struct curlurlencode : csnd::Plugin<1, 1> { static constexpr char const *otypes = "S"; static constexpr char const *itypes = "S"; int init() { CURL* curl = curl_easy_init(); STRINGDAT &input = inargs.str_data(0); STRINGDAT &output = outargs.str_data(0); char* encoded = curl_easy_escape(curl, input.data, strlen(input.data)); output.data = csound->strdup(encoded); output.size = strlen(output.data); curl_free(encoded); curl_easy_cleanup(curl); return OK; } }; struct curlurlencodek : csnd::Plugin<1, 2> { static constexpr char const *otypes = "S"; static constexpr char const *itypes = "Sk"; CURL* curl; int init() { csound->plugin_deinit(this); curl = curl_easy_init(); return OK; } int kperf() { if (inargs[1] == 1) { STRINGDAT &input = inargs.str_data(0); STRINGDAT &output = outargs.str_data(0); char* encoded = curl_easy_escape(curl, input.data, strlen(input.data)); output.data = csound->strdup(encoded); output.size = strlen(output.data); curl_free(encoded); } return OK; } int deinit() { curl_easy_cleanup(curl); return OK; } }; #include void csnd::on_load(csnd::Csound *csound) { csnd::plugin(csound, "curlpost", csnd::thread::i); csnd::plugin(csound, "curlget", csnd::thread::i); csnd::plugin(csound, "curlpostk", csnd::thread::ik); csnd::plugin(csound, "curlgetk", csnd::thread::ik); csnd::plugin(csound, "curlurlencode", csnd::thread::i); csnd::plugin(csound, "curlurlencodek", csnd::thread::ik); }