1 // Copyright (c) 2006, 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 "common/linux/http_upload.h" 31 32 #include <assert.h> 33 #include <dlfcn.h> 34 #include "third_party/curl/curl.h" 35 36 namespace { 37 38 // Callback to get the response data from server. 39 static size_t WriteCallback(void *ptr, size_t size, 40 size_t nmemb, void *userp) { 41 if (!userp) 42 return 0; 43 44 string *response = reinterpret_cast<string *>(userp); 45 size_t real_size = size * nmemb; 46 response->append(reinterpret_cast<char *>(ptr), real_size); 47 return real_size; 48 } 49 50 } // namespace 51 52 namespace google_breakpad { 53 54 static const char kUserAgent[] = "Breakpad/1.0 (Linux)"; 55 56 // static 57 bool HTTPUpload::SendRequest(const string &url, 58 const map<string, string> ¶meters, 59 const string &upload_file, 60 const string &file_part_name, 61 const string &proxy, 62 const string &proxy_user_pwd, 63 const string &ca_certificate_file, 64 string *response_body, 65 long *response_code, 66 string *error_description) { 67 if (response_code != NULL) 68 *response_code = 0; 69 70 if (!CheckParameters(parameters)) 71 return false; 72 73 // We may have been linked statically; if curl_easy_init is in the 74 // current binary, no need to search for a dynamic version. 75 void* curl_lib = dlopen(NULL, RTLD_NOW); 76 if (!curl_lib || dlsym(curl_lib, "curl_easy_init") == NULL) { 77 dlerror(); // Clear dlerror before attempting to open libraries. 78 dlclose(curl_lib); 79 curl_lib = NULL; 80 } 81 if (!curl_lib) { 82 curl_lib = dlopen("libcurl.so", RTLD_NOW); 83 } 84 if (!curl_lib) { 85 if (error_description != NULL) 86 *error_description = dlerror(); 87 curl_lib = dlopen("libcurl.so.4", RTLD_NOW); 88 } 89 if (!curl_lib) { 90 // Debian gives libcurl a different name when it is built against GnuTLS 91 // instead of OpenSSL. 92 curl_lib = dlopen("libcurl-gnutls.so.4", RTLD_NOW); 93 } 94 if (!curl_lib) { 95 curl_lib = dlopen("libcurl.so.3", RTLD_NOW); 96 } 97 if (!curl_lib) { 98 return false; 99 } 100 101 CURL* (*curl_easy_init)(void); 102 *(void**) (&curl_easy_init) = dlsym(curl_lib, "curl_easy_init"); 103 CURL *curl = (*curl_easy_init)(); 104 if (error_description != NULL) 105 *error_description = "No Error"; 106 107 if (!curl) { 108 dlclose(curl_lib); 109 return false; 110 } 111 112 CURLcode err_code = CURLE_OK; 113 CURLcode (*curl_easy_setopt)(CURL *, CURLoption, ...); 114 *(void**) (&curl_easy_setopt) = dlsym(curl_lib, "curl_easy_setopt"); 115 (*curl_easy_setopt)(curl, CURLOPT_URL, url.c_str()); 116 (*curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent); 117 // Set proxy information if necessary. 118 if (!proxy.empty()) 119 (*curl_easy_setopt)(curl, CURLOPT_PROXY, proxy.c_str()); 120 if (!proxy_user_pwd.empty()) 121 (*curl_easy_setopt)(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str()); 122 123 if (!ca_certificate_file.empty()) 124 (*curl_easy_setopt)(curl, CURLOPT_CAINFO, ca_certificate_file.c_str()); 125 126 struct curl_httppost *formpost = NULL; 127 struct curl_httppost *lastptr = NULL; 128 // Add form data. 129 CURLFORMcode (*curl_formadd)(struct curl_httppost **, struct curl_httppost **, ...); 130 *(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd"); 131 map<string, string>::const_iterator iter = parameters.begin(); 132 for (; iter != parameters.end(); ++iter) 133 (*curl_formadd)(&formpost, &lastptr, 134 CURLFORM_COPYNAME, iter->first.c_str(), 135 CURLFORM_COPYCONTENTS, iter->second.c_str(), 136 CURLFORM_END); 137 138 // Add form file. 139 (*curl_formadd)(&formpost, &lastptr, 140 CURLFORM_COPYNAME, file_part_name.c_str(), 141 CURLFORM_FILE, upload_file.c_str(), 142 CURLFORM_END); 143 144 (*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost); 145 146 // Disable 100-continue header. 147 struct curl_slist *headerlist = NULL; 148 char buf[] = "Expect:"; 149 struct curl_slist* (*curl_slist_append)(struct curl_slist *, const char *); 150 *(void**) (&curl_slist_append) = dlsym(curl_lib, "curl_slist_append"); 151 headerlist = (*curl_slist_append)(headerlist, buf); 152 (*curl_easy_setopt)(curl, CURLOPT_HTTPHEADER, headerlist); 153 154 if (response_body != NULL) { 155 (*curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback); 156 (*curl_easy_setopt)(curl, CURLOPT_WRITEDATA, 157 reinterpret_cast<void *>(response_body)); 158 } 159 160 // Fail if 400+ is returned from the web server. 161 (*curl_easy_setopt)(curl, CURLOPT_FAILONERROR, 1); 162 163 CURLcode (*curl_easy_perform)(CURL *); 164 *(void**) (&curl_easy_perform) = dlsym(curl_lib, "curl_easy_perform"); 165 err_code = (*curl_easy_perform)(curl); 166 if (response_code != NULL) { 167 CURLcode (*curl_easy_getinfo)(CURL *, CURLINFO, ...); 168 *(void**) (&curl_easy_getinfo) = dlsym(curl_lib, "curl_easy_getinfo"); 169 (*curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code); 170 } 171 const char* (*curl_easy_strerror)(CURLcode); 172 *(void**) (&curl_easy_strerror) = dlsym(curl_lib, "curl_easy_strerror"); 173 #ifndef NDEBUG 174 if (err_code != CURLE_OK) 175 fprintf(stderr, "Failed to send http request to %s, error: %s\n", 176 url.c_str(), 177 (*curl_easy_strerror)(err_code)); 178 #endif 179 if (error_description != NULL) 180 *error_description = (*curl_easy_strerror)(err_code); 181 182 void (*curl_easy_cleanup)(CURL *); 183 *(void**) (&curl_easy_cleanup) = dlsym(curl_lib, "curl_easy_cleanup"); 184 (*curl_easy_cleanup)(curl); 185 if (formpost != NULL) { 186 void (*curl_formfree)(struct curl_httppost *); 187 *(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree"); 188 (*curl_formfree)(formpost); 189 } 190 if (headerlist != NULL) { 191 void (*curl_slist_free_all)(struct curl_slist *); 192 *(void**) (&curl_slist_free_all) = dlsym(curl_lib, "curl_slist_free_all"); 193 (*curl_slist_free_all)(headerlist); 194 } 195 dlclose(curl_lib); 196 return err_code == CURLE_OK; 197 } 198 199 // static 200 bool HTTPUpload::CheckParameters(const map<string, string> ¶meters) { 201 for (map<string, string>::const_iterator pos = parameters.begin(); 202 pos != parameters.end(); ++pos) { 203 const string &str = pos->first; 204 if (str.size() == 0) 205 return false; // disallow empty parameter names 206 for (unsigned int i = 0; i < str.size(); ++i) { 207 int c = str[i]; 208 if (c < 32 || c == '"' || c > 127) { 209 return false; 210 } 211 } 212 } 213 return true; 214 } 215 216 } // namespace google_breakpad 217