Fix cURL example

Due to a naming mixup in `oss-internship-2020/curl/CMakeLists.txt`, the
necessary `WriteToMemory()` callback was not linked into the sandboxee,
leading to a segfault in the sandboxee when trying to run the
tests/examples.

As another issue, cURL seems to call `sysinfo` and `rt_sigaction` in
recent versions and with recent libc.

Drive-by changes:
- Use the SAPI status macros instead of manually checking `absl::Status`
- Put tests in namespace
- Some Google C++-style fixes
- Start the mock test server only once per test suite

Fixes #72 for cURL.

Signed-off-by: Christian Blichmann <cblichmann@google.com>
This commit is contained in:
Christian Blichmann 2021-01-21 11:31:24 +01:00
parent b98bed9860
commit 3a95d9df41
10 changed files with 166 additions and 148 deletions

View File

@ -23,7 +23,7 @@ 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)
if (SAPI_CURL_ENABLE_EXAMPLES OR SAPI_CURL_ENABLE_TESTS)
list(APPEND CURL_SAPI_CALLBACKS
"${CMAKE_CURRENT_SOURCE_DIR}/callbacks/callbacks.h"
"${CMAKE_CURRENT_SOURCE_DIR}/callbacks/callbacks.cc"
@ -34,7 +34,7 @@ endif()
add_subdirectory(curl_wrapper)
# Setup Sandboxed API
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
set(SAPI_ENABLE_EXAMPLES ${SAPI_CURL_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
set(SAPI_ENABLE_TESTS ${SAPI_CURL_ENABLE_TESTS} CACHE BOOL "" FORCE)
add_subdirectory(

View File

@ -18,6 +18,7 @@
#include <cstdlib>
#include "../sandbox.h" // NOLINT(build/include)
#include "absl/strings/str_cat.h"
namespace {
@ -43,7 +44,8 @@ absl::Status Example1() {
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the library to follow a redirection
@ -51,7 +53,8 @@ absl::Status Example1() {
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_long failed: ", curl_code));
}
// Disable authentication of peer certificate
@ -59,13 +62,15 @@ absl::Status Example1() {
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);
return absl::UnavailableError(
absl::StrCat("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);
return absl::UnavailableError(
absl::StrCat("curl_easy_perform failed: ", curl_code));
}
// Cleanup curl

View File

@ -19,6 +19,7 @@
#include <iostream>
#include "../sandbox.h" // NOLINT(build/include)
#include "absl/strings/str_cat.h"
namespace {
@ -50,7 +51,8 @@ absl::Status Example2() {
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set WriteMemoryCallback as the write function
@ -58,7 +60,8 @@ absl::Status Example2() {
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Pass 'chunk' struct to the callback function
@ -67,7 +70,8 @@ absl::Status Example2() {
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set a user agent
@ -76,13 +80,15 @@ absl::Status Example2() {
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr 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);
return absl::UnavailableError(
absl::StrCat("curl_easy_perform failed: ", curl_code));
}
// Retrieve memory size

View File

@ -65,7 +65,8 @@ absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
// 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);
return absl::UnavailableError(
absl::StrCat("curl_global_init failed: ", curl_code));
}
// Initialize curl easy handle
@ -82,7 +83,8 @@ absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the SSL certificate type to "PEM"
@ -91,7 +93,8 @@ absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the certificate for client authentication
@ -100,7 +103,8 @@ absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the private key for client authentication
@ -109,7 +113,8 @@ absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the password used to protect the private key
@ -118,7 +123,8 @@ absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the file with the certificates vaildating the server
@ -127,7 +133,8 @@ absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Verify the authenticity of the server
@ -135,13 +142,15 @@ absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
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);
return absl::UnavailableError(
absl::StrCat("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);
return absl::UnavailableError(
absl::StrCat("curl_easy_perform failed: ", curl_code));
}
// Cleanup curl easy handle

View File

@ -17,7 +17,8 @@
#include <cstdlib>
#include "../sandbox.h" // NOLINT(build/include)
#include "../sandbox.h" // NOLINT(build/include)
#include "absl/strings/str_cat.h"
#include "curl_sapi.sapi.h" // NOLINT(build/include)
#include "sandboxed_api/util/flag.h"
@ -37,7 +38,8 @@ absl::Status Example4() {
// 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);
return absl::UnavailableError(
absl::StrCat("curl_global_init failed: ", curl_code));
}
// Initialize http_handle
@ -54,7 +56,8 @@ absl::Status Example4() {
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Initialize multi_handle
@ -70,7 +73,8 @@ absl::Status Example4() {
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);
return absl::UnavailableError(
absl::StrCat("curl_multi_add_handle failed: ", curl_code));
}
while (still_running.GetValue()) {
@ -81,7 +85,8 @@ absl::Status Example4() {
curl_code,
api.curl_multi_perform(&multi_handle, still_running.PtrBoth()));
if (curl_code != 0) {
return absl::UnavailableError("curl_mutli_perform failed: " + curl_code);
return absl::UnavailableError(
absl::StrCat("curl_mutli_perform failed: ", curl_code));
}
if (still_running.GetValue()) {
@ -91,8 +96,8 @@ absl::Status Example4() {
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);
return absl::UnavailableError(
absl::StrCat("curl_multi_poll_sapi failed: ", curl_code));
}
}
}
@ -101,8 +106,8 @@ absl::Status Example4() {
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);
return absl::UnavailableError(
absl::StrCat("curl_multi_remove_handle failed: ", curl_code));
}
// Cleanup http_handle
@ -111,7 +116,8 @@ absl::Status Example4() {
// Cleanup multi_handle
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);
return absl::UnavailableError(
absl::StrCat("curl_multi_cleanup failed: ", curl_code));
}
// Cleanup curl

View File

@ -20,6 +20,7 @@
#include <thread> // NOLINT(build/c++11)
#include "../sandbox.h" // NOLINT(build/include)
#include "absl/strings/str_cat.h"
namespace {
@ -40,13 +41,15 @@ absl::Status pull_one_url(const std::string& url, curl::CurlApi& api) {
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);
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr 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);
return absl::UnavailableError(
absl::StrCat("curl_easy_perform failed: ", curl_code));
}
// Cleanup curl easy handle
@ -70,7 +73,8 @@ absl::Status Example5() {
// 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);
return absl::UnavailableError(
absl::StrCat("curl_global_init failed: ", curl_code));
}
// Create the threads (by using futures)

View File

@ -31,7 +31,7 @@ class CurlSapiSandbox : public curl::CurlSandbox {
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder* policy_builder) override {
// Return a new policy
return (*policy_builder)
return sandbox2::PolicyBuilder()
.AllowDynamicStartup()
.AllowExit()
.AllowFork()
@ -55,13 +55,14 @@ class CurlSapiSandbox : public curl::CurlSandbox {
__NR_poll,
__NR_recvfrom,
__NR_recvmsg,
__NR_rt_sigaction,
__NR_sendmmsg,
__NR_sendto,
__NR_setsockopt,
__NR_socket,
__NR_sysinfo,
})
.AllowUnrestrictedNetworking()
.AddDirectory("/lib")
.BuildOrDie();
}
};

View File

@ -26,116 +26,91 @@
#include <thread> // NOLINT(build/c++11)
#include "absl/status/statusor.h"
#include "sandboxed_api/util/status_macros.h"
int curl::tests::CurlTestUtils::port_;
std::thread curl::tests::CurlTestUtils::server_thread_;
namespace curl::tests {
absl::Status curl::tests::CurlTestUtils::CurlTestSetUp() {
// Initialize sandbox2 and sapi
int CurlTestUtils::port_;
std::thread CurlTestUtils::server_thread_;
absl::Status CurlTestUtils::CurlTestSetUp() {
// Initialize sandbox2 and SAPI
sandbox_ = std::make_unique<curl::CurlSapiSandbox>();
absl::Status init = sandbox_->Init();
if (!init.ok()) {
return init;
}
SAPI_RETURN_IF_ERROR(sandbox_->Init());
api_ = std::make_unique<curl::CurlApi>(sandbox_.get());
// Initialize curl
absl::StatusOr<curl::CURL*> curl_handle = api_->curl_easy_init();
if (!curl_handle.ok()) {
return curl_handle.status();
SAPI_ASSIGN_OR_RETURN(curl::CURL* curl_handle, api_->curl_easy_init());
if (!curl_handle) {
return absl::UnavailableError("curl_easy_init returned nullptr");
}
if (!curl_handle.value()) {
return absl::UnavailableError("curl_easy_init returned NULL ");
}
curl_ = std::make_unique<sapi::v::RemotePtr>(curl_handle.value());
curl_ = std::make_unique<sapi::v::RemotePtr>(curl_handle);
absl::StatusOr<int> curl_code;
int curl_code = 0;
// Specify request URL
sapi::v::ConstCStr sapi_url(kUrl.data());
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() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_setopt_ptr returned with the error code " +
curl_code.value());
sapi::v::ConstCStr sapi_url(kUrl);
SAPI_ASSIGN_OR_RETURN(
curl_code, api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_URL,
sapi_url.PtrBefore()));
if (curl_code != curl::CURLE_OK) {
return absl::UnavailableError(absl::StrCat(
"curl_easy_setopt_ptr returned with the error code ", curl_code));
}
// Set 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() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_setopt_long returned with the error code " +
curl_code.value());
SAPI_ASSIGN_OR_RETURN(curl_code, api_->curl_easy_setopt_long(
curl_.get(), curl::CURLOPT_PORT, port_));
if (curl_code != curl::CURLE_OK) {
return absl::UnavailableError(absl::StrCat(
"curl_easy_setopt_long returned with the error code ", curl_code));
}
// Generate pointer to the WriteToMemory callback
void* function_ptr;
absl::Status symbol =
sandbox_->rpc_channel()->Symbol("WriteToMemory", &function_ptr);
if (!symbol.ok()) {
return symbol;
}
SAPI_RETURN_IF_ERROR(
sandbox_->rpc_channel()->Symbol("WriteToMemory", &function_ptr));
sapi::v::RemotePtr remote_function_ptr(function_ptr);
// Set WriteToMemory as the write function
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() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_setopt_ptr returned with the error code " +
curl_code.value());
SAPI_ASSIGN_OR_RETURN(curl_code, api_->curl_easy_setopt_ptr(
curl_.get(), curl::CURLOPT_WRITEFUNCTION,
&remote_function_ptr));
if (curl_code != curl::CURLE_OK) {
return absl::UnavailableError(absl::StrCat(
"curl_easy_setopt_ptr returned with the error code ", curl_code));
}
// Pass memory chunk object to the callback
chunk_ = std::make_unique<sapi::v::LenVal>(0);
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() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_setopt_ptr returned with the error code " +
curl_code.value());
SAPI_ASSIGN_OR_RETURN(
curl_code, api_->curl_easy_setopt_ptr(
curl_.get(), curl::CURLOPT_WRITEDATA, chunk_->PtrBoth()));
if (curl_code != curl::CURLE_OK) {
return absl::UnavailableError(absl::StrCat(
"curl_easy_setopt_ptr returned with the error code ", curl_code));
}
return absl::OkStatus();
}
absl::Status curl::tests::CurlTestUtils::CurlTestTearDown() {
absl::Status CurlTestUtils::CurlTestTearDown() {
// Cleanup curl
return api_->curl_easy_cleanup(curl_.get());
}
absl::StatusOr<std::string> curl::tests::CurlTestUtils::PerformRequest() {
absl::StatusOr<std::string> 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() != curl::CURLE_OK) {
return absl::UnavailableError(
"curl_easy_perform returned with the error code " + curl_code.value());
SAPI_ASSIGN_OR_RETURN(int curl_code, api_->curl_easy_perform(curl_.get()));
if (curl_code != curl::CURLE_OK) {
return absl::UnavailableError(absl::StrCat(
"curl_easy_perform returned with the error code ", curl_code));
}
// Get pointer to the memory chunk
absl::Status status = sandbox_->TransferFromSandboxee(chunk_.get());
if (!status.ok()) {
return status;
}
return std::string{reinterpret_cast<char*>(chunk_->GetData())};
SAPI_RETURN_IF_ERROR(sandbox_->TransferFromSandboxee(chunk_.get()));
return std::string(reinterpret_cast<char*>(chunk_->GetData()));
}
namespace {
@ -161,8 +136,9 @@ std::string ReadUntil(const int socket, const std::string& str,
// Parse HTTP headers to return the Content-Length
ssize_t GetContentLength(const std::string& headers) {
constexpr char kContentLength[] = "Content-Length: ";
// Find the Content-Length header
std::string::size_type length_header_start = headers.find("Content-Length: ");
const auto length_header_start = headers.find(kContentLength);
// There is no Content-Length field
if (length_header_start == std::string::npos) {
@ -170,9 +146,8 @@ ssize_t GetContentLength(const std::string& headers) {
}
// Find Content-Length string
std::string::size_type length_start =
length_header_start + std::string{"Content-Length: "}.size();
std::string::size_type length_bytes =
const auto length_start = length_header_start + strlen(kContentLength);
const auto length_bytes =
headers.find("\r\n", length_start) - length_start;
// length_bytes exceeds maximum
@ -270,7 +245,7 @@ void ServerLoop(int listening_socket, sockaddr_in socket_address) {
} // namespace
void curl::tests::CurlTestUtils::StartMockServer() {
void CurlTestUtils::StartMockServer() {
// Get the socket file descriptor
int listening_socket = socket(AF_INET, SOCK_STREAM, 0);
@ -302,3 +277,5 @@ void curl::tests::CurlTestUtils::StartMockServer() {
// Set server_thread_ operation to socket listening
server_thread_ = std::thread(ServerLoop, listening_socket, socket_address);
}
} // namespace curl::tests

View File

@ -24,33 +24,32 @@
namespace curl::tests {
// Helper class that can be used to test Curl Sandboxed
// Helper class that can be used to test Curl sandbox.
class CurlTestUtils {
protected:
// Initialize and set up the curl handle
static constexpr char kUrl[] = "http://127.0.0.1/";
// Starts a mock server (only once) that will manage connections for the
// tests. The server listens on a port asynchronously by creating a thread.
// The port number is stored in port_. Responds with "OK" to a GET request,
// responds with the POST request fields to a POST request.
static void StartMockServer();
// Initializes and sets up the curl handle.
absl::Status CurlTestSetUp();
// Clean up the curl handle
// Cleans up the curl handle.
absl::Status CurlTestTearDown();
// Perform a request to the mock server, return the response
// Performs a request to the mock server, returning the response.
absl::StatusOr<std::string> PerformRequest();
// Start a mock server (only once) that will manage connections for the tests
// The server listens on a port asynchronously by creating a thread
// The port number is stored in port_
// Responds with "OK" to a GET request
// Responds with the POST request fields to a POST request
static void StartMockServer();
static std::thread server_thread_;
static int port_;
std::unique_ptr<curl::CurlSapiSandbox> sandbox_;
std::unique_ptr<curl::CurlApi> api_;
std::unique_ptr<sapi::v::RemotePtr> curl_;
static std::thread server_thread_;
static constexpr absl::string_view kUrl = "http://127.0.0.1/";
static int port_;
private:
std::unique_ptr<sapi::v::LenVal> chunk_;
};

View File

@ -13,36 +13,48 @@
// limitations under the License.
#include "test_utils.h" // NOLINT(build/include)
#include "sandboxed_api/util/status_matchers.h"
namespace curl::tests {
namespace {
class CurlTest : public curl::tests::CurlTestUtils, public ::testing::Test {
using ::sapi::IsOk;
using ::sapi::StatusIs;
using ::testing::Eq;
using ::testing::IsTrue;
class CurlTest : public CurlTestUtils, public ::testing::Test {
protected:
void SetUp() override {
static void SetUpTestSuite() {
// Start mock server, get port number and check for any error
StartMockServer();
ASSERT_TRUE(server_thread_.joinable());
ASSERT_TRUE(CurlTestSetUp().ok());
ASSERT_THAT(server_thread_.joinable(), IsTrue());
}
static void TearDownTestSuite() {
// Detach the server thread
server_thread_.detach();
}
void SetUp() override {
ASSERT_THAT(CurlTestSetUp(), IsOk());
}
void TearDown() override {
ASSERT_TRUE(CurlTestTearDown().ok());
// Detach the server thread
server_thread_.detach();
ASSERT_THAT(CurlTestTearDown(), IsOk());
}
};
TEST_F(CurlTest, EffectiveUrl) {
sapi::v::RemotePtr effective_url_ptr(nullptr);
ASSERT_TRUE(PerformRequest().ok());
ASSERT_THAT(PerformRequest().status(), IsOk());
// Get effective URL
sapi::v::RemotePtr effective_url_ptr(nullptr);
SAPI_ASSERT_OK_AND_ASSIGN(
int getinfo_code,
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_EFFECTIVE_URL,
effective_url_ptr.PtrBoth()));
ASSERT_EQ(getinfo_code, curl::CURLE_OK);
ASSERT_THAT(getinfo_code, Eq(curl::CURLE_OK));
// Store effective URL in a string
SAPI_ASSERT_OK_AND_ASSIGN(std::string effective_url,
@ -50,15 +62,14 @@ TEST_F(CurlTest, EffectiveUrl) {
effective_url_ptr.GetPointedVar())));
// Compare effective URL with original URL
ASSERT_EQ(effective_url, kUrl);
ASSERT_THAT(effective_url, Eq(kUrl));
}
TEST_F(CurlTest, EffectivePort) {
sapi::v::Int effective_port;
ASSERT_TRUE(PerformRequest().ok());
ASSERT_THAT(PerformRequest().status(), IsOk());
// Get effective port
sapi::v::Int effective_port;
SAPI_ASSERT_OK_AND_ASSIGN(
int getinfo_code,
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_PRIMARY_PORT,
@ -70,11 +81,10 @@ TEST_F(CurlTest, EffectivePort) {
}
TEST_F(CurlTest, ResponseCode) {
sapi::v::Int response_code;
ASSERT_TRUE(PerformRequest().ok());
ASSERT_THAT(PerformRequest().status(), IsOk());
// Get response code
sapi::v::Int response_code;
SAPI_ASSERT_OK_AND_ASSIGN(
int getinfo_code,
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_RESPONSE_CODE,
@ -106,14 +116,14 @@ TEST_F(CurlTest, ContentType) {
ASSERT_EQ(content_type, "text/plain");
}
TEST_F(CurlTest, GETResponse) {
TEST_F(CurlTest, GetResponse) {
SAPI_ASSERT_OK_AND_ASSIGN(std::string response, PerformRequest());
// Compare response with expected response
ASSERT_EQ(response, "OK");
}
TEST_F(CurlTest, POSTResponse) {
TEST_F(CurlTest, PostResponse) {
sapi::v::ConstCStr post_fields("postfields");
// Set request method to POST
@ -143,3 +153,4 @@ TEST_F(CurlTest, POSTResponse) {
}
} // namespace
} // namespace curl::tests