|
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 bool LibcurlWrapper::SetProxy(const string& proxy_host, |
|
61 const string& proxy_userpwd) { |
|
62 if (!init_ok_) { |
|
63 return false; |
|
64 } |
|
65 // Set proxy information if necessary. |
|
66 if (!proxy_host.empty()) { |
|
67 (*easy_setopt_)(curl_, CURLOPT_PROXY, proxy_host.c_str()); |
|
68 } else { |
|
69 std::cout << "SetProxy called with empty proxy host."; |
|
70 return false; |
|
71 } |
|
72 if (!proxy_userpwd.empty()) { |
|
73 (*easy_setopt_)(curl_, CURLOPT_PROXYUSERPWD, proxy_userpwd.c_str()); |
|
74 } else { |
|
75 std::cout << "SetProxy called with empty proxy username/password."; |
|
76 return false; |
|
77 } |
|
78 std::cout << "Set proxy host to " << proxy_host; |
|
79 return true; |
|
80 } |
|
81 |
|
82 bool LibcurlWrapper::AddFile(const string& upload_file_path, |
|
83 const string& basename) { |
|
84 if (!init_ok_) { |
|
85 return false; |
|
86 } |
|
87 std::cout << "Adding " << upload_file_path << " to form upload."; |
|
88 // Add form file. |
|
89 (*formadd_)(&formpost_, &lastptr_, |
|
90 CURLFORM_COPYNAME, basename.c_str(), |
|
91 CURLFORM_FILE, upload_file_path.c_str(), |
|
92 CURLFORM_END); |
|
93 |
|
94 return true; |
|
95 } |
|
96 |
|
97 // Callback to get the response data from server. |
|
98 static size_t WriteCallback(void *ptr, size_t size, |
|
99 size_t nmemb, void *userp) { |
|
100 if (!userp) |
|
101 return 0; |
|
102 |
|
103 string *response = reinterpret_cast<string *>(userp); |
|
104 size_t real_size = size * nmemb; |
|
105 response->append(reinterpret_cast<char *>(ptr), real_size); |
|
106 return real_size; |
|
107 } |
|
108 |
|
109 bool LibcurlWrapper::SendRequest(const string& url, |
|
110 const std::map<string, string>& parameters, |
|
111 string* server_response) { |
|
112 (*easy_setopt_)(curl_, CURLOPT_URL, url.c_str()); |
|
113 std::map<string, string>::const_iterator iter = parameters.begin(); |
|
114 for (; iter != parameters.end(); ++iter) |
|
115 (*formadd_)(&formpost_, &lastptr_, |
|
116 CURLFORM_COPYNAME, iter->first.c_str(), |
|
117 CURLFORM_COPYCONTENTS, iter->second.c_str(), |
|
118 CURLFORM_END); |
|
119 |
|
120 (*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_); |
|
121 if (server_response != NULL) { |
|
122 (*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback); |
|
123 (*easy_setopt_)(curl_, CURLOPT_WRITEDATA, |
|
124 reinterpret_cast<void *>(server_response)); |
|
125 } |
|
126 |
|
127 CURLcode err_code = CURLE_OK; |
|
128 err_code = (*easy_perform_)(curl_); |
|
129 easy_strerror_ = reinterpret_cast<const char* (*)(CURLcode)> |
|
130 (dlsym(curl_lib_, "curl_easy_strerror")); |
|
131 |
|
132 #ifndef NDEBUG |
|
133 if (err_code != CURLE_OK) |
|
134 fprintf(stderr, "Failed to send http request to %s, error: %s\n", |
|
135 url.c_str(), |
|
136 (*easy_strerror_)(err_code)); |
|
137 #endif |
|
138 if (headerlist_ != NULL) { |
|
139 (*slist_free_all_)(headerlist_); |
|
140 } |
|
141 |
|
142 (*easy_cleanup_)(curl_); |
|
143 if (formpost_ != NULL) { |
|
144 (*formfree_)(formpost_); |
|
145 } |
|
146 |
|
147 return err_code == CURLE_OK; |
|
148 } |
|
149 |
|
150 bool LibcurlWrapper::Init() { |
|
151 if (!init_ok_) { |
|
152 std::cout << "Init_OK was not true in LibcurlWrapper::Init(), check earlier log messages"; |
|
153 return false; |
|
154 } |
|
155 |
|
156 if (!SetFunctionPointers()) { |
|
157 std::cout << "Could not find function pointers"; |
|
158 init_ok_ = false; |
|
159 return false; |
|
160 } |
|
161 |
|
162 curl_ = (*easy_init_)(); |
|
163 |
|
164 last_curl_error_ = "No Error"; |
|
165 |
|
166 if (!curl_) { |
|
167 dlclose(curl_lib_); |
|
168 std::cout << "Curl initialization failed"; |
|
169 return false; |
|
170 } |
|
171 |
|
172 // Disable 100-continue header. |
|
173 char buf[] = "Expect:"; |
|
174 |
|
175 headerlist_ = (*slist_append_)(headerlist_, buf); |
|
176 (*easy_setopt_)(curl_, CURLOPT_HTTPHEADER, headerlist_); |
|
177 return true; |
|
178 } |
|
179 |
|
180 #define SET_AND_CHECK_FUNCTION_POINTER(var, function_name, type) \ |
|
181 var = reinterpret_cast<type>(dlsym(curl_lib_, function_name)); \ |
|
182 if (!var) { \ |
|
183 std::cout << "Could not find libcurl function " << function_name; \ |
|
184 init_ok_ = false; \ |
|
185 return false; \ |
|
186 } |
|
187 |
|
188 bool LibcurlWrapper::SetFunctionPointers() { |
|
189 |
|
190 SET_AND_CHECK_FUNCTION_POINTER(easy_init_, |
|
191 "curl_easy_init", |
|
192 CURL*(*)()); |
|
193 |
|
194 SET_AND_CHECK_FUNCTION_POINTER(easy_setopt_, |
|
195 "curl_easy_setopt", |
|
196 CURLcode(*)(CURL*, CURLoption, ...)); |
|
197 |
|
198 SET_AND_CHECK_FUNCTION_POINTER(formadd_, "curl_formadd", |
|
199 CURLFORMcode(*)(curl_httppost**, curl_httppost**, ...)); |
|
200 |
|
201 SET_AND_CHECK_FUNCTION_POINTER(slist_append_, "curl_slist_append", |
|
202 curl_slist*(*)(curl_slist*, const char*)); |
|
203 |
|
204 SET_AND_CHECK_FUNCTION_POINTER(easy_perform_, |
|
205 "curl_easy_perform", |
|
206 CURLcode(*)(CURL*)); |
|
207 |
|
208 SET_AND_CHECK_FUNCTION_POINTER(easy_cleanup_, |
|
209 "curl_easy_cleanup", |
|
210 void(*)(CURL*)); |
|
211 |
|
212 SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_, |
|
213 "curl_slist_free_all", |
|
214 void(*)(curl_slist*)); |
|
215 |
|
216 SET_AND_CHECK_FUNCTION_POINTER(formfree_, |
|
217 "curl_formfree", |
|
218 void(*)(curl_httppost*)); |
|
219 return true; |
|
220 } |
|
221 |
|
222 } |