-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug: internal b/240476093 Test: test on device Change-Id: Iea183b01a9c0d37e246c1c2ad0bed6e09d95e64c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3924397 Commit-Queue: Yuchen Liu <yucliu@chromium.org> Auto-Submit: Mohit Hotwani <hmohit@google.com> Reviewed-by: Ryan Chung <ryanchung@chromium.org> Reviewed-by: Yuchen Liu <yucliu@chromium.org> Cr-Commit-Position: refs/heads/main@{#1052181}
- Loading branch information
Mohit Hotwani
authored and
Chromium LUCI CQ
committed
Sep 28, 2022
1 parent
ed8b19d
commit 568c546
Showing
6 changed files
with
309 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include <dlfcn.h> | ||
|
||
#include <iostream> | ||
#include <string> | ||
|
||
#include "chromecast/crash/libcurl_wrapper.h" | ||
|
||
namespace chromecast { | ||
LibcurlWrapper::LibcurlWrapper() | ||
: init_ok_(false), | ||
curl_lib_(nullptr), | ||
last_curl_error_(""), | ||
curl_(nullptr), | ||
formpost_(nullptr), | ||
lastptr_(nullptr), | ||
headerlist_(nullptr) {} | ||
|
||
LibcurlWrapper::~LibcurlWrapper() { | ||
if (init_ok_) { | ||
(*easy_cleanup_)(curl_); | ||
dlclose(curl_lib_); | ||
} | ||
} | ||
|
||
bool LibcurlWrapper::AddFile(const std::string& upload_file_path, | ||
const std::string& basename) { | ||
if (!CheckInit()) | ||
return false; | ||
|
||
std::cout << "Adding " << upload_file_path << " to form upload."; | ||
// Add form file. | ||
(*formadd_)(&formpost_, &lastptr_, CURLFORM_COPYNAME, basename.c_str(), | ||
CURLFORM_FILE, upload_file_path.c_str(), CURLFORM_END); | ||
|
||
return true; | ||
} | ||
|
||
// 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 = reinterpret_cast<std::string*>(userp); | ||
size_t real_size = size * nmemb; | ||
response->append(reinterpret_cast<char*>(ptr), real_size); | ||
return real_size; | ||
} | ||
|
||
bool LibcurlWrapper::SendRequest( | ||
const std::string& url, | ||
const std::map<std::string, std::string>& parameters, | ||
long* http_status_code, | ||
std::string* http_header_data, | ||
std::string* http_response_data) { | ||
if (!CheckInit()) | ||
return false; | ||
|
||
std::map<std::string, std::string>::const_iterator iter = parameters.begin(); | ||
for (; iter != parameters.end(); ++iter) | ||
(*formadd_)(&formpost_, &lastptr_, CURLFORM_COPYNAME, iter->first.c_str(), | ||
CURLFORM_COPYCONTENTS, iter->second.c_str(), CURLFORM_END); | ||
|
||
(*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_); | ||
|
||
return SendRequestInner(url, http_status_code, http_header_data, | ||
http_response_data); | ||
} | ||
|
||
bool LibcurlWrapper::Init() { | ||
// First check to see if libcurl was statically linked: | ||
curl_lib_ = dlopen(nullptr, RTLD_NOW); | ||
if (curl_lib_ && (!dlsym(curl_lib_, "curl_easy_init") || | ||
!dlsym(curl_lib_, "curl_easy_setopt"))) { | ||
// Not statically linked, try again below. | ||
dlerror(); // Clear dlerror before attempting to open libraries. | ||
dlclose(curl_lib_); | ||
curl_lib_ = nullptr; | ||
} | ||
if (!curl_lib_) { | ||
curl_lib_ = dlopen("libcurl.so", RTLD_NOW); | ||
} | ||
if (!curl_lib_) { | ||
curl_lib_ = dlopen("libcurl.so.4", RTLD_NOW); | ||
} | ||
if (!curl_lib_) { | ||
curl_lib_ = dlopen("libcurl.so.3", RTLD_NOW); | ||
} | ||
if (!curl_lib_) { | ||
std::cout << "Could not find libcurl via dlopen"; | ||
return false; | ||
} | ||
|
||
if (!SetFunctionPointers()) { | ||
std::cout << "Could not find function pointers"; | ||
return false; | ||
} | ||
|
||
curl_ = (*easy_init_)(); | ||
|
||
last_curl_error_ = "No Error"; | ||
|
||
if (!curl_) { | ||
dlclose(curl_lib_); | ||
std::cout << "Curl initialization failed"; | ||
return false; | ||
} | ||
|
||
init_ok_ = true; | ||
return true; | ||
} | ||
|
||
#define SET_AND_CHECK_FUNCTION_POINTER(var, function_name, type) \ | ||
var = reinterpret_cast<type>(dlsym(curl_lib_, function_name)); \ | ||
if (!var) { \ | ||
std::cout << "Could not find libcurl function " << function_name; \ | ||
init_ok_ = false; \ | ||
return false; \ | ||
} | ||
|
||
bool LibcurlWrapper::SetFunctionPointers() { | ||
SET_AND_CHECK_FUNCTION_POINTER(easy_init_, "curl_easy_init", CURL * (*)()); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER(easy_setopt_, "curl_easy_setopt", | ||
CURLcode(*)(CURL*, CURLoption, ...)); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER( | ||
formadd_, "curl_formadd", | ||
CURLFORMcode(*)(curl_httppost**, curl_httppost**, ...)); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER(slist_append_, "curl_slist_append", | ||
curl_slist * (*)(curl_slist*, const char*)); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER(easy_perform_, "curl_easy_perform", | ||
CURLcode(*)(CURL*)); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER(easy_cleanup_, "curl_easy_cleanup", | ||
void (*)(CURL*)); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER(easy_getinfo_, "curl_easy_getinfo", | ||
CURLcode(*)(CURL*, CURLINFO info, ...)); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER(easy_reset_, "curl_easy_reset", | ||
void (*)(CURL*)); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_, "curl_slist_free_all", | ||
void (*)(curl_slist*)); | ||
|
||
SET_AND_CHECK_FUNCTION_POINTER(formfree_, "curl_formfree", | ||
void (*)(curl_httppost*)); | ||
return true; | ||
} | ||
|
||
bool LibcurlWrapper::SendRequestInner(const std::string& url, | ||
long* http_status_code, | ||
std::string* http_header_data, | ||
std::string* http_response_data) { | ||
std::string url_copy(url); | ||
(*easy_setopt_)(curl_, CURLOPT_URL, url_copy.c_str()); | ||
// Use the enum when available in the header file. | ||
(*easy_setopt_)(curl_, CURLOPT_SSLVERSION, 6 /*CURL_SSLVERSION_TLSv1_2*/); | ||
|
||
// Disable 100-continue header. | ||
char buf[] = "Expect:"; | ||
headerlist_ = (*slist_append_)(headerlist_, buf); | ||
(*easy_setopt_)(curl_, CURLOPT_HTTPHEADER, headerlist_); | ||
|
||
if (http_response_data != nullptr) { | ||
http_response_data->clear(); | ||
(*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback); | ||
(*easy_setopt_)(curl_, CURLOPT_WRITEDATA, | ||
reinterpret_cast<void*>(http_response_data)); | ||
} | ||
if (http_header_data != nullptr) { | ||
http_header_data->clear(); | ||
(*easy_setopt_)(curl_, CURLOPT_HEADERFUNCTION, WriteCallback); | ||
(*easy_setopt_)(curl_, CURLOPT_HEADERDATA, | ||
reinterpret_cast<void*>(http_header_data)); | ||
} | ||
CURLcode err_code = CURLE_OK; | ||
err_code = (*easy_perform_)(curl_); | ||
easy_strerror_ = reinterpret_cast<const char* (*)(CURLcode)>( | ||
dlsym(curl_lib_, "curl_easy_strerror")); | ||
|
||
if (http_status_code != nullptr) { | ||
(*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code); | ||
} | ||
|
||
#ifndef NDEBUG | ||
if (err_code != CURLE_OK) | ||
fprintf(stderr, "Failed to send http request to %s, error: %s\n", | ||
url.c_str(), (*easy_strerror_)(err_code)); | ||
#endif | ||
|
||
Reset(); | ||
|
||
return err_code == CURLE_OK; | ||
} | ||
|
||
void LibcurlWrapper::Reset() { | ||
if (headerlist_ != nullptr) { | ||
(*slist_free_all_)(headerlist_); | ||
headerlist_ = nullptr; | ||
} | ||
|
||
if (formpost_ != nullptr) { | ||
(*formfree_)(formpost_); | ||
formpost_ = nullptr; | ||
} | ||
|
||
(*easy_reset_)(curl_); | ||
} | ||
|
||
bool LibcurlWrapper::CheckInit() { | ||
if (!init_ok_) { | ||
std::cout << "LibcurlWrapper: You must call Init(), and have it return " | ||
"'true' before invoking any other methods.\n"; | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
} // namespace chromecast |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROMECAST_CRASH_LIBCURL_WRAPPER_H_ | ||
#define CHROMECAST_CRASH_LIBCURL_WRAPPER_H_ | ||
|
||
#include <map> | ||
#include <string> | ||
|
||
#include "third_party/breakpad/breakpad/src/third_party/curl/curl.h" | ||
|
||
namespace chromecast { | ||
class LibcurlWrapper { | ||
public: | ||
LibcurlWrapper(); | ||
virtual ~LibcurlWrapper(); | ||
virtual bool Init(); | ||
virtual bool AddFile(const std::string& upload_file_path, | ||
const std::string& basename); | ||
virtual bool SendRequest(const std::string& url, | ||
const std::map<std::string, std::string>& parameters, | ||
long* http_status_code, | ||
std::string* http_header_data, | ||
std::string* http_response_data); | ||
|
||
private: | ||
// This function initializes class state corresponding to function | ||
// pointers into the CURL library. | ||
bool SetFunctionPointers(); | ||
|
||
bool SendRequestInner(const std::string& url, | ||
long* http_status_code, | ||
std::string* http_header_data, | ||
std::string* http_response_data); | ||
|
||
void Reset(); | ||
|
||
bool CheckInit(); | ||
|
||
bool init_ok_; // Whether init succeeded | ||
void* curl_lib_; // Pointer to result of dlopen() on | ||
// curl library | ||
std::string last_curl_error_; // The text of the last error when | ||
// dealing | ||
// with CURL. | ||
|
||
CURL* curl_; // Pointer for handle for CURL calls. | ||
|
||
CURL* (*easy_init_)(void); | ||
|
||
// Stateful pointers for calling into curl_formadd() | ||
struct curl_httppost* formpost_; | ||
struct curl_httppost* lastptr_; | ||
struct curl_slist* headerlist_; | ||
|
||
// Function pointers into CURL library | ||
CURLcode (*easy_setopt_)(CURL*, CURLoption, ...); | ||
CURLFORMcode (*formadd_)(struct curl_httppost**, struct curl_httppost**, ...); | ||
struct curl_slist* (*slist_append_)(struct curl_slist*, const char*); | ||
void (*slist_free_all_)(struct curl_slist*); | ||
CURLcode (*easy_perform_)(CURL*); | ||
const char* (*easy_strerror_)(CURLcode); | ||
void (*easy_cleanup_)(CURL*); | ||
CURLcode (*easy_getinfo_)(CURL*, CURLINFO info, ...); | ||
void (*easy_reset_)(CURL*); | ||
void (*formfree_)(struct curl_httppost*); | ||
}; | ||
} // namespace chromecast | ||
|
||
#endif // CHROMECAST_CRASH_LIBCURL_WRAPPER_H_ |