1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include <desktop/minidump.hxx>
11 #include <sal/log.hxx>
18 #include <curl/curl.h>
20 #include <curlinit.hxx>
27 const char kUserAgent
[] = "Breakpad/1.0 (Linux)";
29 static std::map
<std::string
, std::string
> readStrings(std::istream
& file
)
31 std::map
<std::string
, std::string
> parameters
;
33 // when file is not readable, the status eof would not be set
34 // better test of state is okay
38 std::getline(file
, line
);
39 int sep
= line
.find('=');
42 std::string key
= line
.substr(0, sep
);
43 std::string value
= line
.substr(sep
+ 1);
44 parameters
[key
] = value
;
51 // Callback to get the response data from server.
52 static size_t WriteCallback(void const *ptr
, size_t size
,
53 size_t nmemb
, void *userp
)
58 std::string
* response
= static_cast<std::string
*>(userp
);
59 size_t real_size
= size
* nmemb
;
60 response
->append(static_cast<char const *>(ptr
), real_size
);
64 static void getProperty(const std::string
& key
, std::string
& value
,
65 std::map
<std::string
, std::string
>& parameters
)
67 auto itr
= parameters
.find(key
);
68 if (itr
!= parameters
.end())
71 parameters
.erase(itr
);
75 static std::string
generate_json(const std::map
<std::string
, std::string
>& parameters
)
77 std::ostringstream stream
;
80 for (auto itr
= parameters
.begin(), itrEnd
= parameters
.end(); itr
!= itrEnd
; ++itr
)
87 stream
<< "\"" << itr
->first
<< "\": \"" << itr
->second
<< "\"";
94 static bool uploadContent(std::map
<std::string
, std::string
>& parameters
, std::string
& response
)
96 CURL
* curl
= curl_easy_init();
100 ::InitCurl_easy(curl
);
102 std::string proxy
, proxy_user_pwd
, ca_certificate_file
, file
, url
, version
;
104 getProperty("Proxy", proxy
, parameters
);
105 getProperty("ProxyUserPW", proxy_user_pwd
, parameters
);
106 getProperty("CAFile", ca_certificate_file
, parameters
);
108 getProperty("DumpFile", file
, parameters
);
109 getProperty("URL", url
, parameters
);
110 getProperty("Version", version
, parameters
);
120 curl_easy_setopt(curl
, CURLOPT_URL
, url
.c_str());
121 curl_easy_setopt(curl
, CURLOPT_USERAGENT
, kUserAgent
);
122 curl_easy_setopt(curl
, CURLOPT_SSL_VERIFYPEER
, false);
123 // Set proxy information if necessary.
126 curl_easy_setopt(curl
, CURLOPT_PROXY
, proxy
.c_str());
128 curl_easy_setopt(curl
, CURLOPT_PROXYAUTH
, CURLAUTH_ANYSAFE
);
130 if (!proxy_user_pwd
.empty())
131 curl_easy_setopt(curl
, CURLOPT_PROXYUSERPWD
, proxy_user_pwd
.c_str());
133 curl_easy_setopt(curl
, CURLOPT_PROXYUSERPWD
, ":");
136 if (!ca_certificate_file
.empty())
137 curl_easy_setopt(curl
, CURLOPT_CAINFO
, ca_certificate_file
.c_str());
139 curl_mime
* mime
= curl_mime_init(curl
);
140 std::string additional_data
= generate_json(parameters
);
141 curl_mimepart
* part
= curl_mime_addpart(mime
);
142 curl_mime_name(part
, "AdditionalData");
143 curl_mime_data(part
, additional_data
.c_str(), CURL_ZERO_TERMINATED
);
145 part
= curl_mime_addpart(mime
);
146 curl_mime_name(part
, "Version");
147 curl_mime_data(part
, version
.c_str(), CURL_ZERO_TERMINATED
);
149 part
= curl_mime_addpart(mime
);
150 curl_mime_name(part
, "upload_file_minidump");
151 curl_mime_filedata(part
, file
.c_str());
153 curl_easy_setopt(curl
, CURLOPT_MIMEPOST
, mime
);
156 // Disable 100-continue header.
157 char buf
[] = "Expect:";
158 curl_slist
* headerlist
= nullptr;
159 headerlist
= curl_slist_append(headerlist
, buf
);
160 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, headerlist
);
162 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, WriteCallback
);
163 std::string response_body
;
164 curl_easy_setopt(curl
, CURLOPT_WRITEDATA
,
165 static_cast<void *>(&response_body
));
167 // Fail if 400+ is returned from the web server.
168 curl_easy_setopt(curl
, CURLOPT_FAILONERROR
, 1);
170 CURLcode cc
= curl_easy_perform(curl
);
172 curl_easy_getinfo(curl
, CURLINFO_RESPONSE_CODE
, &response_code
);
173 SAL_WARN_IF(cc
!= CURLE_OK
, "desktop",
174 "Failed to send http request to " <<
177 curl_easy_strerror(cc
));
179 if (headerlist
!= nullptr)
181 curl_slist_free_all(headerlist
);
184 response
= response_body
;
192 namespace crashreport
{
194 bool readConfig(const std::string
& iniPath
, std::string
* response
)
197 std::wstring iniPathW
;
198 const int nChars
= MultiByteToWideChar(CP_UTF8
, 0, iniPath
.c_str(), -1, nullptr, 0);
199 auto buf
= std::make_unique
<wchar_t[]>(nChars
);
200 if (MultiByteToWideChar(CP_UTF8
, 0, iniPath
.c_str(), -1, buf
.get(), nChars
) != 0)
201 iniPathW
= buf
.get();
203 std::ifstream file
= iniPathW
.empty() ? std::ifstream(iniPath
) : std::ifstream(iniPathW
);
205 std::ifstream
file(iniPath
);
207 std::map
<std::string
, std::string
> parameters
= readStrings(file
);
209 // make sure that at least the mandatory parameters are in there
210 if (parameters
.find("DumpFile") == parameters
.end())
212 if(response
!= nullptr)
213 *response
= "ini file needs to contain a key DumpFile!";
217 if (parameters
.find("Version") == parameters
.end())
219 if (response
!= nullptr)
220 *response
= "ini file needs to contain a key Version!";
224 if (parameters
.find("URL") == parameters
.end())
226 if (response
!= nullptr)
227 *response
= "ini file needs to contain a key URL!";
231 if (response
!= nullptr)
232 return uploadContent(parameters
, *response
);
239 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */