LibreOffice Module desktop (master) 1
minidump.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10#include <desktop/minidump.hxx>
11#include <sal/log.hxx>
12
13#include <map>
14#include <fstream>
15#include <sstream>
16#include <string>
17
18#include <curl/curl.h>
19
20#ifdef _WIN32
21#include <memory>
22#include <windows.h>
23#endif
24
25const char kUserAgent[] = "Breakpad/1.0 (Linux)";
26
27static std::map<std::string, std::string> readStrings(std::istream& file)
28{
29 std::map<std::string, std::string> parameters;
30
31 // when file is not readable, the status eof would not be set
32 // better test of state is okay
33 while (file)
34 {
35 std::string line;
36 std::getline(file, line);
37 int sep = line.find('=');
38 if (sep >= 0)
39 {
40 std::string key = line.substr(0, sep);
41 std::string value = line.substr(sep + 1);
42 parameters[key] = value;
43 }
44 }
45
46 return parameters;
47}
48
49// Callback to get the response data from server.
50static size_t WriteCallback(void const *ptr, size_t size,
51 size_t nmemb, void *userp)
52{
53 if (!userp)
54 return 0;
55
56 std::string* response = static_cast<std::string *>(userp);
57 size_t real_size = size * nmemb;
58 response->append(static_cast<char const *>(ptr), real_size);
59 return real_size;
60}
61
62static void getProperty(const std::string& key, std::string& value,
63 std::map<std::string, std::string>& parameters)
64{
65 auto itr = parameters.find(key);
66 if (itr != parameters.end())
67 {
68 value = itr->second;
69 parameters.erase(itr);
70 }
71}
72
73static std::string generate_json(const std::map<std::string, std::string>& parameters)
74{
75 std::ostringstream stream;
76 stream << "{\n";
77 bool first = true;
78 for (auto itr = parameters.begin(), itrEnd = parameters.end(); itr != itrEnd; ++itr)
79 {
80 if (!first)
81 {
82 stream << ",\n";
83 }
84 first = false;
85 stream << "\"" << itr->first << "\": \"" << itr->second << "\"";
86 }
87 stream << "\n}";
88
89 return stream.str();
90}
91
92static bool uploadContent(std::map<std::string, std::string>& parameters, std::string& response)
93{
94 CURL* curl = curl_easy_init();
95 if (!curl)
96 return false;
97
98 std::string proxy, proxy_user_pwd, ca_certificate_file, file, url, version;
99
100 getProperty("Proxy", proxy, parameters);
101 getProperty("ProxyUserPW", proxy_user_pwd, parameters);
102 getProperty("CAFile", ca_certificate_file, parameters);
103
104 getProperty("DumpFile", file, parameters);
105 getProperty("URL", url, parameters);
106 getProperty("Version", version, parameters);
107 if (url.empty())
108 return false;
109
110 if (file.empty())
111 return false;
112
113 if (version.empty())
114 return false;
115
116 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
117 curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgent);
118 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
119 // Set proxy information if necessary.
120 if (!proxy.empty())
121 {
122 curl_easy_setopt(curl, CURLOPT_PROXY, proxy.c_str());
123
124 curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANYSAFE);
125
126 if (!proxy_user_pwd.empty())
127 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str());
128 else
129 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, ":");
130 }
131
132 if (!ca_certificate_file.empty())
133 curl_easy_setopt(curl, CURLOPT_CAINFO, ca_certificate_file.c_str());
134
135 curl_mime* mime = curl_mime_init(curl);
136 std::string additional_data = generate_json(parameters);
137 curl_mimepart* part = curl_mime_addpart(mime);
138 curl_mime_name(part, "AdditionalData");
139 curl_mime_data(part, additional_data.c_str(), CURL_ZERO_TERMINATED);
140
141 part = curl_mime_addpart(mime);
142 curl_mime_name(part, "Version");
143 curl_mime_data(part, version.c_str(), CURL_ZERO_TERMINATED);
144
145 part = curl_mime_addpart(mime);
146 curl_mime_name(part, "upload_file_minidump");
147 curl_mime_filedata(part, file.c_str());
148
149 curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
150
151
152 // Disable 100-continue header.
153 char buf[] = "Expect:";
154 curl_slist* headerlist = nullptr;
155 headerlist = curl_slist_append(headerlist, buf);
156 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
157
158 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
159 std::string response_body;
160 curl_easy_setopt(curl, CURLOPT_WRITEDATA,
161 static_cast<void *>(&response_body));
162
163 // Fail if 400+ is returned from the web server.
164 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
165
166 CURLcode cc = curl_easy_perform(curl);
167 long response_code;
168 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
169 SAL_WARN_IF(cc != CURLE_OK, "desktop",
170 "Failed to send http request to " <<
171 url.c_str() <<
172 ", error: " <<
173 curl_easy_strerror(cc));
174
175 if (headerlist != nullptr)
176 {
177 curl_slist_free_all(headerlist);
178 }
179
180 response = response_body;
181
182 if( CURLE_OK != cc )
183 return false;
184
185 return true;
186}
187
188namespace crashreport {
189
190bool readConfig(const std::string& iniPath, std::string * response)
191{
192#if defined _WIN32
193 std::wstring iniPathW;
194 const int nChars = MultiByteToWideChar(CP_UTF8, 0, iniPath.c_str(), -1, nullptr, 0);
195 auto buf = std::make_unique<wchar_t[]>(nChars);
196 if (MultiByteToWideChar(CP_UTF8, 0, iniPath.c_str(), -1, buf.get(), nChars) != 0)
197 iniPathW = buf.get();
198
199 std::ifstream file = iniPathW.empty() ? std::ifstream(iniPath) : std::ifstream(iniPathW);
200#else
201 std::ifstream file(iniPath);
202#endif
203 std::map<std::string, std::string> parameters = readStrings(file);
204
205 // make sure that at least the mandatory parameters are in there
206 if (parameters.find("DumpFile") == parameters.end())
207 {
208 if(response != nullptr)
209 *response = "ini file needs to contain a key DumpFile!";
210 return false;
211 }
212
213 if (parameters.find("Version") == parameters.end())
214 {
215 if (response != nullptr)
216 *response = "ini file needs to contain a key Version!";
217 return false;
218 }
219
220 if (parameters.find("URL") == parameters.end())
221 {
222 if (response != nullptr)
223 *response = "ini file needs to contain a key URL!";
224 return false;
225 }
226
227 if (response != nullptr)
228 return uploadContent(parameters, *response);
229
230 return true;
231}
232
233}
234
235/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Any value
Reference< XOutputStream > stream
#define SAL_WARN_IF(condition, area, stream)
static bool uploadContent(std::map< std::string, std::string > &parameters, std::string &response)
Definition: minidump.cxx:92
static size_t WriteCallback(void const *ptr, size_t size, size_t nmemb, void *userp)
Definition: minidump.cxx:50
static std::map< std::string, std::string > readStrings(std::istream &file)
Definition: minidump.cxx:27
static std::string generate_json(const std::map< std::string, std::string > &parameters)
Definition: minidump.cxx:73
const char kUserAgent[]
Definition: minidump.cxx:25
static void getProperty(const std::string &key, std::string &value, std::map< std::string, std::string > &parameters)
Definition: minidump.cxx:62
size
bool readConfig(const std::string &iniPath, std::string *response)
Read+Send, Test and send info from the Dump.ini .
Definition: minidump.cxx:190
line
constexpr OUStringLiteral first