michael@0: // Copyright (c) 2009, Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "common/linux/libcurl_wrapper.h" michael@0: #include "common/using_std_string.h" michael@0: michael@0: namespace google_breakpad { michael@0: LibcurlWrapper::LibcurlWrapper() michael@0: : init_ok_(false), michael@0: formpost_(NULL), michael@0: lastptr_(NULL), michael@0: headerlist_(NULL) { michael@0: curl_lib_ = dlopen("libcurl.so", RTLD_NOW); michael@0: if (!curl_lib_) { michael@0: curl_lib_ = dlopen("libcurl.so.4", RTLD_NOW); michael@0: } michael@0: if (!curl_lib_) { michael@0: curl_lib_ = dlopen("libcurl.so.3", RTLD_NOW); michael@0: } michael@0: if (!curl_lib_) { michael@0: std::cout << "Could not find libcurl via dlopen"; michael@0: return; michael@0: } michael@0: std::cout << "LibcurlWrapper init succeeded"; michael@0: init_ok_ = true; michael@0: return; michael@0: } michael@0: michael@0: bool LibcurlWrapper::SetProxy(const string& proxy_host, michael@0: const string& proxy_userpwd) { michael@0: if (!init_ok_) { michael@0: return false; michael@0: } michael@0: // Set proxy information if necessary. michael@0: if (!proxy_host.empty()) { michael@0: (*easy_setopt_)(curl_, CURLOPT_PROXY, proxy_host.c_str()); michael@0: } else { michael@0: std::cout << "SetProxy called with empty proxy host."; michael@0: return false; michael@0: } michael@0: if (!proxy_userpwd.empty()) { michael@0: (*easy_setopt_)(curl_, CURLOPT_PROXYUSERPWD, proxy_userpwd.c_str()); michael@0: } else { michael@0: std::cout << "SetProxy called with empty proxy username/password."; michael@0: return false; michael@0: } michael@0: std::cout << "Set proxy host to " << proxy_host; michael@0: return true; michael@0: } michael@0: michael@0: bool LibcurlWrapper::AddFile(const string& upload_file_path, michael@0: const string& basename) { michael@0: if (!init_ok_) { michael@0: return false; michael@0: } michael@0: std::cout << "Adding " << upload_file_path << " to form upload."; michael@0: // Add form file. michael@0: (*formadd_)(&formpost_, &lastptr_, michael@0: CURLFORM_COPYNAME, basename.c_str(), michael@0: CURLFORM_FILE, upload_file_path.c_str(), michael@0: CURLFORM_END); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // Callback to get the response data from server. michael@0: static size_t WriteCallback(void *ptr, size_t size, michael@0: size_t nmemb, void *userp) { michael@0: if (!userp) michael@0: return 0; michael@0: michael@0: string *response = reinterpret_cast(userp); michael@0: size_t real_size = size * nmemb; michael@0: response->append(reinterpret_cast(ptr), real_size); michael@0: return real_size; michael@0: } michael@0: michael@0: bool LibcurlWrapper::SendRequest(const string& url, michael@0: const std::map& parameters, michael@0: string* server_response) { michael@0: (*easy_setopt_)(curl_, CURLOPT_URL, url.c_str()); michael@0: std::map::const_iterator iter = parameters.begin(); michael@0: for (; iter != parameters.end(); ++iter) michael@0: (*formadd_)(&formpost_, &lastptr_, michael@0: CURLFORM_COPYNAME, iter->first.c_str(), michael@0: CURLFORM_COPYCONTENTS, iter->second.c_str(), michael@0: CURLFORM_END); michael@0: michael@0: (*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_); michael@0: if (server_response != NULL) { michael@0: (*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback); michael@0: (*easy_setopt_)(curl_, CURLOPT_WRITEDATA, michael@0: reinterpret_cast(server_response)); michael@0: } michael@0: michael@0: CURLcode err_code = CURLE_OK; michael@0: err_code = (*easy_perform_)(curl_); michael@0: easy_strerror_ = reinterpret_cast michael@0: (dlsym(curl_lib_, "curl_easy_strerror")); michael@0: michael@0: #ifndef NDEBUG michael@0: if (err_code != CURLE_OK) michael@0: fprintf(stderr, "Failed to send http request to %s, error: %s\n", michael@0: url.c_str(), michael@0: (*easy_strerror_)(err_code)); michael@0: #endif michael@0: if (headerlist_ != NULL) { michael@0: (*slist_free_all_)(headerlist_); michael@0: } michael@0: michael@0: (*easy_cleanup_)(curl_); michael@0: if (formpost_ != NULL) { michael@0: (*formfree_)(formpost_); michael@0: } michael@0: michael@0: return err_code == CURLE_OK; michael@0: } michael@0: michael@0: bool LibcurlWrapper::Init() { michael@0: if (!init_ok_) { michael@0: std::cout << "Init_OK was not true in LibcurlWrapper::Init(), check earlier log messages"; michael@0: return false; michael@0: } michael@0: michael@0: if (!SetFunctionPointers()) { michael@0: std::cout << "Could not find function pointers"; michael@0: init_ok_ = false; michael@0: return false; michael@0: } michael@0: michael@0: curl_ = (*easy_init_)(); michael@0: michael@0: last_curl_error_ = "No Error"; michael@0: michael@0: if (!curl_) { michael@0: dlclose(curl_lib_); michael@0: std::cout << "Curl initialization failed"; michael@0: return false; michael@0: } michael@0: michael@0: // Disable 100-continue header. michael@0: char buf[] = "Expect:"; michael@0: michael@0: headerlist_ = (*slist_append_)(headerlist_, buf); michael@0: (*easy_setopt_)(curl_, CURLOPT_HTTPHEADER, headerlist_); michael@0: return true; michael@0: } michael@0: michael@0: #define SET_AND_CHECK_FUNCTION_POINTER(var, function_name, type) \ michael@0: var = reinterpret_cast(dlsym(curl_lib_, function_name)); \ michael@0: if (!var) { \ michael@0: std::cout << "Could not find libcurl function " << function_name; \ michael@0: init_ok_ = false; \ michael@0: return false; \ michael@0: } michael@0: michael@0: bool LibcurlWrapper::SetFunctionPointers() { michael@0: michael@0: SET_AND_CHECK_FUNCTION_POINTER(easy_init_, michael@0: "curl_easy_init", michael@0: CURL*(*)()); michael@0: michael@0: SET_AND_CHECK_FUNCTION_POINTER(easy_setopt_, michael@0: "curl_easy_setopt", michael@0: CURLcode(*)(CURL*, CURLoption, ...)); michael@0: michael@0: SET_AND_CHECK_FUNCTION_POINTER(formadd_, "curl_formadd", michael@0: CURLFORMcode(*)(curl_httppost**, curl_httppost**, ...)); michael@0: michael@0: SET_AND_CHECK_FUNCTION_POINTER(slist_append_, "curl_slist_append", michael@0: curl_slist*(*)(curl_slist*, const char*)); michael@0: michael@0: SET_AND_CHECK_FUNCTION_POINTER(easy_perform_, michael@0: "curl_easy_perform", michael@0: CURLcode(*)(CURL*)); michael@0: michael@0: SET_AND_CHECK_FUNCTION_POINTER(easy_cleanup_, michael@0: "curl_easy_cleanup", michael@0: void(*)(CURL*)); michael@0: michael@0: SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_, michael@0: "curl_slist_free_all", michael@0: void(*)(curl_slist*)); michael@0: michael@0: SET_AND_CHECK_FUNCTION_POINTER(formfree_, michael@0: "curl_formfree", michael@0: void(*)(curl_httppost*)); michael@0: return true; michael@0: } michael@0: michael@0: }