diff options
-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; |