Add namespaces and improve error handling in examples

This commit is contained in:
Federico Stazi 2020-09-29 13:50:13 +00:00
parent 0b1951ea4c
commit fec2124ee1
15 changed files with 380 additions and 332 deletions

6
.gitmodules vendored
View File

@ -4,9 +4,9 @@
[submodule "oss-internship-2020/pffft/master"]
path = oss-internship-2020/pffft/master
url = https://bitbucket.org/jpommier/pffft/src/master/
[submodule "oss-internship-2020/curl/curl_wrapper/curl"]
path = oss-internship-2020/curl/curl_wrapper/curl
url = https://github.com/curl/curl
[submodule "oss-internship-2020/gdal/gdal"]
path = oss-internship-2020/gdal/gdal
url = https://github.com/OSGeo/gdal/tree/master/gdal
[submodule "oss-internship-2020/curl/curl_wrapper/curl"]
path = oss-internship-2020/curl/curl_wrapper/curl
url = git@github.com:curl/curl.git

View File

@ -12,15 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.12)
project(libcurl_sandbox)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
option(CURL_SAPI_ENABLE_EXAMPLES "" ON)
option(CURL_SAPI_ENABLE_TESTS "" ON)
option(SAPI_CURL_ENABLE_EXAMPLES "" ON)
option(SAPI_CURL_ENABLE_TESTS "" ON)
# Add callbacks used by examples and tests
if (CURL_SAPI_ENABLE_EXAMPLES OR CURL_SAPI_ENABLE_TESTS)
@ -35,8 +35,8 @@ add_subdirectory(curl_wrapper)
# Setup Sandboxed API
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
set(SAPI_ENABLE_EXAMPLES ${CURL_SAPI_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
set(SAPI_ENABLE_TESTS ${CURL_SAPI_ENABLE_TESTS} CACHE BOOL "" FORCE)
set(SAPI_ENABLE_EXAMPLES ${SAPI_CURL_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
set(SAPI_ENABLE_TESTS ${SAPI_CURL_ENABLE_TESTS} CACHE BOOL "" FORCE)
add_subdirectory(
"${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
@ -125,7 +125,7 @@ add_sapi_library(curl_sapi
LIBRARY_NAME Curl
NAMESPACE ""
NAMESPACE curl
)
# Include generated SAPI header
@ -134,11 +134,11 @@ target_include_directories(curl_sapi INTERFACE
)
# Add examples
if (CURL_SAPI_ENABLE_EXAMPLES)
if (SAPI_CURL_ENABLE_EXAMPLES)
add_subdirectory(examples)
endif()
# Add tests
if (CURL_SAPI_ENABLE_TESTS)
if (SAPI_CURL_ENABLE_TESTS)
add_subdirectory(tests)
endif()

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef TESTS_CALLBACKS_H
#define TESTS_CALLBACKS_H
#ifndef CALLBACKS_H_
#define CALLBACKS_H_
#include <curl/curl.h>
@ -21,4 +21,4 @@
extern "C" size_t WriteToMemory(char* contents, size_t size, size_t num_bytes,
void* userp);
#endif // TESTS_CALLBACKS_H
#endif // CALLBACKS_H_

@ -1 +1 @@
Subproject commit cbe7fad20d969626a5c4eb0501a273dfe812bcd3
Subproject commit a87cca7b1cbec0b4206b2bb1cb074a8a4a5bd151

View File

@ -14,8 +14,8 @@
// Wrapper for curl library
#ifndef CURL_WRAPPER_H
#define CURL_WRAPPER_H
#ifndef CURL_WRAPPER_H_
#define CURL_WRAPPER_H_
#include <curl/curl.h>
@ -77,6 +77,7 @@ CURLSHcode curl_share_setopt_ptr(CURLSH* handle, CURLSHoption option,
// The wrapper method is needed to make the variadic argument explicit
CURLSHcode curl_share_setopt_long(CURLSH* handle, CURLSHoption option,
long parameter);
}
#endif // CURL_WRAPPER_H
} // extern "C"
#endif // CURL_WRAPPER_H_

View File

@ -19,59 +19,70 @@
#include "../sandbox.h" // NOLINT(build/include)
namespace {
absl::Status Example1() {
// Initialize sandbox2 and sapi
curl::CurlSapiSandbox sandbox;
SAPI_RETURN_IF_ERROR(sandbox.Init());
curl::CurlApi api(&sandbox);
// Initialize the curl session
curl::CURL* curl_handle;
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
sapi::v::RemotePtr curl(curl_handle);
if (!curl_handle) {
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
}
int curl_code;
// Specify URL to get
sapi::v::ConstCStr url("http://example.com");
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Set the library to follow a redirection
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_long(&curl, curl::CURLOPT_FOLLOWLOCATION, 1l));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
}
// Disable authentication of peer certificate
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_long(&curl, curl::CURLOPT_SSL_VERIFYPEER, 0l));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
}
// Perform the request
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
}
// Cleanup curl
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
return absl::OkStatus();
}
} // namespace
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
absl::Status status;
// Initialize sandbox2 and sapi
CurlSapiSandbox sandbox;
status = sandbox.Init();
if (!status.ok()) {
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
}
CurlApi api(&sandbox);
// Initialize the curl session
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
if (!curl_handle.ok()) {
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
}
sapi::v::RemotePtr curl(curl_handle.value());
if (!curl.GetValue()) LOG(FATAL) << "curl_easy_init failed: curl is NULL";
absl::StatusOr<int> curl_code;
// Specify URL to get
sapi::v::ConstCStr url("http://example.com");
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
}
// Set the library to follow a redirection
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_FOLLOWLOCATION, 1l);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
}
// Disable authentication of peer certificate
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 0l);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
}
// Perform the request
curl_code = api.curl_easy_perform(&curl);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
}
// Cleanup curl
status = api.curl_easy_cleanup(&curl);
if (!status.ok()) {
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
if (absl::Status status = Example1(); !status.ok()) {
LOG(ERROR) << "Example1 failed: " << status.ToString();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

View File

@ -20,87 +20,90 @@
#include "../sandbox.h" // NOLINT(build/include)
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
absl::Status status;
namespace {
absl::Status Example2() {
// Initialize sandbox2 and sapi
CurlSapiSandbox sandbox;
status = sandbox.Init();
if (!status.ok()) {
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
}
CurlApi api(&sandbox);
curl::CurlSapiSandbox sandbox;
SAPI_RETURN_IF_ERROR(sandbox.Init());
curl::CurlApi api(&sandbox);
// Generate pointer to WriteMemoryCallback function
void* function_ptr;
status = sandbox.rpc_channel()->Symbol("WriteToMemory", &function_ptr);
if (!status.ok()) {
LOG(FATAL) << "sapi::Sandbox::rpc_channel().Symbol failed: " << status;
}
sapi::v::RemotePtr remote_function_ptr(function_ptr);
SAPI_RETURN_IF_ERROR(
sandbox.rpc_channel()->Symbol("WriteToMemory", &function_ptr));
sapi::v::RemotePtr write_to_memory(function_ptr);
// Initialize the curl session
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
if (!curl_handle.ok()) {
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
}
sapi::v::RemotePtr curl(curl_handle.value());
if (!curl.GetValue()) {
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
curl::CURL* curl_handle;
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
sapi::v::RemotePtr curl(curl_handle);
if (!curl_handle) {
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
}
absl::StatusOr<int> curl_code;
int curl_code;
// Specify URL to get
sapi::v::ConstCStr url("http://example.com");
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Set WriteMemoryCallback as the write function
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEFUNCTION,
&remote_function_ptr);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_WRITEFUNCTION,
&write_to_memory));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Pass 'chunk' struct to the callback function
sapi::v::LenVal chunk(0);
curl_code =
api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEDATA, chunk.PtrBoth());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_WRITEDATA,
chunk.PtrBoth()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Set a user agent
sapi::v::ConstCStr user_agent("libcurl-agent/1.0");
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_USERAGENT,
user_agent.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_USERAGENT,
user_agent.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Perform the request
curl_code = api.curl_easy_perform(&curl);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
}
// Retrieve memory size
status = sandbox.TransferFromSandboxee(&chunk);
if (!status.ok()) {
LOG(FATAL) << "sandbox.TransferFromSandboxee failed: " << status;
}
SAPI_RETURN_IF_ERROR(sandbox.TransferFromSandboxee(&chunk));
std::cout << "memory size: " << chunk.GetDataSize() << " bytes" << std::endl;
// Cleanup curl
status = api.curl_easy_cleanup(&curl);
if (!status.ok()) {
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
return absl::OkStatus();
}
} // namespace
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
if (absl::Status status = Example2(); !status.ok()) {
LOG(ERROR) << "Example2 failed: " << status.ToString();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

View File

@ -19,7 +19,9 @@
#include "../sandbox.h" // NOLINT(build/include)
class CurlSapiSandboxEx3 : public CurlSapiSandbox {
namespace {
class CurlSapiSandboxEx3 : public curl::CurlSapiSandbox {
public:
CurlSapiSandboxEx3(std::string ssl_certificate, std::string ssl_key,
std::string ca_certificates)
@ -42,7 +44,7 @@ class CurlSapiSandboxEx3 : public CurlSapiSandbox {
.AddFile(ssl_key)
.AddFile(ca_certificates);
// Provide the new PolicyBuilder to ModifyPolicy in CurlSandbox
return CurlSapiSandbox::ModifyPolicy(policy_builder.get());
return curl::CurlSapiSandbox::ModifyPolicy(policy_builder.get());
}
std::string ssl_certificate;
@ -50,116 +52,123 @@ class CurlSapiSandboxEx3 : public CurlSapiSandbox {
std::string ca_certificates;
};
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
absl::Status status;
// Get input parameters (should be absolute paths)
if (argc != 5) {
LOG(FATAL) << "wrong number of arguments (4 expected)";
}
std::string ssl_certificate = argv[1];
std::string ssl_key = argv[2];
std::string ssl_key_password = argv[3];
std::string ca_certificates = argv[4];
absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
std::string ssl_key_password,
std::string ca_certificates) {
// Initialize sandbox2 and sapi
CurlSapiSandboxEx3 sandbox(ssl_certificate, ssl_key, ca_certificates);
status = sandbox.Init();
if (!status.ok()) {
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
}
CurlApi api(&sandbox);
SAPI_RETURN_IF_ERROR(sandbox.Init());
curl::CurlApi api(&sandbox);
absl::StatusOr<int> curl_code;
int curl_code;
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
curl_code = api.curl_global_init(3l);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
if (curl_code != 0) {
return absl::UnavailableError("curl_global_init failed: " + curl_code);
}
// Initialize curl easy handle
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
if (!curl_handle.ok()) {
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
}
sapi::v::RemotePtr curl(curl_handle.value());
if (!curl.GetValue()) {
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
curl::CURL* curl_handle;
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
sapi::v::RemotePtr curl(curl_handle);
if (!curl_handle) {
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
}
// Specify URL to get (using HTTPS)
sapi::v::ConstCStr url("https://example.com");
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Set the SSL certificate type to "PEM"
sapi::v::ConstCStr ssl_cert_type("PEM");
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERTTYPE,
ssl_cert_type.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERTTYPE,
ssl_cert_type.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Set the certificate for client authentication
sapi::v::ConstCStr sapi_ssl_certificate(ssl_certificate.c_str());
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERT,
sapi_ssl_certificate.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERT,
sapi_ssl_certificate.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Set the private key for client authentication
sapi::v::ConstCStr sapi_ssl_key(ssl_key.c_str());
curl_code =
api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLKEY, sapi_ssl_key.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLKEY,
sapi_ssl_key.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Set the password used to protect the private key
sapi::v::ConstCStr sapi_ssl_key_password(ssl_key_password.c_str());
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_KEYPASSWD,
sapi_ssl_key_password.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_KEYPASSWD,
sapi_ssl_key_password.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Set the file with the certificates vaildating the server
sapi::v::ConstCStr sapi_ca_certificates(ca_certificates.c_str());
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_CAINFO,
sapi_ca_certificates.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_CAINFO,
sapi_ca_certificates.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Verify the authenticity of the server
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 1L);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_long(&curl, curl::CURLOPT_SSL_VERIFYPEER, 1L));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
}
// Perform the request
curl_code = api.curl_easy_perform(&curl);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
}
// Cleanup curl easy handle
status = api.curl_easy_cleanup(&curl);
if (!status.ok()) {
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
}
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
// Cleanup curl
status = api.curl_global_cleanup();
if (!status.ok()) {
LOG(FATAL) << "curl_global_cleanup failed: " << status;
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
return absl::OkStatus();
}
} // namespace
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
// Get input parameters (should be absolute paths)
if (argc != 5) {
LOG(ERROR) << "wrong number of arguments (4 expected)";
return EXIT_FAILURE;
}
if (absl::Status status = Example3(argv[1], argv[2], argv[3], argv[4]);
!status.ok()) {
LOG(ERROR) << "Example3 failed: " << status.ToString();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

View File

@ -21,107 +21,114 @@
#include "curl_sapi.sapi.h" // NOLINT(build/include)
#include "sandboxed_api/util/flag.h"
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
absl::Status status;
namespace {
absl::Status Example4() {
// Initialize sandbox2 and sapi
CurlSapiSandbox sandbox;
status = sandbox.Init();
if (!status.ok()) {
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
}
CurlApi api(&sandbox);
curl::CurlSapiSandbox sandbox;
SAPI_RETURN_IF_ERROR(sandbox.Init());
curl::CurlApi api(&sandbox);
// Number of running handles
sapi::v::Int still_running(1);
absl::StatusOr<int> curl_code;
int curl_code;
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
curl_code = api.curl_global_init(3l);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
if (curl_code != 0) {
return absl::UnavailableError("curl_global_init failed: " + curl_code);
}
// Initialize http_handle
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
if (!curl_handle.ok()) {
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
}
sapi::v::RemotePtr http_handle(curl_handle.value());
if (!http_handle.GetValue()) {
LOG(FATAL) << "curl_easy_init failed: http_handle is NULL";
curl::CURL* curl_handle;
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
sapi::v::RemotePtr http_handle(curl_handle);
if (!curl_handle) {
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
}
// Specify URL to get
sapi::v::ConstCStr url("http://example.com");
curl_code =
api.curl_easy_setopt_ptr(&http_handle, CURLOPT_URL, url.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&http_handle, curl::CURLOPT_URL,
url.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Initialize multi_handle
absl::StatusOr<CURLM*> curlm_handle = api.curl_multi_init();
if (!curlm_handle.ok()) {
LOG(FATAL) << "curl_multi_init failed: " << curlm_handle.status();
}
sapi::v::RemotePtr multi_handle(curlm_handle.value());
if (!multi_handle.GetValue()) {
LOG(FATAL) << "curl_multi_init failed: multi_handle is NULL";
curl::CURLM* curlm_handle;
SAPI_ASSIGN_OR_RETURN(curlm_handle, api.curl_multi_init());
sapi::v::RemotePtr multi_handle(curlm_handle);
if (!curlm_handle) {
return absl::UnavailableError(
"curl_multi_init failed: multi_handle is NULL");
}
// Add http_handle to the multi stack
curl_code = api.curl_multi_add_handle(&multi_handle, &http_handle);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_multi_add_handle failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code,
api.curl_multi_add_handle(&multi_handle, &http_handle));
if (curl_code != 0) {
return absl::UnavailableError("curl_multi_add_handle failed: " + curl_code);
}
while (still_running.GetValue()) {
sapi::v::Int numfds(0);
// Perform the request
curl_code = api.curl_multi_perform(&multi_handle, still_running.PtrBoth());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_mutli_perform failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_multi_perform(&multi_handle, still_running.PtrBoth()));
if (curl_code != 0) {
return absl::UnavailableError("curl_mutli_perform failed: " + curl_code);
}
if (still_running.GetValue()) {
// Wait for an event or timeout
sapi::v::NullPtr null_ptr;
curl_code = api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0, 1000,
numfds.PtrBoth());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_multi_poll_sapi failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0, 1000,
numfds.PtrBoth()));
if (curl_code != 0) {
return absl::UnavailableError("curl_multi_poll_sapi failed: " +
curl_code);
}
}
}
// Remove http_handle from the multi stack
curl_code = api.curl_multi_remove_handle(&multi_handle, &http_handle);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_multi_remove_handle failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_multi_remove_handle(&multi_handle, &http_handle));
if (curl_code != 0) {
return absl::UnavailableError("curl_multi_remove_handle failed: " +
curl_code);
}
// Cleanup http_handle
status = api.curl_easy_cleanup(&http_handle);
if (!status.ok()) {
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
}
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&http_handle));
// Cleanup multi_handle
curl_code = api.curl_multi_cleanup(&multi_handle);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_multi_cleanup failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_multi_cleanup(&multi_handle));
if (curl_code != 0) {
return absl::UnavailableError("curl_multi_cleanup failed: " + curl_code);
}
// Cleanup curl
status = api.curl_global_cleanup();
if (!status.ok()) {
LOG(FATAL) << "curl_global_cleanup failed: " << status;
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
return absl::OkStatus();
}
} // namespace
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
if (absl::Status status = Example4(); !status.ok()) {
LOG(ERROR) << "Example4 failed: " << status.ToString();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

View File

@ -15,87 +15,91 @@
// Sandboxed version of multithread.c
// Multithreaded HTTP GET requests
#include <pthread.h>
#include <cstdlib>
#include <future>
#include <thread>
#include "../sandbox.h" // NOLINT(build/include)
void pull_one_url(const std::string& url, CurlApi& api) {
namespace {
absl::Status pull_one_url(const std::string& url, curl::CurlApi& api) {
// Initialize the curl session
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
if (!curl_handle.ok()) {
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
}
sapi::v::RemotePtr curl(curl_handle.value());
if (!curl.GetValue()) {
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
curl::CURL* curl_handle;
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
sapi::v::RemotePtr curl(curl_handle);
if (!curl_handle) {
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
}
absl::StatusOr<int> curl_code;
int curl_code;
// Specify URL to get
sapi::v::ConstCStr sapi_url(url.c_str());
curl_code =
api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, sapi_url.PtrBefore());
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, sapi_url.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
}
// Perform the request
curl_code = api.curl_easy_perform(&curl);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
if (curl_code != 0) {
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
}
// Cleanup curl
absl::Status status = api.curl_easy_cleanup(&curl);
if (!status.ok()) {
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
}
// Cleanup curl easy handle
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
return absl::OkStatus();
}
const std::vector<std::string> urls = {
"http://example.com", "http://example.edu", "http://example.net",
"http://example.org"};
absl::Status Example5() {
// Initialize sandbox2 and sapi
curl::CurlSapiSandbox sandbox;
SAPI_RETURN_IF_ERROR(sandbox.Init());
curl::CurlApi api(&sandbox);
int curl_code;
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
if (curl_code != 0) {
return absl::UnavailableError("curl_global_init failed: " + curl_code);
}
// Create the threads (by using futures)
std::vector<std::future<absl::Status>> futures;
for (auto& url : urls) {
futures.emplace_back(
std::async(pull_one_url, std::ref(url), std::ref(api)));
}
// Join the threads and check for errors
for (auto& future : futures) {
SAPI_RETURN_IF_ERROR(future.get());
}
// Cleanup curl
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
return absl::OkStatus();
}
} // namespace
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
absl::Status status;
// Initialize sandbox2 and sapi
CurlSapiSandbox sandbox;
status = sandbox.Init();
if (!status.ok()) {
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
}
CurlApi api(&sandbox);
absl::StatusOr<int> curl_code;
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
curl_code = api.curl_global_init(3l);
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
}
// Create the threads
std::vector<std::thread> threads;
for (auto& url : urls) {
threads.emplace_back(pull_one_url, std::ref(url), std::ref(api));
}
// Join the threads
for (auto& thread : threads) {
thread.join();
}
// Cleanup curl
status = api.curl_global_cleanup();
if (!status.ok()) {
LOG(FATAL) << "curl_global_cleanup failed: " << status;
if (absl::Status status = Example5(); !status.ok()) {
LOG(ERROR) << "Example5 failed: " << status.ToString();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

View File

@ -20,6 +20,8 @@
#include "../sandbox.h" // NOLINT(build/include)
#include "sandboxed_api/transaction.h"
namespace {
class CurlTransaction : public sapi::Transaction {
public:
explicit CurlTransaction(std::unique_ptr<sapi::Sandbox> sandbox)
@ -36,7 +38,7 @@ class CurlTransaction : public sapi::Transaction {
};
absl::Status CurlTransaction::Main() {
CurlApi api(sandbox());
curl::CurlApi api(sandbox());
// Initialize the curl session
SAPI_ASSIGN_OR_RETURN(void* curl_remote, api.curl_easy_init());
@ -47,13 +49,13 @@ absl::Status CurlTransaction::Main() {
sapi::v::ConstCStr url("http://example.com");
SAPI_ASSIGN_OR_RETURN(
int setopt_url_code,
api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore()));
TRANSACTION_FAIL_IF_NOT(setopt_url_code == CURLE_OK,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore()));
TRANSACTION_FAIL_IF_NOT(setopt_url_code == curl::CURLE_OK,
"curl_easy_setopt_ptr failed");
// Perform the request
SAPI_ASSIGN_OR_RETURN(int perform_code, api.curl_easy_perform(&curl));
TRANSACTION_FAIL_IF_NOT(setopt_url_code == CURLE_OK,
TRANSACTION_FAIL_IF_NOT(setopt_url_code == curl::CURLE_OK,
"curl_easy_perform failed");
// Cleanup curl
@ -63,8 +65,10 @@ absl::Status CurlTransaction::Main() {
return absl::OkStatus();
}
} // namespace
int main(int argc, char* argv[]) {
CurlTransaction curl{std::make_unique<CurlSapiSandbox>()};
CurlTransaction curl{std::make_unique<curl::CurlSapiSandbox>()};
absl::Status status = curl.Run();
CHECK(status.ok()) << "CurlTransaction failed";

View File

@ -24,7 +24,9 @@
#include "curl_sapi.sapi.h" // NOLINT(build/include)
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
class CurlSapiSandbox : public CurlSandbox {
namespace curl {
class CurlSapiSandbox : public curl::CurlSandbox {
protected:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder* policy_builder) override {

View File

@ -28,17 +28,17 @@
int CurlTestUtils::port_;
std::thread CurlTestUtils::server_thread_;
absl::Status CurlTestUtils::CurlTestSetUp() {
absl::Status curl::tests::CurlTestUtils::CurlTestSetUp() {
// Initialize sandbox2 and sapi
sandbox_ = std::make_unique<CurlSapiSandbox>();
sandbox_ = std::make_unique<curl::CurlSapiSandbox>();
absl::Status init = sandbox_->Init();
if (!init.ok()) {
return init;
}
api_ = std::make_unique<CurlApi>(sandbox_.get());
api_ = std::make_unique<curl::CurlApi>(sandbox_.get());
// Initialize curl
absl::StatusOr<CURL*> curl_handle = api_->curl_easy_init();
absl::StatusOr<curl::CURL*> curl_handle = api_->curl_easy_init();
if (!curl_handle.ok()) {
return curl_handle.status();
}
@ -51,23 +51,24 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
// Specify request URL
sapi::v::ConstCStr sapi_url(kUrl.data());
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_URL,
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_URL,
sapi_url.PtrBefore());
if (!curl_code.ok()) {
return curl_code.status();
}
if (curl_code.value() != CURLE_OK) {
if (curl_code.value() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_setopt_ptr returned with the error code " +
curl_code.value());
}
// Set port
curl_code = api_->curl_easy_setopt_long(curl_.get(), CURLOPT_PORT, port_);
curl_code =
api_->curl_easy_setopt_long(curl_.get(), curl::CURLOPT_PORT, port_);
if (!curl_code.ok()) {
return curl_code.status();
}
if (curl_code.value() != CURLE_OK) {
if (curl_code.value() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_setopt_long returned with the error code " +
curl_code.value());
@ -83,12 +84,12 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
sapi::v::RemotePtr remote_function_ptr(function_ptr);
// Set WriteToMemory as the write function
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEFUNCTION,
&remote_function_ptr);
curl_code = api_->curl_easy_setopt_ptr(
curl_.get(), curl::CURLOPT_WRITEFUNCTION, &remote_function_ptr);
if (!curl_code.ok()) {
return curl_code.status();
}
if (curl_code.value() != CURLE_OK) {
if (curl_code.value() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_setopt_ptr returned with the error code " +
curl_code.value());
@ -96,12 +97,12 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
// Pass memory chunk object to the callback
chunk_ = std::make_unique<sapi::v::LenVal>(0);
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEDATA,
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_WRITEDATA,
chunk_->PtrBoth());
if (!curl_code.ok()) {
return curl_code.status();
}
if (curl_code.value() != CURLE_OK) {
if (curl_code.value() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_setopt_ptr returned with the error code " +
curl_code.value());
@ -110,18 +111,18 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
return absl::OkStatus();
}
absl::Status CurlTestUtils::CurlTestTearDown() {
absl::Status curl::tests::CurlTestUtils::CurlTestTearDown() {
// Cleanup curl
return api_->curl_easy_cleanup(curl_.get());
}
absl::StatusOr<std::string> CurlTestUtils::PerformRequest() {
absl::StatusOr<std::string> curl::tests::CurlTestUtils::PerformRequest() {
// Perform the request
absl::StatusOr<int> curl_code = api_->curl_easy_perform(curl_.get());
if (!curl_code.ok()) {
return curl_code.status();
}
if (curl_code.value() != CURLE_OK) {
if (curl_code.value() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_perform returned with the error code " + curl_code.value());
}
@ -267,7 +268,7 @@ void ServerLoop(int listening_socket, sockaddr_in socket_address) {
} // namespace
void CurlTestUtils::StartMockServer() {
void curl::tests::CurlTestUtils::StartMockServer() {
// Get the socket file descriptor
int listening_socket = socket(AF_INET, SOCK_STREAM, 0);

View File

@ -21,6 +21,8 @@
#include "sandboxed_api/util/flag.h"
#include "sandboxed_api/util/status_matchers.h"
namespace curl::tests {
// Helper class that can be used to test Curl Sandboxed
class CurlTestUtils {
protected:
@ -39,8 +41,8 @@ class CurlTestUtils {
// Responds with the POST request fields to a POST request
static void StartMockServer();
std::unique_ptr<CurlSapiSandbox> sandbox_;
std::unique_ptr<CurlApi> api_;
std::unique_ptr<curl::CurlSapiSandbox> sandbox_;
std::unique_ptr<curl::CurlApi> api_;
std::unique_ptr<sapi::v::RemotePtr> curl_;
static std::thread server_thread_;

View File

@ -14,7 +14,9 @@
#include "test_utils.h" // NOLINT(build/include)
class CurlTest : public CurlTestUtils, public ::testing::Test {
namespace {
class CurlTest : public curl::tests::CurlTestUtils, public ::testing::Test {
protected:
void SetUp() override {
// Start mock server, get port number and check for any error
@ -38,9 +40,9 @@ TEST_F(CurlTest, EffectiveUrl) {
// Get effective URL
SAPI_ASSERT_OK_AND_ASSIGN(
int getinfo_code,
api_->curl_easy_getinfo_ptr(curl_.get(), CURLINFO_EFFECTIVE_URL,
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_EFFECTIVE_URL,
effective_url_ptr.PtrBoth()));
ASSERT_EQ(getinfo_code, CURLE_OK);
ASSERT_EQ(getinfo_code, curl::CURLE_OK);
// Store effective URL in a string
SAPI_ASSERT_OK_AND_ASSIGN(std::string effective_url,
@ -74,9 +76,9 @@ TEST_F(CurlTest, ResponseCode) {
// Get response code
SAPI_ASSERT_OK_AND_ASSIGN(
int getinfo_code,
api_->curl_easy_getinfo_ptr(curl_.get(), CURLINFO_RESPONSE_CODE,
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_RESPONSE_CODE,
response_code.PtrBoth()));
ASSERT_EQ(getinfo_code, CURLE_OK);
ASSERT_EQ(getinfo_code, curl::CURLE_OK);
// Check response code
ASSERT_EQ(response_code.GetValue(), 200);
@ -120,19 +122,21 @@ TEST_F(CurlTest, POSTResponse) {
// Set the size of the POST fields
SAPI_ASSERT_OK_AND_ASSIGN(
int setopt_post_fields_size,
api_->curl_easy_setopt_long(curl_.get(), CURLOPT_POSTFIELDSIZE,
api_->curl_easy_setopt_long(curl_.get(), curl::CURLOPT_POSTFIELDSIZE,
post_fields.GetSize()));
ASSERT_EQ(setopt_post_fields_size, CURLE_OK);
ASSERT_EQ(setopt_post_fields_size, curl::CURLE_OK);
// Set the POST fields
SAPI_ASSERT_OK_AND_ASSIGN(
int setopt_post_fields,
api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_POSTFIELDS,
api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_POSTFIELDS,
post_fields.PtrBefore()));
ASSERT_EQ(setopt_post_fields, CURLE_OK);
ASSERT_EQ(setopt_post_fields, curl::CURLE_OK);
SAPI_ASSERT_OK_AND_ASSIGN(std::string response, PerformRequest());
// Compare response with expected response
ASSERT_EQ(std::string(post_fields.GetData()), response);
}
} // namespace