#include #include #include #include "faf.h" static size_t curl_download_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { std::ostream *dest = (std::ostream *)userdata; size_t len = size * nmemb; dest->write(ptr, len); return len; } static bool json_array_fill_set(json_object *array, std::set &dest) { if (json_object_get_type(array) != json_type_array) return false; unsigned len = json_object_array_length(array); unsigned i; json_object *elem; for (i = 0; i < len; ++i) { elem = json_object_array_get_idx(array, i); if (json_object_get_type(elem) != json_type_int) continue; dest.insert(json_object_get_int(elem)); } return true; } static json_object *json_parse(const char *raw) { json_object *json = json_tokener_parse(raw); return is_error(json) ? NULL : json; } FafClient::FafClient(std::string baseUrl) { this->errorMsg = ""; this->baseUrl = baseUrl; if (this->baseUrl[this->baseUrl.length() - 1] != '/') this->baseUrl += '/'; } void FafClient::setError(std::string errorMsg) { this->errorMsg = errorMsg; } std::string FafClient::getError() { std::string result = this->errorMsg; this->errorMsg = ""; return result; } bool FafClient::downloadToStream(std::string url, std::ostream &dest) { CURL *curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &dest); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_download_callback); CURLcode retcode = curl_easy_perform(curl); bool success = retcode == CURLE_OK; if (!success) { std::string errorMsg("cURL request failed: "); this->setError(errorMsg + curl_easy_strerror(retcode)); } curl_easy_cleanup(curl); return success; } bool FafClient::getLlvmBuilds(std::set &dest) { std::string url = this->baseUrl + "query/LlvmBuild"; std::stringstream response; bool result = this->downloadToStream(url, response); if (!result) return false; json_object *json = json_parse(response.str().c_str()); if (!json) { this->setError("Unable to parse JSON from response"); return false; } json_object *builds = json_object_object_get(json, "LlvmBuild"); if (!builds) { this->setError("Key 'LlvmBuild' not found in the response"); return false; } else if (json_object_get_type(builds) != json_type_array) { this->setError("'LlvmBuild' is not an array"); return false; } json_array_fill_set(builds, dest); json_object_put(json); return true; } bool FafClient::getBcFiles(int llvmBuildId, std::set &dest) { std::stringstream buildid; buildid << llvmBuildId; std::string url = this->baseUrl + "query/LlvmBuild/" + buildid.str(); std::stringstream response; bool result = this->downloadToStream(url, response); if (!result) return false; json_object *json = json_parse(response.str().c_str()); if (!json) { this->setError("Unable to parse JSON from response"); return false; } json_object *build = json_object_object_get(json, buildid.str().c_str()); if (!build) { this->setError("Key '" + buildid.str() + "' not found in the response"); return false; } else if (json_object_get_type(build) != json_type_object) { this->setError("'" + buildid.str() + "' is not a JSON object"); return false; } json_object *bcfiles = json_object_object_get(build, "bc_files"); if (!bcfiles) { this->setError("Key 'bc_files' not found in the object"); return false; } else if (json_object_get_type(bcfiles) != json_type_array) { this->setError("'bc_files' is not an array"); return false; } json_array_fill_set(bcfiles, dest); json_object_put(build); return true; } bool FafClient::getBcFileName(int bcFileId, std::string &dest) { std::stringstream fileid; fileid << bcFileId; std::string url = this->baseUrl + "query/LlvmBcFile/" + fileid.str(); std::stringstream response; bool result = this->downloadToStream(url, response); if (!result) return false; json_object *json = json_parse(response.str().c_str()); if (!json) { this->setError("Unable to parse JSON from response"); return false; } json_object *file = json_object_object_get(json, fileid.str().c_str()); if (!file) { this->setError("Key '" + fileid.str() + "' not found in the response"); return false; } else if (json_object_get_type(file) != json_type_object) { this->setError("'" + fileid.str() + "' is not a JSON object"); return false; } json_object *path = json_object_object_get(file, "path"); if (!path) { this->setError("Key 'path' not found in the object"); return false; } else if (json_object_get_type(path) != json_type_string) { this->setError("'path' is not a string"); return false; } std::string fullpath(json_object_get_string(path)); unsigned slash = fullpath.rfind('/'); dest = slash < fullpath.length() ? fullpath.erase(0, slash + 1) : fullpath; json_object_put(json); return true; } bool FafClient::downloadBcFile(int bcFileId, std::ostream &dest) { std::stringstream queryUrl; queryUrl << this->baseUrl << "status/llvm/bcfile/" << bcFileId; return this->downloadToStream(queryUrl.str(), dest); }