From 9f722a8a0407c111ceac51ba0d3ac2189c2dd9a1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 23 Mar 2010 21:51:41 +0100 Subject: rhticket: xml-escape strings Signed-off-by: Denys Vlasenko --- lib/Plugins/rhticket.cpp | 418 +++++++++++++++++++++++++++-------------------- 1 file changed, 240 insertions(+), 178 deletions(-) diff --git a/lib/Plugins/rhticket.cpp b/lib/Plugins/rhticket.cpp index 8aebb499..e0e72ff2 100644 --- a/lib/Plugins/rhticket.cpp +++ b/lib/Plugins/rhticket.cpp @@ -17,6 +17,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#define _GNU_SOURCE 1 /* for stpcpy */ #include "abrtlib.h" #include "abrt_xmlrpc.h" /* for xcurl_easy_handle */ #include "rhticket.h" @@ -31,133 +32,184 @@ using namespace std; +static char *xml_escape(const char *str) +{ + const char *s = str; + unsigned count = 1; /* for NUL */ + while (*s) + { + if (*s == '&') + count += sizeof("&")-2; + if (*s == '<') + count += sizeof("<")-2; + if (*s == '>') + count += sizeof(">")-2; + if ((unsigned char)*s > 126 || (unsigned char)*s < ' ') + count += sizeof("\\x00")-2; + count++; + s++; + } + char *result = (char*)xmalloc(count); + char *d = result; + s = str; + while (*s) + { + if (*s == '&') + d = stpcpy(d, "&"); + else if (*s == '<') + d = stpcpy(d, "<"); + else if (*s == '>') + d = stpcpy(d, ">"); + else + if ((unsigned char)*s > 126 + || ( (unsigned char)*s < ' ' + && *s != '\t' + && *s != '\n' + && *s != '\r' + ) + ) { + *d++ = '\\'; + *d++ = 'x'; + *d++ = "0123456789abcdef"[(unsigned char)*s >> 4]; + *d++ = "0123456789abcdef"[(unsigned char)*s & 0xf]; + } + else + *d++ = *s; + s++; + } + *d = '\0'; + return result; +} + static char* check_curl_error(CURLcode err, const char* msg) { - if (err) { - return xasprintf("%s: %s", msg, curl_easy_strerror(err)); - } - return NULL; + if (err) + { + return xasprintf("%s: %s", msg, curl_easy_strerror(err)); + } + return NULL; } // // Examine each header looking for "Location:" header // struct Headerdata { - char *location; + char *location; }; static size_t headerfunction(void *buffer_pv, size_t count, size_t nmemb, void *headerdata_pv) { - struct Headerdata* headerdata = (struct Headerdata*)headerdata_pv; - const char* buffer = (const char*)buffer_pv; - const char location_key[] = "Location:"; - const size_t location_key_size = sizeof(location_key)-1; + struct Headerdata* headerdata = (struct Headerdata*)headerdata_pv; + const char* buffer = (const char*)buffer_pv; + const char location_key[] = "Location:"; + const size_t location_key_size = sizeof(location_key)-1; - size_t size = count * nmemb; - if (size >= location_key_size - && 0 == memcmp(buffer, location_key, location_key_size) - ) { - const char* start = (const char*) buffer + location_key_size + 1; - const char* end; + size_t size = count * nmemb; + if (size >= location_key_size + && 0 == memcmp(buffer, location_key, location_key_size) + ) { + const char* start = (const char*) buffer + location_key_size + 1; + const char* end; - // skip over any leading space - while (start < buffer+size && isspace(*start)) - ++start; + // skip over any leading space + while (start < buffer+size && isspace(*start)) + ++start; - end = start; + end = start; - // skip till we find the end of the url (first space or end of buffer) - while (end < buffer+size && !isspace(*end)) - ++end; + // skip till we find the end of the url (first space or end of buffer) + while (end < buffer+size && !isspace(*end)) + ++end; - headerdata->location = xstrndup(start, end - start); - } + headerdata->location = xstrndup(start, end - start); + } - return size; + return size; } static char* post(int *http_resp_code, const char* url, const char* data) { - char *retval; - CURLcode curl_err; - struct curl_slist *httpheader_list = NULL; - struct Headerdata headerdata = { NULL }; - - if (http_resp_code) - *http_resp_code = -1; - - CURL *handle = xcurl_easy_init(); - - curl_err = curl_easy_setopt(handle, CURLOPT_VERBOSE, 0); - retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_VERBOSE)"); - if (retval) - goto ret; - - curl_err = curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 1); - retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_NOPROGRESS)"); - if (retval) - goto ret; - - curl_err = curl_easy_setopt(handle, CURLOPT_POST, 1); - retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_POST)"); - if (retval) - goto ret; - - curl_err = curl_easy_setopt(handle, CURLOPT_URL, url); - retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_URL)"); - if (retval) - goto ret; - - httpheader_list = curl_slist_append(httpheader_list, "Content-Type: application/xml"); - curl_err = curl_easy_setopt(handle, CURLOPT_HTTPHEADER, httpheader_list); - retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_HTTPHEADER)"); - if (retval) - goto ret; - - curl_err = curl_easy_setopt(handle, CURLOPT_POSTFIELDS, data); - retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_POSTFIELDS)"); - if (retval) - goto ret; - - curl_err = curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerfunction); - retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_HEADERFUNCTION)"); - if (retval) - goto ret; - - curl_err = curl_easy_setopt(handle, CURLOPT_WRITEHEADER, &headerdata); - retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_WRITEHEADER)"); - if (retval) - goto ret; - - curl_err = curl_easy_perform(handle); - retval = check_curl_error(curl_err, "curl_easy_perform"); - if (retval) - goto ret; - - long response_code; - curl_err = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response_code); - retval = check_curl_error(curl_err, "curl_easy_getinfo(CURLINFO_RESPONSE_CODE)"); - if (retval) - goto ret; - - if (http_resp_code) - *http_resp_code = response_code; - switch (response_code) { - case 200: - case 201: - retval = headerdata.location; - break; - /* default: */ - /* TODO: extract meaningful error string from server reply */ - } + char *retval; + CURLcode curl_err; + struct curl_slist *httpheader_list = NULL; + struct Headerdata headerdata = { NULL }; + + if (http_resp_code) + *http_resp_code = -1; + + CURL *handle = xcurl_easy_init(); + + curl_err = curl_easy_setopt(handle, CURLOPT_VERBOSE, 0); + retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_VERBOSE)"); + if (retval) + goto ret; + + curl_err = curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 1); + retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_NOPROGRESS)"); + if (retval) + goto ret; + + curl_err = curl_easy_setopt(handle, CURLOPT_POST, 1); + retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_POST)"); + if (retval) + goto ret; + + curl_err = curl_easy_setopt(handle, CURLOPT_URL, url); + retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_URL)"); + if (retval) + goto ret; + + httpheader_list = curl_slist_append(httpheader_list, "Content-Type: application/xml"); + curl_err = curl_easy_setopt(handle, CURLOPT_HTTPHEADER, httpheader_list); + retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_HTTPHEADER)"); + if (retval) + goto ret; + + curl_err = curl_easy_setopt(handle, CURLOPT_POSTFIELDS, data); + retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_POSTFIELDS)"); + if (retval) + goto ret; + + curl_err = curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerfunction); + retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_HEADERFUNCTION)"); + if (retval) + goto ret; + + curl_err = curl_easy_setopt(handle, CURLOPT_WRITEHEADER, &headerdata); + retval = check_curl_error(curl_err, "curl_easy_setopt(CURLOPT_WRITEHEADER)"); + if (retval) + goto ret; + + curl_err = curl_easy_perform(handle); + retval = check_curl_error(curl_err, "curl_easy_perform"); + if (retval) + goto ret; + + long response_code; + curl_err = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response_code); + retval = check_curl_error(curl_err, "curl_easy_getinfo(CURLINFO_RESPONSE_CODE)"); + if (retval) + goto ret; + + if (http_resp_code) + *http_resp_code = response_code; + switch (response_code) + { + case 200: + case 201: + retval = headerdata.location; + break; + /* default: */ + /* TODO: extract meaningful error string from server reply */ + } ret: - curl_easy_cleanup(handle); - curl_slist_free_all(httpheader_list); - return retval; + curl_easy_cleanup(handle); + curl_slist_free_all(httpheader_list); + return retval; } /* @@ -173,95 +225,105 @@ CReporterRHticket::~CReporterRHticket() {} string CReporterRHticket::Report(const map_crash_data_t& pCrashData, - const map_plugin_settings_t& pSettings, - const char *pArgs) + const map_plugin_settings_t& pSettings, + const char *pArgs) { - const string& package = get_crash_data_item_content(pCrashData, FILENAME_PACKAGE); -// const string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT); - const string& release = get_crash_data_item_content(pCrashData, FILENAME_RELEASE); -// const string& arch = get_crash_data_item_content(pCrashData, FILENAME_ARCHITECTURE); - const string& duphash = get_crash_data_item_content(pCrashData, CD_DUPHASH); - const char *reason = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_REASON); - - string summary = "[abrt] crash in " + package; - if (reason != NULL) { - summary += ": "; - summary += reason; - } -// string status_whiteboard = "abrt_hash:" + duphash; - - string description = "abrt "VERSION" detected a crash.\n\n"; - description += make_description_bz(pCrashData); - -// string product; -// string version; -// parse_release(release.c_str(), product, version); - - string postdata = ssprintf( - "" - "" - "%s" - "%s" - // "" - "", -//TODO: xml-encode, check UTF-8 correctness etc: - summary.c_str(), - description.c_str() - ); - string url = concat_path_file(m_sStrataURL.c_str(), "cases"); - - int http_resp_code; - char *res = post(&http_resp_code, url.c_str(), postdata.c_str()); - string result = res ? res : ""; - free(res); - if (http_resp_code / 100 != 2) { /* not 2xx */ - throw CABRTException(EXCEP_PLUGIN, _("server returned HTTP code %u, error message: %s"), - http_resp_code, res ? result.c_str() : "(none)"); - } - - return result; + const string& package = get_crash_data_item_content(pCrashData, FILENAME_PACKAGE); +// const string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT); +// const string& release = get_crash_data_item_content(pCrashData, FILENAME_RELEASE); +// const string& arch = get_crash_data_item_content(pCrashData, FILENAME_ARCHITECTURE); +// const string& duphash = get_crash_data_item_content(pCrashData, CD_DUPHASH); + const char *reason = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_REASON); + + string summary = "[abrt] crash in " + package; + if (reason != NULL) + { + summary += ": "; + summary += reason; + } +// string status_whiteboard = "abrt_hash:" + duphash; + + string description = "abrt "VERSION" detected a crash.\n\n"; + description += make_description_bz(pCrashData); + +// string product; +// string version; +// parse_release(release.c_str(), product, version); + + char *xml_summary = xml_escape(summary.c_str()); + char *xml_description = xml_escape(description.c_str()); + string postdata = ssprintf( + "" + "" + "%s" + "%s" + // "" + "", + xml_summary, + xml_description + ); + free(xml_summary); + free(xml_description); + string url = concat_path_file(m_sStrataURL.c_str(), "cases"); + + int http_resp_code; + char *res = post(&http_resp_code, url.c_str(), postdata.c_str()); + string result = res ? res : ""; + free(res); + if (http_resp_code / 100 != 2) + { + /* not 2xx */ + throw CABRTException(EXCEP_PLUGIN, _("server returned HTTP code %u, error message: %s"), + http_resp_code, res ? result.c_str() : "(none)"); + } + + return result; } void CReporterRHticket::SetSettings(const map_plugin_settings_t& pSettings) { - m_pSettings = pSettings; - - map_plugin_settings_t::const_iterator end = pSettings.end(); - map_plugin_settings_t::const_iterator it; - it = pSettings.find("URL"); - if (it != end) { - m_sStrataURL = it->second; - } - it = pSettings.find("Login"); - if (it != end) { - m_sLogin = it->second; - } - it = pSettings.find("Password"); - if (it != end) { - m_sPassword = it->second; - } - it = pSettings.find("SSLVerify"); - if (it != end) { - m_bSSLVerify = string_to_bool(it->second.c_str()); - } + m_pSettings = pSettings; + + map_plugin_settings_t::const_iterator end = pSettings.end(); + map_plugin_settings_t::const_iterator it; + it = pSettings.find("URL"); + if (it != end) + { + m_sStrataURL = it->second; + } + it = pSettings.find("Login"); + if (it != end) + { + m_sLogin = it->second; + } + it = pSettings.find("Password"); + if (it != end) + { + m_sPassword = it->second; + } + it = pSettings.find("SSLVerify"); + if (it != end) + { + m_bSSLVerify = string_to_bool(it->second.c_str()); + } } /* Should not be deleted (why?) */ const map_plugin_settings_t& CReporterRHticket::GetSettings() { - m_pSettings["URL"] = m_sStrataURL; - m_pSettings["Login"] = m_sLogin; - m_pSettings["Password"] = m_sPassword; - m_pSettings["SSLVerify"] = m_bSSLVerify ? "yes" : "no"; + m_pSettings["URL"] = m_sStrataURL; + m_pSettings["Login"] = m_sLogin; + m_pSettings["Password"] = m_sPassword; + m_pSettings["SSLVerify"] = m_bSSLVerify ? "yes" : "no"; - return m_pSettings; + return m_pSettings; } PLUGIN_INFO(REPORTER, - CReporterRHticket, - "RHticket", - "0.0.4", - "Reports bugs to Red Hat support", - "Denys Vlasenko ", - "https://fedorahosted.org/abrt/wiki", - "" /*PLUGINS_LIB_DIR"/rhticket.GTKBuilder"*/); + CReporterRHticket, + "RHticket", + "0.0.4", + "Reports bugs to Red Hat support", + "Denys Vlasenko ", + "https://fedorahosted.org/abrt/wiki", + "" /*PLUGINS_LIB_DIR"/rhticket.GTKBuilder"*/); -- cgit