Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / desktop / source / minidump / minidump.cxx
blob8b96d2ff37f1605daa61ddc65ae32d6f00e175a3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <desktop/minidump.hxx>
12 #include <map>
13 #include <memory>
14 #include <fstream>
15 #include <sstream>
16 #include <string>
18 #include <curl/curl.h>
20 static const char kUserAgent[] = "Breakpad/1.0 (Linux)";
22 static std::map<std::string, std::string> readStrings(std::istream& file)
24 std::map<std::string, std::string> parameters;
26 // when file is not readable, the status eof would not be set
27 // better test of state is okay
28 while (file)
30 std::string line;
31 std::getline(file, line);
32 int sep = line.find('=');
33 if (sep >= 0)
35 std::string key = line.substr(0, sep);
36 std::string value = line.substr(sep + 1);
37 parameters[key] = value;
41 return parameters;
44 // Callback to get the response data from server.
45 static size_t WriteCallback(void const *ptr, size_t size,
46 size_t nmemb, void *userp)
48 if (!userp)
49 return 0;
51 std::string* response = static_cast<std::string *>(userp);
52 size_t real_size = size * nmemb;
53 response->append(static_cast<char const *>(ptr), real_size);
54 return real_size;
57 static void getProperty(const std::string& key, std::string& value,
58 std::map<std::string, std::string>& parameters)
60 auto itr = parameters.find(key);
61 if (itr != parameters.end())
63 value = itr->second;
64 parameters.erase(itr);
68 static std::string generate_json(const std::map<std::string, std::string>& parameters)
70 std::ostringstream stream;
71 stream << "{\n";
72 bool first = true;
73 for (auto itr = parameters.begin(), itrEnd = parameters.end(); itr != itrEnd; ++itr)
75 if (!first)
77 stream << ",\n";
79 first = false;
80 stream << "\"" << itr->first << "\": \"" << itr->second << "\"";
82 stream << "\n}";
84 return stream.str();
87 static bool uploadContent(std::map<std::string, std::string>& parameters, std::string& response)
89 CURL* curl = curl_easy_init();
90 if (!curl)
91 return false;
93 std::string proxy, proxy_user_pwd, ca_certificate_file, file, url, version;
95 getProperty("Proxy", proxy, parameters);
96 getProperty("ProxyUserPW", proxy_user_pwd, parameters);
97 getProperty("CAFile", ca_certificate_file, parameters);
99 getProperty("DumpFile", file, parameters);
100 getProperty("URL", url, parameters);
101 getProperty("Version", version, parameters);
102 if (url.empty())
103 return false;
105 if (file.empty())
106 return false;
108 if (version.empty())
109 return false;
111 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
112 curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgent);
113 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
114 // Set proxy information if necessary.
115 if (!proxy.empty())
117 curl_easy_setopt(curl, CURLOPT_PROXY, proxy.c_str());
119 curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANYSAFE);
121 if (!proxy_user_pwd.empty())
122 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str());
123 else
124 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, ":");
127 if (!ca_certificate_file.empty())
128 curl_easy_setopt(curl, CURLOPT_CAINFO, ca_certificate_file.c_str());
130 curl_httppost* formpost = nullptr;
131 curl_httppost* lastptr = nullptr;
132 std::string additional_data = generate_json(parameters);
133 curl_formadd(&formpost, &lastptr,
134 CURLFORM_COPYNAME, "AdditionalData",
135 CURLFORM_COPYCONTENTS, additional_data.c_str(),
136 CURLFORM_END);
138 curl_formadd(&formpost, &lastptr,
139 CURLFORM_COPYNAME, "Version",
140 CURLFORM_COPYCONTENTS, version.c_str(),
141 CURLFORM_END);
143 std::string response_body;
144 long response_code;
145 curl_formadd(&formpost, &lastptr,
146 CURLFORM_COPYNAME, "upload_file_minidump",
147 CURLFORM_FILE, file.c_str(),
148 CURLFORM_END);
150 curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
153 // Disable 100-continue header.
154 char buf[] = "Expect:";
155 curl_slist* headerlist = nullptr;
156 headerlist = curl_slist_append(headerlist, buf);
157 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
159 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
160 curl_easy_setopt(curl, CURLOPT_WRITEDATA,
161 static_cast<void *>(&response_body));
163 // Fail if 400+ is returned from the web server.
164 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
166 CURLcode cc = curl_easy_perform(curl);
167 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
168 #ifndef NDEBUG
169 if (cc != CURLE_OK)
170 fprintf(stderr, "Failed to send http request to %s, error: %s\n",
171 url.c_str(),
172 curl_easy_strerror(cc));
173 #endif
175 if (formpost != nullptr)
177 curl_formfree(formpost);
179 if (headerlist != nullptr)
181 curl_slist_free_all(headerlist);
184 response = response_body;
186 if( CURLE_OK != cc )
187 return false;
189 return true;
192 namespace crashreport {
194 bool readConfig(const std::string& iniPath, std::string * response)
196 std::ifstream file(iniPath);
197 std::map<std::string, std::string> parameters = readStrings(file);
199 // make sure that at least the mandatory parameters are in there
200 if (parameters.find("DumpFile") == parameters.end())
202 if(response != nullptr)
203 *response = "ini file needs to contain a key DumpFile!";
204 return false;
207 if (parameters.find("Version") == parameters.end())
209 if (response != nullptr)
210 *response = "ini file needs to contain a key Version!";
211 return false;
214 if (parameters.find("URL") == parameters.end())
216 if (response != nullptr)
217 *response = "ini file needs to contain a key URL!";
218 return false;
221 if (response != nullptr)
222 return uploadContent(parameters, *response);
224 return true;
229 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */