diff options
author | Markus Mohrhard <markus.mohrhard@googlemail.com> | 2016-06-02 19:15:47 +0200 |
---|---|---|
committer | Markus Mohrhard <markus.mohrhard@googlemail.com> | 2016-06-04 08:41:56 +0000 |
commit | 2d1fc99275315bd6f45c1b73540f2b55e94bef9f (patch) | |
tree | 4a8e5c858a086efad4c6c3723f1ac5a5125395b4 | |
parent | e95be04a73e977022455335d7cbf56804638f761 (diff) |
extract the minidump uploader code into a static lib
The plan for the near future is to still ship the executable but replace
the interal use if possible with using the static library.
At some point when it is not needed for debugging anymore and everything
works correctly we should only build the uploader executable in dev
configurations. The huge disadvantage of the interal solution is that it
is nearly impossible for a user to upload a crash report if LibO starts
working correctly. Also LibO overwrites the file with the information
after the upload whereas the executable does not.
Change-Id: Ib9854946be3a34e580964c18e1a9c0cce16221d1
Reviewed-on: https://gerrit.libreoffice.org/25862
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
Tested-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
-rw-r--r-- | desktop/Executable_minidump_upload.mk | 4 | ||||
-rw-r--r-- | desktop/Module_desktop.mk | 4 | ||||
-rw-r--r-- | desktop/StaticLibrary_minidump.mk | 19 | ||||
-rw-r--r-- | desktop/source/minidump/minidump.cxx | 208 | ||||
-rw-r--r-- | desktop/source/minidump/minidump.hxx | 19 | ||||
-rw-r--r-- | desktop/source/minidump/minidump_upload.cxx | 205 |
6 files changed, 258 insertions, 201 deletions
diff --git a/desktop/Executable_minidump_upload.mk b/desktop/Executable_minidump_upload.mk index 7fe9546a9624..2c0202371a63 100644 --- a/desktop/Executable_minidump_upload.mk +++ b/desktop/Executable_minidump_upload.mk @@ -13,6 +13,10 @@ $(eval $(call gb_Executable_use_libraries,minidump_upload,\ sal \ )) +$(eval $(call gb_Executable_use_static_libraries,minidump_upload,\ + minidump \ +)) + $(eval $(call gb_Executable_use_external,minidump_upload,curl)) $(eval $(call gb_Executable_add_exception_objects,minidump_upload,\ diff --git a/desktop/Module_desktop.mk b/desktop/Module_desktop.mk index 430d48fb45ab..22d3647c1386 100644 --- a/desktop/Module_desktop.mk +++ b/desktop/Module_desktop.mk @@ -17,7 +17,9 @@ $(eval $(call gb_Module_add_targets,desktop,\ Library_deploymentmisc \ Library_offacc \ Library_sofficeapp \ - $(if $(ENABLE_BREAKPAD),Library_crashreport) \ + $(if $(ENABLE_BREAKPAD), \ + Library_crashreport \ + StaticLibrary_minidump) \ $(if $(ENABLE_HEADLESS),,Library_spl) \ Package_branding \ $(if $(CUSTOM_BRAND_DIR),Package_branding_custom) \ diff --git a/desktop/StaticLibrary_minidump.mk b/desktop/StaticLibrary_minidump.mk new file mode 100644 index 000000000000..70cab1a26d0e --- /dev/null +++ b/desktop/StaticLibrary_minidump.mk @@ -0,0 +1,19 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_StaticLibrary_StaticLibrary,minidump)) + +$(eval $(call gb_StaticLibrary_use_external,minidump,curl)) + +$(eval $(call gb_StaticLibrary_add_exception_objects,minidump,\ + desktop/source/minidump/minidump \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/desktop/source/minidump/minidump.cxx b/desktop/source/minidump/minidump.cxx new file mode 100644 index 000000000000..371d17cdd3f0 --- /dev/null +++ b/desktop/source/minidump/minidump.cxx @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "minidump.hxx" + +#include <map> +#include <memory> +#include <iostream> +#include <fstream> +#include <sstream> + +#include <curl/curl.h> + +static const char kUserAgent[] = "Breakpad/1.0 (Linux)"; + +std::map<std::string, std::string> readStrings(std::istream& file) +{ + std::map<std::string, std::string> parameters; + + while (!file.eof()) + { + std::string line; + std::getline(file, line); + int sep = line.find('='); + if (sep >= 0) + { + std::string key = line.substr(0, sep); + std::string value = line.substr(sep + 1); + parameters[key] = value; + } + } + + return parameters; +} + +// Callback to get the response data from server. +static size_t WriteCallback(void *ptr, size_t size, + size_t nmemb, void *userp) +{ + if (!userp) + return 0; + + std::string* response = static_cast<std::string *>(userp); + size_t real_size = size * nmemb; + response->append(static_cast<char *>(ptr), real_size); + return real_size; +} + +void getProperty(const std::string& key, std::string& value, + std::map<std::string, std::string>& parameters) +{ + auto itr = parameters.find(key); + if (itr != parameters.end()) + { + value = itr->second; + parameters.erase(itr); + } +} + +std::string generate_json(const std::map<std::string, std::string>& parameters) +{ + std::ostringstream stream; + stream << "{\n"; + bool first = true; + for (auto itr = parameters.begin(), itrEnd = parameters.end(); itr != itrEnd; ++itr) + { + if (!first) + { + stream << ",\n"; + } + first = false; + stream << "\"" << itr->first << "\": \"" << itr->second << "\""; + } + stream << "\n}"; + + return stream.str(); +} + +bool uploadContent(std::map<std::string, std::string>& parameters) +{ + CURL* curl = curl_easy_init(); + if (!curl) + return false; + + std::string proxy, proxy_user_pwd, ca_certificate_file, file, url, version; + + getProperty("Proxy", proxy, parameters); + getProperty("ProxyUserPW", proxy_user_pwd, parameters); + getProperty("CAFile", ca_certificate_file, parameters); + + getProperty("DumpFile", file, parameters); + getProperty("URL", url, parameters); + getProperty("Version", version, parameters); + if (url.empty()) + return false; + + if (file.empty()) + return false; + + if (version.empty()) + return false; + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgent); + // Set proxy information if necessary. + if (!proxy.empty()) + curl_easy_setopt(curl, CURLOPT_PROXY, proxy.c_str()); + if (!proxy_user_pwd.empty()) + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str()); + + if (!ca_certificate_file.empty()) + curl_easy_setopt(curl, CURLOPT_CAINFO, ca_certificate_file.c_str()); + + curl_httppost* formpost = nullptr; + curl_httppost* lastptr = nullptr; + std::string additional_data = generate_json(parameters); + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "AdditionalData", + CURLFORM_COPYCONTENTS, additional_data.c_str(), + CURLFORM_END); + + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "Version", + CURLFORM_COPYCONTENTS, version.c_str(), + CURLFORM_END); + + std::string response_body; + long response_code; + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "upload_file_minidump", + CURLFORM_FILE, file.c_str(), + CURLFORM_END); + + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + + + // Disable 100-continue header. + char buf[] = "Expect:"; + curl_slist* headerlist = nullptr; + headerlist = curl_slist_append(headerlist, buf); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, + static_cast<void *>(&response_body)); + + // Fail if 400+ is returned from the web server. + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); + + CURLcode cc = curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); +#ifndef NDEBUG + if (cc != CURLE_OK) + fprintf(stderr, "Failed to send http request to %s, error: %s\n", + url.c_str(), + curl_easy_strerror(cc)); +#endif + + const char* error_description = curl_easy_strerror(cc); + + if (formpost != nullptr) + { + curl_formfree(formpost); + } + if (headerlist != nullptr) + { + curl_slist_free_all(headerlist); + } + + std::cerr << response_body << " " << error_description << std::endl; + + + if( CURLE_OK != cc ) + return false; + + return true; +} + +bool readConfig(const std::string& iniPath) +{ + std::ifstream file(iniPath); + std::map<std::string, std::string> parameters = readStrings(file); + + // make sure that at least the mandatory parameters are in there + if (parameters.find("DumpFile") == parameters.end()) + { + std::cerr << "ini file needs to contain a key DumpFile!"; + return false; + } + + if (parameters.find("Version") == parameters.end()) + { + std::cerr << "ini file needs to contain a key Version!"; + return false; + } + + uploadContent(parameters); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/minidump/minidump.hxx b/desktop/source/minidump/minidump.hxx new file mode 100644 index 000000000000..21d52e80ddae --- /dev/null +++ b/desktop/source/minidump/minidump.hxx @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_DESKTOP_MINIDUMP_MINIDUMP_HXX +#define INCLUDED_DESKTOP_MINIDUMP_MINIDUMP_HXX + +#include <string> + +bool readConfig(const std::string& iniPath); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/minidump/minidump_upload.cxx b/desktop/source/minidump/minidump_upload.cxx index 30eaaaa0d39c..7f8d6170f14b 100644 --- a/desktop/source/minidump/minidump_upload.cxx +++ b/desktop/source/minidump/minidump_upload.cxx @@ -7,207 +7,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include <string> -#include <map> -#include <memory> -#include <iostream> -#include <fstream> -#include <sstream> +#include "minidump.hxx" -#include <curl/curl.h> +#include<iostream> -static const char kUserAgent[] = "Breakpad/1.0 (Linux)"; - -std::map<std::string, std::string> readStrings(std::istream& file) -{ - std::map<std::string, std::string> parameters; - - - while (!file.eof()) - { - std::string line; - std::getline(file, line); - int sep = line.find('='); - if (sep >= 0) - { - std::string key = line.substr(0, sep); - std::string value = line.substr(sep + 1); - parameters[key] = value; - } - } - - return parameters; -} - -// Callback to get the response data from server. -static size_t WriteCallback(void *ptr, size_t size, - size_t nmemb, void *userp) -{ - if (!userp) - return 0; - - std::string* response = static_cast<std::string *>(userp); - size_t real_size = size * nmemb; - response->append(static_cast<char *>(ptr), real_size); - return real_size; -} - -void getProperty(const std::string& key, std::string& value, - std::map<std::string, std::string>& parameters) -{ - auto itr = parameters.find(key); - if (itr != parameters.end()) - { - value = itr->second; - parameters.erase(itr); - } -} - -std::string generate_json(const std::map<std::string, std::string>& parameters) -{ - std::ostringstream stream; - stream << "{\n"; - bool first = true; - for (auto itr = parameters.begin(), itrEnd = parameters.end(); itr != itrEnd; ++itr) - { - if (!first) - { - stream << ",\n"; - } - first = false; - stream << "\"" << itr->first << "\": \"" << itr->second << "\""; - } - stream << "\n}"; - - return stream.str(); -} - -bool uploadContent(std::map<std::string, std::string>& parameters) -{ - CURL* curl = curl_easy_init(); - if (!curl) - return false; - - std::string proxy, proxy_user_pwd, ca_certificate_file, file, url, version; - - getProperty("Proxy", proxy, parameters); - getProperty("ProxyUserPW", proxy_user_pwd, parameters); - getProperty("CAFile", ca_certificate_file, parameters); - - getProperty("DumpFile", file, parameters); - getProperty("URL", url, parameters); - getProperty("Version", version, parameters); - if (url.empty()) - return false; - - if (file.empty()) - return false; - - if (version.empty()) - return false; - - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgent); - // Set proxy information if necessary. - if (!proxy.empty()) - curl_easy_setopt(curl, CURLOPT_PROXY, proxy.c_str()); - if (!proxy_user_pwd.empty()) - curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str()); - - if (!ca_certificate_file.empty()) - curl_easy_setopt(curl, CURLOPT_CAINFO, ca_certificate_file.c_str()); - - curl_httppost* formpost = nullptr; - curl_httppost* lastptr = nullptr; - std::string additional_data = generate_json(parameters); - curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "AdditionalData", - CURLFORM_COPYCONTENTS, additional_data.c_str(), - CURLFORM_END); - - curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "Version", - CURLFORM_COPYCONTENTS, version.c_str(), - CURLFORM_END); - - std::string response_body; - long response_code; - curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "upload_file_minidump", - CURLFORM_FILE, file.c_str(), - CURLFORM_END); - - curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); - - - // Disable 100-continue header. - char buf[] = "Expect:"; - curl_slist* headerlist = nullptr; - headerlist = curl_slist_append(headerlist, buf); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, - static_cast<void *>(&response_body)); - - // Fail if 400+ is returned from the web server. - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); - - CURLcode cc = curl_easy_perform(curl); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); -#ifndef NDEBUG - if (cc != CURLE_OK) - fprintf(stderr, "Failed to send http request to %s, error: %s\n", - url.c_str(), - curl_easy_strerror(cc)); -#endif - - const char* error_description = curl_easy_strerror(cc); - - if (formpost != nullptr) - { - curl_formfree(formpost); - } - if (headerlist != nullptr) - { - curl_slist_free_all(headerlist); - } - - std::cerr << response_body << " " << error_description << std::endl; - - - if( CURLE_OK != cc ) - return false; - - return true; -} - -bool readConfig(char** argv) -{ - std::string iniPath = argv[1]; - - std::ifstream file(iniPath); - std::map<std::string, std::string> parameters = readStrings(file); - - // make sure that at least the mandatory parameters are in there - if (parameters.find("DumpFile") == parameters.end()) - { - std::cerr << "ini file needs to contain a key DumpFile!"; - return false; - } - - if (parameters.find("Version") == parameters.end()) - { - std::cerr << "ini file needs to contain a key Version!"; - return false; - } - - uploadContent(parameters); - - return true; -} - -int main(int argc, char* argv[]) +int main(int argc, char** argv) { if (argc < 2) { @@ -215,7 +19,8 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } - if (!readConfig(argv)) + std::string iniPath(argv[1]); + if (!readConfig(iniPath)) return EXIT_FAILURE; return EXIT_SUCCESS; |