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