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