xref: /aosp_15_r20/external/google-breakpad/src/common/linux/http_upload.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1*9712c20fSFrederick Mayle // Copyright 2006 Google LLC
2*9712c20fSFrederick Mayle //
3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without
4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are
5*9712c20fSFrederick Mayle // met:
6*9712c20fSFrederick Mayle //
7*9712c20fSFrederick Mayle //     * Redistributions of source code must retain the above copyright
8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer.
9*9712c20fSFrederick Mayle //     * Redistributions in binary form must reproduce the above
10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer
11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the
12*9712c20fSFrederick Mayle // distribution.
13*9712c20fSFrederick Mayle //     * Neither the name of Google LLC nor the names of its
14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from
15*9712c20fSFrederick Mayle // this software without specific prior written permission.
16*9712c20fSFrederick Mayle //
17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*9712c20fSFrederick Mayle 
29*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
30*9712c20fSFrederick Mayle #include <config.h>  // Must come first
31*9712c20fSFrederick Mayle #endif
32*9712c20fSFrederick Mayle 
33*9712c20fSFrederick Mayle #include "common/linux/http_upload.h"
34*9712c20fSFrederick Mayle 
35*9712c20fSFrederick Mayle #include <assert.h>
36*9712c20fSFrederick Mayle #include <dlfcn.h>
37*9712c20fSFrederick Mayle #include "third_party/curl/curl.h"
38*9712c20fSFrederick Mayle 
39*9712c20fSFrederick Mayle namespace {
40*9712c20fSFrederick Mayle 
41*9712c20fSFrederick Mayle // Callback to get the response data from server.
WriteCallback(void * ptr,size_t size,size_t nmemb,void * userp)42*9712c20fSFrederick Mayle static size_t WriteCallback(void* ptr, size_t size,
43*9712c20fSFrederick Mayle                             size_t nmemb, void* userp) {
44*9712c20fSFrederick Mayle   if (!userp)
45*9712c20fSFrederick Mayle     return 0;
46*9712c20fSFrederick Mayle 
47*9712c20fSFrederick Mayle   string* response = reinterpret_cast<string*>(userp);
48*9712c20fSFrederick Mayle   size_t real_size = size * nmemb;
49*9712c20fSFrederick Mayle   response->append(reinterpret_cast<char*>(ptr), real_size);
50*9712c20fSFrederick Mayle   return real_size;
51*9712c20fSFrederick Mayle }
52*9712c20fSFrederick Mayle 
53*9712c20fSFrederick Mayle }  // namespace
54*9712c20fSFrederick Mayle 
55*9712c20fSFrederick Mayle namespace google_breakpad {
56*9712c20fSFrederick Mayle 
57*9712c20fSFrederick Mayle static const char kUserAgent[] = "Breakpad/1.0 (Linux)";
58*9712c20fSFrederick Mayle 
59*9712c20fSFrederick Mayle // static
SendRequest(const string & url,const map<string,string> & parameters,const map<string,string> & files,const string & proxy,const string & proxy_user_pwd,const string & ca_certificate_file,string * response_body,long * response_code,string * error_description)60*9712c20fSFrederick Mayle bool HTTPUpload::SendRequest(const string& url,
61*9712c20fSFrederick Mayle                              const map<string, string>& parameters,
62*9712c20fSFrederick Mayle                              const map<string, string>& files,
63*9712c20fSFrederick Mayle                              const string& proxy,
64*9712c20fSFrederick Mayle                              const string& proxy_user_pwd,
65*9712c20fSFrederick Mayle                              const string& ca_certificate_file,
66*9712c20fSFrederick Mayle                              string* response_body,
67*9712c20fSFrederick Mayle                              long* response_code,
68*9712c20fSFrederick Mayle                              string* error_description) {
69*9712c20fSFrederick Mayle   if (response_code != NULL)
70*9712c20fSFrederick Mayle     *response_code = 0;
71*9712c20fSFrederick Mayle 
72*9712c20fSFrederick Mayle   if (!CheckParameters(parameters))
73*9712c20fSFrederick Mayle     return false;
74*9712c20fSFrederick Mayle 
75*9712c20fSFrederick Mayle   // We may have been linked statically; if curl_easy_init is in the
76*9712c20fSFrederick Mayle   // current binary, no need to search for a dynamic version.
77*9712c20fSFrederick Mayle   void* curl_lib = dlopen(NULL, RTLD_NOW);
78*9712c20fSFrederick Mayle   if (!CheckCurlLib(curl_lib)) {
79*9712c20fSFrederick Mayle     fprintf(stderr,
80*9712c20fSFrederick Mayle             "Failed to open curl lib from binary, use libcurl.so instead\n");
81*9712c20fSFrederick Mayle     dlerror();  // Clear dlerror before attempting to open libraries.
82*9712c20fSFrederick Mayle     dlclose(curl_lib);
83*9712c20fSFrederick Mayle     curl_lib = NULL;
84*9712c20fSFrederick Mayle   }
85*9712c20fSFrederick Mayle   if (!curl_lib) {
86*9712c20fSFrederick Mayle     curl_lib = dlopen("libcurl.so", RTLD_NOW);
87*9712c20fSFrederick Mayle   }
88*9712c20fSFrederick Mayle   if (!curl_lib) {
89*9712c20fSFrederick Mayle     if (error_description != NULL)
90*9712c20fSFrederick Mayle       *error_description = dlerror();
91*9712c20fSFrederick Mayle     curl_lib = dlopen("libcurl.so.4", RTLD_NOW);
92*9712c20fSFrederick Mayle   }
93*9712c20fSFrederick Mayle   if (!curl_lib) {
94*9712c20fSFrederick Mayle     // Debian gives libcurl a different name when it is built against GnuTLS
95*9712c20fSFrederick Mayle     // instead of OpenSSL.
96*9712c20fSFrederick Mayle     curl_lib = dlopen("libcurl-gnutls.so.4", RTLD_NOW);
97*9712c20fSFrederick Mayle   }
98*9712c20fSFrederick Mayle   if (!curl_lib) {
99*9712c20fSFrederick Mayle     curl_lib = dlopen("libcurl.so.3", RTLD_NOW);
100*9712c20fSFrederick Mayle   }
101*9712c20fSFrederick Mayle   if (!curl_lib) {
102*9712c20fSFrederick Mayle     return false;
103*9712c20fSFrederick Mayle   }
104*9712c20fSFrederick Mayle 
105*9712c20fSFrederick Mayle   CURL* (*curl_easy_init)(void);
106*9712c20fSFrederick Mayle   *(void**) (&curl_easy_init) = dlsym(curl_lib, "curl_easy_init");
107*9712c20fSFrederick Mayle   CURL* curl = (*curl_easy_init)();
108*9712c20fSFrederick Mayle   if (error_description != NULL)
109*9712c20fSFrederick Mayle     *error_description = "No Error";
110*9712c20fSFrederick Mayle 
111*9712c20fSFrederick Mayle   if (!curl) {
112*9712c20fSFrederick Mayle     dlclose(curl_lib);
113*9712c20fSFrederick Mayle     return false;
114*9712c20fSFrederick Mayle   }
115*9712c20fSFrederick Mayle 
116*9712c20fSFrederick Mayle   CURLcode err_code = CURLE_OK;
117*9712c20fSFrederick Mayle   CURLcode (*curl_easy_setopt)(CURL*, CURLoption, ...);
118*9712c20fSFrederick Mayle   *(void**) (&curl_easy_setopt) = dlsym(curl_lib, "curl_easy_setopt");
119*9712c20fSFrederick Mayle   (*curl_easy_setopt)(curl, CURLOPT_URL, url.c_str());
120*9712c20fSFrederick Mayle   (*curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent);
121*9712c20fSFrederick Mayle   // Support multithread by disabling timeout handling, would get SIGSEGV with
122*9712c20fSFrederick Mayle   // Curl_resolv_timeout in stack trace otherwise.
123*9712c20fSFrederick Mayle   // See https://curl.haxx.se/libcurl/c/threadsafe.html
124*9712c20fSFrederick Mayle   (*curl_easy_setopt)(curl, CURLOPT_NOSIGNAL, 1);
125*9712c20fSFrederick Mayle   // Set proxy information if necessary.
126*9712c20fSFrederick Mayle   if (!proxy.empty())
127*9712c20fSFrederick Mayle     (*curl_easy_setopt)(curl, CURLOPT_PROXY, proxy.c_str());
128*9712c20fSFrederick Mayle   if (!proxy_user_pwd.empty())
129*9712c20fSFrederick Mayle     (*curl_easy_setopt)(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str());
130*9712c20fSFrederick Mayle 
131*9712c20fSFrederick Mayle   if (!ca_certificate_file.empty())
132*9712c20fSFrederick Mayle     (*curl_easy_setopt)(curl, CURLOPT_CAINFO, ca_certificate_file.c_str());
133*9712c20fSFrederick Mayle 
134*9712c20fSFrederick Mayle   struct curl_httppost* formpost = NULL;
135*9712c20fSFrederick Mayle   struct curl_httppost* lastptr = NULL;
136*9712c20fSFrederick Mayle   // Add form data.
137*9712c20fSFrederick Mayle   CURLFORMcode (*curl_formadd)(struct curl_httppost**, struct curl_httppost**, ...);
138*9712c20fSFrederick Mayle   *(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd");
139*9712c20fSFrederick Mayle   map<string, string>::const_iterator iter = parameters.begin();
140*9712c20fSFrederick Mayle   for (; iter != parameters.end(); ++iter)
141*9712c20fSFrederick Mayle     (*curl_formadd)(&formpost, &lastptr,
142*9712c20fSFrederick Mayle                  CURLFORM_COPYNAME, iter->first.c_str(),
143*9712c20fSFrederick Mayle                  CURLFORM_COPYCONTENTS, iter->second.c_str(),
144*9712c20fSFrederick Mayle                  CURLFORM_END);
145*9712c20fSFrederick Mayle 
146*9712c20fSFrederick Mayle   // Add form files.
147*9712c20fSFrederick Mayle   for (iter = files.begin(); iter != files.end(); ++iter) {
148*9712c20fSFrederick Mayle     (*curl_formadd)(&formpost, &lastptr,
149*9712c20fSFrederick Mayle                  CURLFORM_COPYNAME, iter->first.c_str(),
150*9712c20fSFrederick Mayle                  CURLFORM_FILE, iter->second.c_str(),
151*9712c20fSFrederick Mayle                  CURLFORM_END);
152*9712c20fSFrederick Mayle   }
153*9712c20fSFrederick Mayle 
154*9712c20fSFrederick Mayle   (*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost);
155*9712c20fSFrederick Mayle 
156*9712c20fSFrederick Mayle   // Disable 100-continue header.
157*9712c20fSFrederick Mayle   struct curl_slist* headerlist = NULL;
158*9712c20fSFrederick Mayle   char buf[] = "Expect:";
159*9712c20fSFrederick Mayle   struct curl_slist* (*curl_slist_append)(struct curl_slist*, const char*);
160*9712c20fSFrederick Mayle   *(void**) (&curl_slist_append) = dlsym(curl_lib, "curl_slist_append");
161*9712c20fSFrederick Mayle   headerlist = (*curl_slist_append)(headerlist, buf);
162*9712c20fSFrederick Mayle   (*curl_easy_setopt)(curl, CURLOPT_HTTPHEADER, headerlist);
163*9712c20fSFrederick Mayle 
164*9712c20fSFrederick Mayle   if (response_body != NULL) {
165*9712c20fSFrederick Mayle     (*curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
166*9712c20fSFrederick Mayle     (*curl_easy_setopt)(curl, CURLOPT_WRITEDATA,
167*9712c20fSFrederick Mayle                      reinterpret_cast<void*>(response_body));
168*9712c20fSFrederick Mayle   }
169*9712c20fSFrederick Mayle 
170*9712c20fSFrederick Mayle   // Fail if 400+ is returned from the web server.
171*9712c20fSFrederick Mayle   (*curl_easy_setopt)(curl, CURLOPT_FAILONERROR, 1);
172*9712c20fSFrederick Mayle 
173*9712c20fSFrederick Mayle   CURLcode (*curl_easy_perform)(CURL*);
174*9712c20fSFrederick Mayle   *(void**) (&curl_easy_perform) = dlsym(curl_lib, "curl_easy_perform");
175*9712c20fSFrederick Mayle   err_code = (*curl_easy_perform)(curl);
176*9712c20fSFrederick Mayle   if (response_code != NULL) {
177*9712c20fSFrederick Mayle     CURLcode (*curl_easy_getinfo)(CURL*, CURLINFO, ...);
178*9712c20fSFrederick Mayle     *(void**) (&curl_easy_getinfo) = dlsym(curl_lib, "curl_easy_getinfo");
179*9712c20fSFrederick Mayle     (*curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code);
180*9712c20fSFrederick Mayle   }
181*9712c20fSFrederick Mayle   const char* (*curl_easy_strerror)(CURLcode);
182*9712c20fSFrederick Mayle   *(void**) (&curl_easy_strerror) = dlsym(curl_lib, "curl_easy_strerror");
183*9712c20fSFrederick Mayle #ifndef NDEBUG
184*9712c20fSFrederick Mayle   if (err_code != CURLE_OK)
185*9712c20fSFrederick Mayle     fprintf(stderr, "Failed to send http request to %s, error: %s\n",
186*9712c20fSFrederick Mayle             url.c_str(),
187*9712c20fSFrederick Mayle             (*curl_easy_strerror)(err_code));
188*9712c20fSFrederick Mayle #endif
189*9712c20fSFrederick Mayle   if (error_description != NULL)
190*9712c20fSFrederick Mayle     *error_description = (*curl_easy_strerror)(err_code);
191*9712c20fSFrederick Mayle 
192*9712c20fSFrederick Mayle   void (*curl_easy_cleanup)(CURL*);
193*9712c20fSFrederick Mayle   *(void**) (&curl_easy_cleanup) = dlsym(curl_lib, "curl_easy_cleanup");
194*9712c20fSFrederick Mayle   (*curl_easy_cleanup)(curl);
195*9712c20fSFrederick Mayle   if (formpost != NULL) {
196*9712c20fSFrederick Mayle     void (*curl_formfree)(struct curl_httppost*);
197*9712c20fSFrederick Mayle     *(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree");
198*9712c20fSFrederick Mayle     (*curl_formfree)(formpost);
199*9712c20fSFrederick Mayle   }
200*9712c20fSFrederick Mayle   if (headerlist != NULL) {
201*9712c20fSFrederick Mayle     void (*curl_slist_free_all)(struct curl_slist*);
202*9712c20fSFrederick Mayle     *(void**) (&curl_slist_free_all) = dlsym(curl_lib, "curl_slist_free_all");
203*9712c20fSFrederick Mayle     (*curl_slist_free_all)(headerlist);
204*9712c20fSFrederick Mayle   }
205*9712c20fSFrederick Mayle   dlclose(curl_lib);
206*9712c20fSFrederick Mayle   return err_code == CURLE_OK;
207*9712c20fSFrederick Mayle }
208*9712c20fSFrederick Mayle 
209*9712c20fSFrederick Mayle // static
CheckCurlLib(void * curl_lib)210*9712c20fSFrederick Mayle bool HTTPUpload::CheckCurlLib(void* curl_lib) {
211*9712c20fSFrederick Mayle   return curl_lib &&
212*9712c20fSFrederick Mayle       dlsym(curl_lib, "curl_easy_init") &&
213*9712c20fSFrederick Mayle       dlsym(curl_lib, "curl_easy_setopt");
214*9712c20fSFrederick Mayle }
215*9712c20fSFrederick Mayle 
216*9712c20fSFrederick Mayle // static
CheckParameters(const map<string,string> & parameters)217*9712c20fSFrederick Mayle bool HTTPUpload::CheckParameters(const map<string, string>& parameters) {
218*9712c20fSFrederick Mayle   for (map<string, string>::const_iterator pos = parameters.begin();
219*9712c20fSFrederick Mayle        pos != parameters.end(); ++pos) {
220*9712c20fSFrederick Mayle     const string& str = pos->first;
221*9712c20fSFrederick Mayle     if (str.size() == 0)
222*9712c20fSFrederick Mayle       return false;  // disallow empty parameter names
223*9712c20fSFrederick Mayle     for (unsigned int i = 0; i < str.size(); ++i) {
224*9712c20fSFrederick Mayle       int c = str[i];
225*9712c20fSFrederick Mayle       if (c < 32 || c == '"' || c > 127) {
226*9712c20fSFrederick Mayle         return false;
227*9712c20fSFrederick Mayle       }
228*9712c20fSFrederick Mayle     }
229*9712c20fSFrederick Mayle   }
230*9712c20fSFrederick Mayle   return true;
231*9712c20fSFrederick Mayle }
232*9712c20fSFrederick Mayle 
233*9712c20fSFrederick Mayle }  // namespace google_breakpad
234