diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-25 14:20:40 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-25 14:20:40 +0100 |
commit | 7b721840773a6faf2fa93562aeae1cc4c7d05804 (patch) | |
tree | 2c2a631f2e33def142f5e3d235884c14790ab88b /lib | |
parent | 8481061ffa1ea3fb84952dae88c817e9049325b1 (diff) | |
download | abrt-7b721840773a6faf2fa93562aeae1cc4c7d05804.tar.gz abrt-7b721840773a6faf2fa93562aeae1cc4c7d05804.tar.xz abrt-7b721840773a6faf2fa93562aeae1cc4c7d05804.zip |
rhticket: factor out HTTP POST code into abrt_curl.{h,cpp}
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Plugins/Catcut.cpp | 1 | ||||
-rw-r--r-- | lib/Plugins/FileTransfer.cpp | 2 | ||||
-rw-r--r-- | lib/Plugins/KerneloopsReporter.cpp | 2 | ||||
-rw-r--r-- | lib/Plugins/TicketUploader.cpp | 2 | ||||
-rw-r--r-- | lib/Plugins/rhticket.cpp | 147 | ||||
-rw-r--r-- | lib/Utils/Makefile.am | 1 | ||||
-rw-r--r-- | lib/Utils/abrt_curl.cpp | 193 | ||||
-rw-r--r-- | lib/Utils/abrt_curl.h | 45 | ||||
-rw-r--r-- | lib/Utils/abrt_xmlrpc.cpp | 10 | ||||
-rw-r--r-- | lib/Utils/abrt_xmlrpc.h | 1 |
10 files changed, 254 insertions, 150 deletions
diff --git a/lib/Plugins/Catcut.cpp b/lib/Plugins/Catcut.cpp index 48546367..6c655f2b 100644 --- a/lib/Plugins/Catcut.cpp +++ b/lib/Plugins/Catcut.cpp @@ -17,6 +17,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "abrtlib.h" +#include "abrt_curl.h" #include "abrt_xmlrpc.h" #include "Catcut.h" #include "CrashTypes.h" diff --git a/lib/Plugins/FileTransfer.cpp b/lib/Plugins/FileTransfer.cpp index 8f5bc6db..f0bb047b 100644 --- a/lib/Plugins/FileTransfer.cpp +++ b/lib/Plugins/FileTransfer.cpp @@ -26,7 +26,7 @@ #include <bzlib.h> #include <zlib.h> #include "abrtlib.h" -#include "abrt_xmlrpc.h" /* for xcurl_easy_init */ +#include "abrt_curl.h" #include "FileTransfer.h" #include "DebugDump.h" #include "ABRTException.h" diff --git a/lib/Plugins/KerneloopsReporter.cpp b/lib/Plugins/KerneloopsReporter.cpp index 4271e1d9..8c4fe114 100644 --- a/lib/Plugins/KerneloopsReporter.cpp +++ b/lib/Plugins/KerneloopsReporter.cpp @@ -18,7 +18,7 @@ */ #include "abrtlib.h" -#include "abrt_xmlrpc.h" /* for xcurl_easy_init */ +#include "abrt_curl.h" #include "KerneloopsReporter.h" #include "CommLayerInner.h" #include "ABRTException.h" diff --git a/lib/Plugins/TicketUploader.cpp b/lib/Plugins/TicketUploader.cpp index a7151b5e..2acb7b49 100644 --- a/lib/Plugins/TicketUploader.cpp +++ b/lib/Plugins/TicketUploader.cpp @@ -18,7 +18,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "abrtlib.h" -#include "abrt_xmlrpc.h" /* for xcurl_easy_init */ +#include "abrt_curl.h" #include "TicketUploader.h" #include "DebugDump.h" #include "ABRTException.h" diff --git a/lib/Plugins/rhticket.cpp b/lib/Plugins/rhticket.cpp index e0e72ff2..b5abf9df 100644 --- a/lib/Plugins/rhticket.cpp +++ b/lib/Plugins/rhticket.cpp @@ -19,7 +19,7 @@ #define _GNU_SOURCE 1 /* for stpcpy */ #include "abrtlib.h" -#include "abrt_xmlrpc.h" /* for xcurl_easy_handle */ +#include "abrt_curl.h" #include "rhticket.h" #include "CrashTypes.h" #include "DebugDump.h" @@ -81,136 +81,6 @@ static char *xml_escape(const char *str) 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; -} - -// -// Examine each header looking for "Location:" header -// -struct Headerdata { - 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; - - 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; - - end = start; - - // 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); - } - - 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 */ - } - - ret: - curl_easy_cleanup(handle); - curl_slist_free_all(httpheader_list); - return retval; -} /* * CReporterRHticket @@ -266,17 +136,22 @@ string CReporterRHticket::Report(const map_crash_data_t& pCrashData, 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); + curl_post_state *state = new_curl_post_state(0 + + ABRT_CURL_POST_WANT_HEADERS + + ABRT_CURL_POST_WANT_ERROR_MSG); + int http_resp_code = curl_post(state, url.c_str(), postdata.c_str()); + if (http_resp_code / 100 != 2) { /* not 2xx */ + string errmsg = state->curl_error_msg ? state->curl_error_msg : "(none)"; + free_curl_post_state(state); throw CABRTException(EXCEP_PLUGIN, _("server returned HTTP code %u, error message: %s"), - http_resp_code, res ? result.c_str() : "(none)"); + http_resp_code, errmsg.c_str()); } + string result = find_header_in_curl_post_state(state, "Location:") ? : ""; + free_curl_post_state(state); return result; } diff --git a/lib/Utils/Makefile.am b/lib/Utils/Makefile.am index 976cf318..aff324d6 100644 --- a/lib/Utils/Makefile.am +++ b/lib/Utils/Makefile.am @@ -45,6 +45,7 @@ libABRTdUtils_la_SOURCES = \ make_descr.cpp \ CommLayerInner.h CommLayerInner.cpp \ abrt_xmlrpc.h abrt_xmlrpc.cpp \ + abrt_curl.h abrt_curl.cpp \ Plugin.h Plugin.cpp \ Polkit.h Polkit.cpp \ Action.h Database.h Reporter.h Analyzer.h \ diff --git a/lib/Utils/abrt_curl.cpp b/lib/Utils/abrt_curl.cpp new file mode 100644 index 00000000..f327bd8c --- /dev/null +++ b/lib/Utils/abrt_curl.cpp @@ -0,0 +1,193 @@ +/* + Copyright (C) 2010 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "abrtlib.h" +#include "abrt_curl.h" +#include "CommLayerInner.h" + +using namespace std; + +/* + * Utility function + */ +CURL* xcurl_easy_init() +{ + CURL* curl = curl_easy_init(); + if (!curl) + { + error_msg_and_die("Can't create curl handle"); + } + return curl; +} + + +/* + * curl_post: perform HTTP POST transaction + */ +static char* +check_curl_error(CURLcode err, const char* msg) +{ + if (err) + return xasprintf("%s: %s", msg, curl_easy_strerror(err)); + return NULL; +} + +static void +die_if_curl_error(CURLcode err) +{ + char *msg = check_curl_error(err, "curl"); + if (msg) + error_msg_and_die("%s", msg); +} + +/* "save headers" callback */ +static size_t +save_headers(void *buffer_pv, size_t count, size_t nmemb, void *ptr) +{ + curl_post_state_t* state = (curl_post_state_t*)ptr; + size_t size = count * nmemb; + + + unsigned cnt = state->header_cnt; + state->headers = (char**)xrealloc(state->headers, (cnt+2) * sizeof(state->headers[0])); + + char *h = xstrndup((char*)buffer_pv, size); + strchrnul(h, '\r')[0] = '\0'; + strchrnul(h, '\n')[0] = '\0'; + VERB3 log("save_headers: state:%p header %d: '%s'", state, cnt, h); + state->headers[cnt] = h; + state->header_cnt = ++cnt; + state->headers[cnt] = NULL; + + return size; +} + +int +curl_post(curl_post_state_t* state, const char* url, const char* data) +{ + CURLcode curl_err; + struct curl_slist *httpheader_list = NULL; + FILE* body_stream = NULL; + long response_code; + curl_post_state_t localstate; + + VERB3 log("curl_post('%s','%s')", url, data); + + if (!state) + { + memset(&localstate, 0, sizeof(localstate)); + state = &localstate; + } + + state->http_resp_code = response_code = -1; + state->curl_error_msg = NULL; + + CURL *handle = xcurl_easy_init(); + + curl_err = curl_easy_setopt(handle, CURLOPT_VERBOSE, 0); + die_if_curl_error(curl_err); + curl_err = curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 1); + die_if_curl_error(curl_err); + curl_err = curl_easy_setopt(handle, CURLOPT_URL, url); + die_if_curl_error(curl_err); + curl_err = curl_easy_setopt(handle, CURLOPT_POST, 1); + die_if_curl_error(curl_err); + curl_err = curl_easy_setopt(handle, CURLOPT_POSTFIELDS, data); + die_if_curl_error(curl_err); + + httpheader_list = curl_slist_append(httpheader_list, "Content-Type: application/xml"); + curl_err = curl_easy_setopt(handle, CURLOPT_HTTPHEADER, httpheader_list); + die_if_curl_error(curl_err); + + if (state->flags & ABRT_CURL_POST_WANT_HEADERS) + { + curl_err = curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, save_headers); + die_if_curl_error(curl_err); + curl_err = curl_easy_setopt(handle, CURLOPT_WRITEHEADER, state); + die_if_curl_error(curl_err); + } + if (state->flags & ABRT_CURL_POST_WANT_BODY) + { + body_stream = open_memstream(&state->body, &state->body_size); + if (!body_stream) + error_msg_and_die("out of memory"); + curl_err = curl_easy_setopt(handle, CURLOPT_WRITEDATA, body_stream); + die_if_curl_error(curl_err); + } + + /* This is the place where everything happens. Here errors + * are not limited to "out of memory", can't just die. + */ + curl_err = curl_easy_perform(handle); + if (curl_err) + { + if (state->flags & ABRT_CURL_POST_WANT_ERROR_MSG) + state->curl_error_msg = check_curl_error(curl_err, "curl_easy_perform"); + goto ret; + } + + curl_err = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response_code); + die_if_curl_error(curl_err); + state->http_resp_code = response_code; + + ret: + curl_easy_cleanup(handle); + curl_slist_free_all(httpheader_list); + if (body_stream) + fclose(body_stream); + + return response_code; +} + +curl_post_state_t *new_curl_post_state(int flags) +{ + curl_post_state_t *state = (curl_post_state_t *)xzalloc(sizeof(*state)); + state->flags = flags; + return state; +} + +void free_curl_post_state(curl_post_state_t *state) +{ + char **headers = state->headers; + if (headers) + { + while (*headers) + free(*headers++); + free(state->headers); + } + free(state->curl_error_msg); + free(state->body); + free(state); + +} + +char *find_header_in_curl_post_state(curl_post_state_t *state, const char *str) +{ + char **headers = state->headers; + if (headers) + { + unsigned len = strlen(str); + while (*headers) + { + if (strncmp(*headers, str, len) == 0) + return skip_whitespace(*headers + len); + headers++; + } + } + return NULL; +} diff --git a/lib/Utils/abrt_curl.h b/lib/Utils/abrt_curl.h new file mode 100644 index 00000000..3c302453 --- /dev/null +++ b/lib/Utils/abrt_curl.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2010 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef ABRT_CURL_H_ +#define ABRT_CURL_H_ + +#include <curl/curl.h> + +CURL* xcurl_easy_init(); + +typedef struct curl_post_state { + int flags; + int http_resp_code; + unsigned header_cnt; + char **headers; + char *curl_error_msg; + char *body; + size_t body_size; +} curl_post_state_t; +enum { + ABRT_CURL_POST_WANT_HEADERS = (1 << 0), + ABRT_CURL_POST_WANT_ERROR_MSG = (1 << 1), + ABRT_CURL_POST_WANT_BODY = (1 << 2), +}; +curl_post_state_t *new_curl_post_state(int flags); +void free_curl_post_state(curl_post_state_t *state); +int curl_post(curl_post_state_t* state, const char* url, const char* data); +char *find_header_in_curl_post_state(curl_post_state_t *state, const char *str); + +#endif diff --git a/lib/Utils/abrt_xmlrpc.cpp b/lib/Utils/abrt_xmlrpc.cpp index 8be74d85..cbe09907 100644 --- a/lib/Utils/abrt_xmlrpc.cpp +++ b/lib/Utils/abrt_xmlrpc.cpp @@ -23,16 +23,6 @@ #include "abrt_xmlrpc.h" #include "ABRTException.h" -CURL* xcurl_easy_init() -{ - CURL* curl = curl_easy_init(); - if (!curl) - { - error_msg_and_die("Can't create curl handle"); - } - return curl; -} - void throw_xml_fault(xmlrpc_env *env) { std::string errmsg = ssprintf("XML-RPC Fault(%d): %s", env->fault_code, env->fault_string); diff --git a/lib/Utils/abrt_xmlrpc.h b/lib/Utils/abrt_xmlrpc.h index 4d20d4e8..ce770384 100644 --- a/lib/Utils/abrt_xmlrpc.h +++ b/lib/Utils/abrt_xmlrpc.h @@ -44,6 +44,5 @@ struct abrt_xmlrpc_conn { /* Utility functions */ void throw_xml_fault(xmlrpc_env *env); void throw_if_xml_fault_occurred(xmlrpc_env *env); -CURL* xcurl_easy_init(); #endif |