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 <memory>
14 #include <fstream>
15 #include <sstream>
16 #include <string>
17 
18 #include <curl/curl.h>
19 
20 static const char kUserAgent[] = "Breakpad/1.0 (Linux)";
21 
22 static std::map<std::string, std::string> readStrings(std::istream& file)
23 {
24  std::map<std::string, std::string> parameters;
25 
26  // when file is not readable, the status eof would not be set
27  // better test of state is okay
28  while (file)
29  {
30  std::string line;
31  std::getline(file, line);
32  int sep = line.find('=');
33  if (sep >= 0)
34  {
35  std::string key = line.substr(0, sep);
36  std::string value = line.substr(sep + 1);
37  parameters[key] = value;
38  }
39  }
40 
41  return parameters;
42 }
43 
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)
47 {
48  if (!userp)
49  return 0;
50 
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;
55 }
56 
57 static void getProperty(const std::string& key, std::string& value,
58  std::map<std::string, std::string>& parameters)
59 {
60  auto itr = parameters.find(key);
61  if (itr != parameters.end())
62  {
63  value = itr->second;
64  parameters.erase(itr);
65  }
66 }
67 
68 static std::string generate_json(const std::map<std::string, std::string>& parameters)
69 {
70  std::ostringstream stream;
71  stream << "{\n";
72  bool first = true;
73  for (auto itr = parameters.begin(), itrEnd = parameters.end(); itr != itrEnd; ++itr)
74  {
75  if (!first)
76  {
77  stream << ",\n";
78  }
79  first = false;
80  stream << "\"" << itr->first << "\": \"" << itr->second << "\"";
81  }
82  stream << "\n}";
83 
84  return stream.str();
85 }
86 
87 static bool uploadContent(std::map<std::string, std::string>& parameters, std::string& response)
88 {
89  CURL* curl = curl_easy_init();
90  if (!curl)
91  return false;
92 
93  std::string proxy, proxy_user_pwd, ca_certificate_file, file, url, version;
94 
95  getProperty("Proxy", proxy, parameters);
96  getProperty("ProxyUserPW", proxy_user_pwd, parameters);
97  getProperty("CAFile", ca_certificate_file, parameters);
98 
99  getProperty("DumpFile", file, parameters);
100  getProperty("URL", url, parameters);
101  getProperty("Version", version, parameters);
102  if (url.empty())
103  return false;
104 
105  if (file.empty())
106  return false;
107 
108  if (version.empty())
109  return false;
110 
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())
116  {
117  curl_easy_setopt(curl, CURLOPT_PROXY, proxy.c_str());
118 
119  curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANYSAFE);
120 
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, ":");
125  }
126 
127  if (!ca_certificate_file.empty())
128  curl_easy_setopt(curl, CURLOPT_CAINFO, ca_certificate_file.c_str());
129 
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);
137 
138  curl_formadd(&formpost, &lastptr,
139  CURLFORM_COPYNAME, "Version",
140  CURLFORM_COPYCONTENTS, version.c_str(),
141  CURLFORM_END);
142 
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);
149 
150  curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
151 
152 
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);
158 
159  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
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  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
174 
175  if (formpost != nullptr)
176  {
177  curl_formfree(formpost);
178  }
179  if (headerlist != nullptr)
180  {
181  curl_slist_free_all(headerlist);
182  }
183 
184  response = response_body;
185 
186  if( CURLE_OK != cc )
187  return false;
188 
189  return true;
190 }
191 
192 namespace crashreport {
193 
194 bool readConfig(const std::string& iniPath, std::string * response)
195 {
196  std::ifstream file(iniPath);
197  std::map<std::string, std::string> parameters = readStrings(file);
198 
199  // make sure that at least the mandatory parameters are in there
200  if (parameters.find("DumpFile") == parameters.end())
201  {
202  if(response != nullptr)
203  *response = "ini file needs to contain a key DumpFile!";
204  return false;
205  }
206 
207  if (parameters.find("Version") == parameters.end())
208  {
209  if (response != nullptr)
210  *response = "ini file needs to contain a key Version!";
211  return false;
212  }
213 
214  if (parameters.find("URL") == parameters.end())
215  {
216  if (response != nullptr)
217  *response = "ini file needs to contain a key URL!";
218  return false;
219  }
220 
221  if (response != nullptr)
222  return uploadContent(parameters, *response);
223 
224  return true;
225 }
226 
227 }
228 
229 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
IJScriptValueObject VARIANT value
static size_t WriteCallback(void const *ptr, size_t size, size_t nmemb, void *userp)
Definition: minidump.cxx:45
static void getProperty(const std::string &key, std::string &value, std::map< std::string, std::string > &parameters)
Definition: minidump.cxx:57
static std::string generate_json(const std::map< std::string, std::string > &parameters)
Definition: minidump.cxx:68
static const char kUserAgent[]
Definition: minidump.cxx:20
tools::SvRef< SotStorageStream > stream
bool readConfig(const std::string &iniPath, std::string *response)
Read+Send, Test and send info from the Dump.ini .
Definition: minidump.cxx:194
static bool uploadContent(std::map< std::string, std::string > &parameters, std::string &response)
Definition: minidump.cxx:87
static std::map< std::string, std::string > readStrings(std::istream &file)
Definition: minidump.cxx:22
void SAL_CALL first(const css::awt::SpinEvent &rEvent) override