1 // Copyright (c) 2009, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 #include <dlfcn.h> 31 32 #include <iostream> 33 #include <string> 34 35 #include "common/linux/libcurl_wrapper.h" 36 #include "common/using_std_string.h" 37 38 namespace google_breakpad { 39 LibcurlWrapper::LibcurlWrapper() 40 : init_ok_(false), 41 formpost_(NULL), 42 lastptr_(NULL), 43 headerlist_(NULL) { 44 curl_lib_ = dlopen("libcurl.so", RTLD_NOW); 45 if (!curl_lib_) { 46 curl_lib_ = dlopen("libcurl.so.4", RTLD_NOW); 47 } 48 if (!curl_lib_) { 49 curl_lib_ = dlopen("libcurl.so.3", RTLD_NOW); 50 } 51 if (!curl_lib_) { 52 std::cout << "Could not find libcurl via dlopen"; 53 return; 54 } 55 std::cout << "LibcurlWrapper init succeeded"; 56 init_ok_ = true; 57 return; 58 } 59 60 LibcurlWrapper::~LibcurlWrapper() {} 61 62 bool LibcurlWrapper::SetProxy(const string& proxy_host, 63 const string& proxy_userpwd) { 64 if (!init_ok_) { 65 return false; 66 } 67 // Set proxy information if necessary. 68 if (!proxy_host.empty()) { 69 (*easy_setopt_)(curl_, CURLOPT_PROXY, proxy_host.c_str()); 70 } else { 71 std::cout << "SetProxy called with empty proxy host."; 72 return false; 73 } 74 if (!proxy_userpwd.empty()) { 75 (*easy_setopt_)(curl_, CURLOPT_PROXYUSERPWD, proxy_userpwd.c_str()); 76 } else { 77 std::cout << "SetProxy called with empty proxy username/password."; 78 return false; 79 } 80 std::cout << "Set proxy host to " << proxy_host; 81 return true; 82 } 83 84 bool LibcurlWrapper::AddFile(const string& upload_file_path, 85 const string& basename) { 86 if (!init_ok_) { 87 return false; 88 } 89 std::cout << "Adding " << upload_file_path << " to form upload."; 90 // Add form file. 91 (*formadd_)(&formpost_, &lastptr_, 92 CURLFORM_COPYNAME, basename.c_str(), 93 CURLFORM_FILE, upload_file_path.c_str(), 94 CURLFORM_END); 95 96 return true; 97 } 98 99 // Callback to get the response data from server. 100 static size_t WriteCallback(void *ptr, size_t size, 101 size_t nmemb, void *userp) { 102 if (!userp) 103 return 0; 104 105 string *response = reinterpret_cast<string *>(userp); 106 size_t real_size = size * nmemb; 107 response->append(reinterpret_cast<char *>(ptr), real_size); 108 return real_size; 109 } 110 111 bool LibcurlWrapper::SendRequest(const string& url, 112 const std::map<string, string>& parameters, 113 int* http_status_code, 114 string* http_header_data, 115 string* http_response_data) { 116 (*easy_setopt_)(curl_, CURLOPT_URL, url.c_str()); 117 std::map<string, string>::const_iterator iter = parameters.begin(); 118 for (; iter != parameters.end(); ++iter) 119 (*formadd_)(&formpost_, &lastptr_, 120 CURLFORM_COPYNAME, iter->first.c_str(), 121 CURLFORM_COPYCONTENTS, iter->second.c_str(), 122 CURLFORM_END); 123 124 (*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_); 125 if (http_response_data != NULL) { 126 http_response_data->clear(); 127 (*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback); 128 (*easy_setopt_)(curl_, CURLOPT_WRITEDATA, 129 reinterpret_cast<void *>(http_response_data)); 130 } 131 if (http_header_data != NULL) { 132 http_header_data->clear(); 133 (*easy_setopt_)(curl_, CURLOPT_HEADERFUNCTION, WriteCallback); 134 (*easy_setopt_)(curl_, CURLOPT_HEADERDATA, 135 reinterpret_cast<void *>(http_header_data)); 136 } 137 138 CURLcode err_code = CURLE_OK; 139 err_code = (*easy_perform_)(curl_); 140 easy_strerror_ = reinterpret_cast<const char* (*)(CURLcode)> 141 (dlsym(curl_lib_, "curl_easy_strerror")); 142 143 if (http_status_code != NULL) { 144 (*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code); 145 } 146 147 #ifndef NDEBUG 148 if (err_code != CURLE_OK) 149 fprintf(stderr, "Failed to send http request to %s, error: %s\n", 150 url.c_str(), 151 (*easy_strerror_)(err_code)); 152 #endif 153 if (headerlist_ != NULL) { 154 (*slist_free_all_)(headerlist_); 155 } 156 157 (*easy_cleanup_)(curl_); 158 if (formpost_ != NULL) { 159 (*formfree_)(formpost_); 160 } 161 162 return err_code == CURLE_OK; 163 } 164 165 bool LibcurlWrapper::Init() { 166 if (!init_ok_) { 167 std::cout << "Init_OK was not true in LibcurlWrapper::Init(), check earlier log messages"; 168 return false; 169 } 170 171 if (!SetFunctionPointers()) { 172 std::cout << "Could not find function pointers"; 173 init_ok_ = false; 174 return false; 175 } 176 177 curl_ = (*easy_init_)(); 178 179 last_curl_error_ = "No Error"; 180 181 if (!curl_) { 182 dlclose(curl_lib_); 183 std::cout << "Curl initialization failed"; 184 return false; 185 } 186 187 // Disable 100-continue header. 188 char buf[] = "Expect:"; 189 190 headerlist_ = (*slist_append_)(headerlist_, buf); 191 (*easy_setopt_)(curl_, CURLOPT_HTTPHEADER, headerlist_); 192 return true; 193 } 194 195 #define SET_AND_CHECK_FUNCTION_POINTER(var, function_name, type) \ 196 var = reinterpret_cast<type>(dlsym(curl_lib_, function_name)); \ 197 if (!var) { \ 198 std::cout << "Could not find libcurl function " << function_name; \ 199 init_ok_ = false; \ 200 return false; \ 201 } 202 203 bool LibcurlWrapper::SetFunctionPointers() { 204 205 SET_AND_CHECK_FUNCTION_POINTER(easy_init_, 206 "curl_easy_init", 207 CURL*(*)()); 208 209 SET_AND_CHECK_FUNCTION_POINTER(easy_setopt_, 210 "curl_easy_setopt", 211 CURLcode(*)(CURL*, CURLoption, ...)); 212 213 SET_AND_CHECK_FUNCTION_POINTER(formadd_, "curl_formadd", 214 CURLFORMcode(*)(curl_httppost**, curl_httppost**, ...)); 215 216 SET_AND_CHECK_FUNCTION_POINTER(slist_append_, "curl_slist_append", 217 curl_slist*(*)(curl_slist*, const char*)); 218 219 SET_AND_CHECK_FUNCTION_POINTER(easy_perform_, 220 "curl_easy_perform", 221 CURLcode(*)(CURL*)); 222 223 SET_AND_CHECK_FUNCTION_POINTER(easy_cleanup_, 224 "curl_easy_cleanup", 225 void(*)(CURL*)); 226 227 SET_AND_CHECK_FUNCTION_POINTER(easy_getinfo_, 228 "curl_easy_getinfo", 229 CURLcode(*)(CURL *, CURLINFO info, ...)); 230 231 SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_, 232 "curl_slist_free_all", 233 void(*)(curl_slist*)); 234 235 SET_AND_CHECK_FUNCTION_POINTER(formfree_, 236 "curl_formfree", 237 void(*)(curl_httppost*)); 238 return true; 239 } 240 241 } 242