mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Address review comments
This commit is contained in:
parent
bbebeee1a6
commit
eb783de3f5
|
@ -33,4 +33,5 @@ set(BUILD_TESTING OFF)
|
|||
add_subdirectory(curl)
|
||||
target_link_libraries(curl_wrapper_and_callbacks
|
||||
CURL::libcurl
|
||||
sapi::sapi
|
||||
)
|
||||
|
|
|
@ -19,68 +19,64 @@
|
|||
|
||||
#include <curl/curl.h>
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLcode curl_easy_setopt_ptr(CURL* handle, CURLoption option,
|
||||
void* parameter);
|
||||
extern "C" {
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLcode curl_easy_setopt_long(CURL* handle, CURLoption option,
|
||||
long parameter);
|
||||
CURLcode curl_easy_setopt_ptr(CURL* handle, CURLoption option, void* parameter);
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLcode curl_easy_setopt_curl_off_t(CURL* handle, CURLoption option,
|
||||
CURLcode curl_easy_setopt_long(CURL* handle, CURLoption option, long parameter);
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
CURLcode curl_easy_setopt_curl_off_t(CURL* handle, CURLoption option,
|
||||
curl_off_t parameter);
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLcode curl_easy_getinfo_ptr(CURL* handle, CURLINFO option,
|
||||
void* parameter);
|
||||
CURLcode curl_easy_getinfo_ptr(CURL* handle, CURLINFO option, void* parameter);
|
||||
|
||||
// The typedef and wrapper method are needed because the original method has
|
||||
// some conflicts in curl_sapi.sapi.h
|
||||
extern "C" typedef time_t time_t_sapi;
|
||||
extern "C" time_t_sapi curl_getdate_sapi(char* datestring, time_t_sapi* now);
|
||||
typedef time_t time_t_sapi;
|
||||
time_t_sapi curl_getdate_sapi(char* datestring, time_t_sapi* now);
|
||||
|
||||
// The typedef and wrapper method are needed because the original method has
|
||||
// some conflicts in curl_sapi.sapi.h
|
||||
extern "C" typedef fd_set fd_set_sapi;
|
||||
extern "C" CURLMcode curl_multi_fdset_sapi(CURLM* multi_handle,
|
||||
fd_set_sapi* read_fd_set,
|
||||
typedef fd_set fd_set_sapi;
|
||||
CURLMcode curl_multi_fdset_sapi(CURLM* multi_handle, fd_set_sapi* read_fd_set,
|
||||
fd_set_sapi* write_fd_set,
|
||||
fd_set_sapi* exc_fd_set,
|
||||
int* max_fd);
|
||||
fd_set_sapi* exc_fd_set, int* max_fd);
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLMcode curl_multi_setopt_ptr(CURLM* handle, CURLMoption option,
|
||||
CURLMcode curl_multi_setopt_ptr(CURLM* handle, CURLMoption option,
|
||||
void* parameter);
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLMcode curl_multi_setopt_long(CURLM* handle, CURLMoption option,
|
||||
CURLMcode curl_multi_setopt_long(CURLM* handle, CURLMoption option,
|
||||
long parameter);
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLMcode curl_multi_setopt_curl_off_t(CURLM* handle,
|
||||
CURLMoption option,
|
||||
CURLMcode curl_multi_setopt_curl_off_t(CURLM* handle, CURLMoption option,
|
||||
curl_off_t parameter);
|
||||
|
||||
// The wrapper method is needed because incomplete array type is not supported
|
||||
extern "C" CURLMcode curl_multi_poll_sapi(CURLM* multi_handle,
|
||||
CURLMcode curl_multi_poll_sapi(CURLM* multi_handle,
|
||||
struct curl_waitfd* extra_fds,
|
||||
unsigned int extra_nfds,
|
||||
int timeout_ms, int* numfds);
|
||||
unsigned int extra_nfds, int timeout_ms,
|
||||
int* numfds);
|
||||
|
||||
// The wrapper method is needed because incomplete array type is not supported
|
||||
extern "C" CURLMcode curl_multi_wait_sapi(CURLM* multi_handle,
|
||||
CURLMcode curl_multi_wait_sapi(CURLM* multi_handle,
|
||||
struct curl_waitfd* extra_fds,
|
||||
unsigned int extra_nfds,
|
||||
int timeout_ms, int* numfds);
|
||||
unsigned int extra_nfds, int timeout_ms,
|
||||
int* numfds);
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLSHcode curl_share_setopt_ptr(CURLSH* handle, CURLSHoption option,
|
||||
CURLSHcode curl_share_setopt_ptr(CURLSH* handle, CURLSHoption option,
|
||||
void* parameter);
|
||||
|
||||
// The wrapper method is needed to make the variadic argument explicit
|
||||
extern "C" CURLSHcode curl_share_setopt_long(CURLSH* handle,
|
||||
CURLSHoption option,
|
||||
CURLSHcode curl_share_setopt_long(CURLSH* handle, CURLSHoption option,
|
||||
long parameter);
|
||||
}
|
||||
|
||||
#endif // CURL_WRAPPER_H
|
||||
|
|
|
@ -8,5 +8,5 @@ This is the list of the examples:
|
|||
- **example2**: sandboxed version of [getinmemory.c](https://curl.haxx.se/libcurl/c/getinmemory.html). Same HTTP request as example1. The difference is that this example uses a callback to save the page directly in memory. Only the page size is printed out.
|
||||
- **example3**: sandboxed version of [simplessl.c](https://curl.haxx.se/libcurl/c/simplessl.html). HTTPS request of the [example.com](https://example.com) page, using SSL authentication. This script takes 4 arguments (SSL certificates file, SSL keys file, SSL keys password and CA certificates files), and prints out the page.
|
||||
- **example4**: sandboxed version of [multi-poll.c](https://curl.haxx.se/libcurl/c/multi-poll.html). Same HTTP request as example1, with the addition of a polling method that can be used to track the status of the request. The page is printed out after it is downloaded.
|
||||
- **example5**: sandboxed version of [multithread.c](https://curl.haxx.se/libcurl/c/multithread.html). Four HTTP request of the pages [example.com](http://example.com), [example.edu](http://example.edu), [example.net](http://example.net) and [example.org](http://example.org), performed at the same time using libcurl's multithreading methods. The threads' status and the pages are printed out.
|
||||
- **example5**: sandboxed version of [multithread.c](https://curl.haxx.se/libcurl/c/multithread.html). Four HTTP request of the pages [example.com](http://example.com), [example.edu](http://example.edu), [example.net](http://example.net) and [example.org](http://example.org), performed at the same time using libcurl's multithreading methods. The pages are printed out.
|
||||
- **example6**: sandboxed version of [simple.c](https://curl.haxx.se/libcurl/c/simple.html). Performs the same tasks as example1, but Sandbox API Transactions are used to show how they can be used to perform a simple request.
|
|
@ -18,22 +18,25 @@
|
|||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "sandboxed_api/vars.h"
|
||||
|
||||
// Function taken from curl's getinmemory.c
|
||||
size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb,
|
||||
void* userp) {
|
||||
size_t realsize = size * nmemb;
|
||||
struct MemoryStruct* mem = (struct MemoryStruct*)userp;
|
||||
size_t real_size = size * nmemb;
|
||||
auto* mem = static_cast<sapi::LenValStruct*>(userp);
|
||||
|
||||
char* ptr = (char*)realloc(mem->memory, mem->size + realsize + 1);
|
||||
if (ptr == NULL) { // Out of memory
|
||||
char* ptr = static_cast<char*>(realloc(mem->data, mem->size + real_size + 1));
|
||||
if (ptr == nullptr) { // Out of memory
|
||||
std::cout << "not enough memory (realloc returned NULL)\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem->memory = ptr;
|
||||
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->memory[mem->size] = 0;
|
||||
mem->data = ptr;
|
||||
auto data = static_cast<char*>(mem->data);
|
||||
memcpy(&(data[mem->size]), contents, real_size);
|
||||
mem->size += real_size;
|
||||
data[mem->size] = 0;
|
||||
|
||||
return realsize;
|
||||
return real_size;
|
||||
}
|
||||
|
|
|
@ -17,11 +17,6 @@
|
|||
|
||||
#include <curl/curl.h>
|
||||
|
||||
extern "C" struct MemoryStruct {
|
||||
char* memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
extern "C" size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb,
|
||||
void* userp);
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@ int main(int argc, char* argv[]) {
|
|||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
sapi::StatusOr<CURL*> status_or_curl;
|
||||
sapi::StatusOr<int> status_or_int;
|
||||
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
|
@ -36,36 +34,38 @@ int main(int argc, char* argv[]) {
|
|||
CurlApi api(&sandbox);
|
||||
|
||||
// Initialize the curl session
|
||||
status_or_curl = api.curl_easy_init();
|
||||
if (!status_or_curl.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << status_or_curl.status();
|
||||
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(status_or_curl.value());
|
||||
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");
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
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
|
||||
status_or_int = api.curl_easy_setopt_long(&curl, CURLOPT_FOLLOWLOCATION, 1l);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << status_or_int.status();
|
||||
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
|
||||
status_or_int = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 0l);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << status_or_int.status();
|
||||
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
|
||||
status_or_int = api.curl_easy_perform(&curl);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << status_or_int.status();
|
||||
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
|
||||
|
|
|
@ -30,8 +30,6 @@ int main(int argc, char* argv[]) {
|
|||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
sapi::StatusOr<CURL*> status_or_curl;
|
||||
sapi::StatusOr<int> status_or_int;
|
||||
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
|
@ -42,63 +40,64 @@ int main(int argc, char* argv[]) {
|
|||
CurlApi api(&sandbox);
|
||||
|
||||
// Generate pointer to WriteMemoryCallback function
|
||||
sapi::RPCChannel rpcc(sandbox.comms());
|
||||
size_t (*_function_ptr)(void*, size_t, size_t, void*);
|
||||
status = rpcc.Symbol("WriteMemoryCallback", (void**)&_function_ptr);
|
||||
void* function_ptr;
|
||||
status = sandbox.rpc_channel()->Symbol("WriteMemoryCallback", &function_ptr);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "rpcc.Symbol failed: " << status;
|
||||
LOG(FATAL) << "sapi::Sandbox::rpc_channel().Symbol failed: " << status;
|
||||
}
|
||||
sapi::v::RemotePtr remote_function_ptr((void*)_function_ptr);
|
||||
sapi::v::RemotePtr remote_function_ptr(function_ptr);
|
||||
|
||||
// Initialize the curl session
|
||||
status_or_curl = api.curl_easy_init();
|
||||
if (!status_or_curl.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << status_or_curl.status();
|
||||
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(status_or_curl.value());
|
||||
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");
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
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 WriteMemoryCallback as the write function
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEFUNCTION,
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEFUNCTION,
|
||||
&remote_function_ptr);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Pass 'chunk' struct to the callback function
|
||||
sapi::v::Struct<MemoryStruct> chunk;
|
||||
status_or_int =
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEDATA, chunk.PtrBoth());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Set a user agent
|
||||
sapi::v::ConstCStr user_agent("libcurl-agent/1.0");
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_USERAGENT,
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_USERAGENT,
|
||||
user_agent.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
status_or_int = api.curl_easy_perform(&curl);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
|
||||
// Retrieve memory size
|
||||
sapi::v::Int size;
|
||||
size.SetRemote(&((MemoryStruct*)chunk.GetRemote())->size);
|
||||
size.SetRemote(&(static_cast<sapi::LenValStruct*>(chunk.GetRemote()))->size);
|
||||
status = sandbox.TransferFromSandboxee(&size);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "sandbox.TransferFromSandboxee failed: " << status;
|
||||
|
|
|
@ -55,8 +55,6 @@ int main(int argc, char* argv[]) {
|
|||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
sapi::StatusOr<int> status_or_int;
|
||||
sapi::StatusOr<CURL*> status_or_curl;
|
||||
|
||||
// Get input parameters (should be absolute paths)
|
||||
if (argc != 5) {
|
||||
|
@ -75,79 +73,81 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
CurlApi api(&sandbox);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
status_or_int = api.curl_global_init(3l);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
|
||||
// Initialize curl easy handle
|
||||
status_or_curl = api.curl_easy_init();
|
||||
if (!status_or_curl.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << status_or_curl.status();
|
||||
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(status_or_curl.value());
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
}
|
||||
|
||||
// Specify URL to get (using HTTPS)
|
||||
sapi::v::ConstCStr url("https://example.com");
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
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 SSL certificate type to "PEM"
|
||||
sapi::v::ConstCStr ssl_cert_type("PEM");
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERTTYPE,
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERTTYPE,
|
||||
ssl_cert_type.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Set the certificate for client authentication
|
||||
sapi::v::ConstCStr sapi_ssl_certificate(ssl_certificate.c_str());
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERT,
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERT,
|
||||
sapi_ssl_certificate.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Set the private key for client authentication
|
||||
sapi::v::ConstCStr sapi_ssl_key(ssl_key.c_str());
|
||||
status_or_int =
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLKEY, sapi_ssl_key.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Set the password used to protect the private key
|
||||
sapi::v::ConstCStr sapi_ssl_key_password(ssl_key_password.c_str());
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_KEYPASSWD,
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_KEYPASSWD,
|
||||
sapi_ssl_key_password.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Set the file with the certificates vaildating the server
|
||||
sapi::v::ConstCStr sapi_ca_certificates(ca_certificates.c_str());
|
||||
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_CAINFO,
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_CAINFO,
|
||||
sapi_ca_certificates.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Verify the authenticity of the server
|
||||
status_or_int = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
status_or_int = api.curl_easy_perform(&curl);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << status_or_int.status();
|
||||
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 easy handle
|
||||
|
|
|
@ -26,9 +26,6 @@ int main(int argc, char* argv[]) {
|
|||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
sapi::StatusOr<int> status_or_int;
|
||||
sapi::StatusOr<CURL*> status_or_curl;
|
||||
sapi::StatusOr<CURLM*> status_or_curlm;
|
||||
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
|
@ -41,71 +38,72 @@ int main(int argc, char* argv[]) {
|
|||
// Number of running handles
|
||||
sapi::v::Int still_running(1);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
status_or_int = api.curl_global_init(3l);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
|
||||
// Initialize http_handle
|
||||
status_or_curl = api.curl_easy_init();
|
||||
if (!status_or_curl.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << status_or_curl.status();
|
||||
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(status_or_curl.value());
|
||||
sapi::v::RemotePtr http_handle(curl_handle.value());
|
||||
if (!http_handle.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: http_handle is NULL";
|
||||
}
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
status_or_int =
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&http_handle, CURLOPT_URL, url.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Initialize multi_handle
|
||||
status_or_curlm = api.curl_multi_init();
|
||||
if (!status_or_curlm.ok()) {
|
||||
LOG(FATAL) << "curl_multi_init failed: " << status_or_curlm.status();
|
||||
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(status_or_curlm.value());
|
||||
sapi::v::RemotePtr multi_handle(curlm_handle.value());
|
||||
if (!multi_handle.GetValue()) {
|
||||
LOG(FATAL) << "curl_multi_init failed: multi_handle is NULL";
|
||||
}
|
||||
|
||||
// Add http_handle to the multi stack
|
||||
status_or_int = api.curl_multi_add_handle(&multi_handle, &http_handle);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_add_handle failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
|
||||
while (still_running.GetValue()) {
|
||||
sapi::v::Int numfds(0);
|
||||
|
||||
// Perform the request
|
||||
status_or_int =
|
||||
api.curl_multi_perform(&multi_handle, still_running.PtrBoth());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_mutli_perform failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
|
||||
if (still_running.GetValue()) {
|
||||
// Wait for an event or timeout
|
||||
sapi::v::NullPtr null_ptr;
|
||||
status_or_int = api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0,
|
||||
1000, numfds.PtrBoth());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_poll_sapi failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove http_handle from the multi stack
|
||||
status_or_int = api.curl_multi_remove_handle(&multi_handle, &http_handle);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_remove_handle failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
|
||||
// Cleanup http_handle
|
||||
|
@ -115,9 +113,9 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
// Cleanup multi_handle
|
||||
status_or_int = api.curl_multi_cleanup(&multi_handle);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_cleanup failed: " << status_or_int.status();
|
||||
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();
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
|
|
|
@ -21,54 +21,41 @@
|
|||
|
||||
#include "../sandbox.h"
|
||||
|
||||
struct thread_args {
|
||||
const char* url;
|
||||
CurlApi* api;
|
||||
};
|
||||
|
||||
constexpr int kThreadsnumber = 4;
|
||||
|
||||
void* pull_one_url(void* args) {
|
||||
absl::Status status;
|
||||
sapi::StatusOr<CURL*> status_or_curl;
|
||||
sapi::StatusOr<int> status_or_int;
|
||||
|
||||
CurlApi& api = *((thread_args*)args)->api;
|
||||
|
||||
void pull_one_url(const std::string& url, CurlApi& api) {
|
||||
// Initialize the curl session
|
||||
status_or_curl = api.curl_easy_init();
|
||||
if (!status_or_curl.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << status_or_curl.status();
|
||||
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(status_or_curl.value());
|
||||
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 sapi_url(((thread_args*)args)->url);
|
||||
status_or_int =
|
||||
sapi::v::ConstCStr sapi_url(url.c_str());
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, sapi_url.PtrBefore());
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << status_or_int.status();
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
status_or_int = api.curl_easy_perform(&curl);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << status_or_int.status();
|
||||
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);
|
||||
absl::Status status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* const urls[kThreadsnumber] = {
|
||||
const std::vector<std::string> urls = {
|
||||
"http://example.com", "http://example.edu", "http://example.net",
|
||||
"http://example.org"};
|
||||
|
||||
|
@ -76,10 +63,7 @@ int main(int argc, char* argv[]) {
|
|||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
pthread_t tid[kThreadsnumber];
|
||||
|
||||
absl::Status status;
|
||||
sapi::StatusOr<int> status_or_int;
|
||||
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
|
@ -89,29 +73,23 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
CurlApi api(&sandbox);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
status_or_int = api.curl_global_init(3l);
|
||||
if (!status_or_int.ok() or status_or_int.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << status_or_int.status();
|
||||
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
|
||||
for (int i = 0; i < kThreadsnumber; ++i) {
|
||||
thread_args args = {urls[i], &api};
|
||||
int error = pthread_create(&tid[i], NULL, pull_one_url, (void*)&args);
|
||||
if (error) {
|
||||
LOG(FATAL) << "pthread_create failed";
|
||||
}
|
||||
std::cout << "Thread " << i << " gets " << urls[i] << std::endl;
|
||||
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 (int i = 0; i < kThreadsnumber; ++i) {
|
||||
int error = pthread_join(tid[i], NULL);
|
||||
if (error) {
|
||||
LOG(FATAL) << "pthread_join failed";
|
||||
}
|
||||
std::cout << "Thread " << i << " terminated" << std::endl;
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
|
|
|
@ -17,19 +17,21 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
size_t WriteToMemory(char* contents, size_t size, size_t num_bytes,
|
||||
#include "sandboxed_api/vars.h"
|
||||
|
||||
size_t WriteToMemoryTests(char* contents, size_t size, size_t num_bytes,
|
||||
void* userp) {
|
||||
size_t real_size = size * num_bytes;
|
||||
auto* mem = static_cast<MemoryStruct*>(userp);
|
||||
auto* mem = static_cast<sapi::LenValStruct*>(userp);
|
||||
|
||||
char* ptr =
|
||||
static_cast<char*>(realloc(mem->memory, mem->size + real_size + 1));
|
||||
char* ptr = static_cast<char*>(realloc(mem->data, mem->size + real_size + 1));
|
||||
if (ptr == nullptr) return 0;
|
||||
|
||||
mem->memory = ptr;
|
||||
memcpy(&(mem->memory[mem->size]), contents, real_size);
|
||||
mem->data = ptr;
|
||||
auto data = static_cast<char*>(mem->data);
|
||||
memcpy(&(data[mem->size]), contents, real_size);
|
||||
mem->size += real_size;
|
||||
mem->memory[mem->size] = 0;
|
||||
data[mem->size] = 0;
|
||||
|
||||
return real_size;
|
||||
}
|
||||
|
|
|
@ -17,13 +17,8 @@
|
|||
|
||||
#include <curl/curl.h>
|
||||
|
||||
extern "C" struct MemoryStruct {
|
||||
char* memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
// Append contents to the string stored by userp (userp is a MemoryStruct*)
|
||||
extern "C" size_t WriteToMemory(char* contents, size_t size, size_t num_bytes,
|
||||
void* userp);
|
||||
extern "C" size_t WriteToMemoryTests(char* contents, size_t size,
|
||||
size_t num_bytes, void* userp);
|
||||
|
||||
#endif // TESTS_CALLBACKS_H
|
||||
|
|
|
@ -27,243 +27,261 @@
|
|||
long int CurlTestUtils::port_;
|
||||
std::thread CurlTestUtils::server_thread_;
|
||||
|
||||
void CurlTestUtils::CurlTestSetUp() {
|
||||
absl::Status CurlTestUtils::CurlTestSetUp() {
|
||||
// Initialize sandbox2 and sapi
|
||||
sandbox_ = std::make_unique<CurlSapiSandbox>();
|
||||
ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
|
||||
absl::Status init = sandbox_->Init();
|
||||
if (!init.ok()) {
|
||||
return init;
|
||||
}
|
||||
api_ = std::make_unique<CurlApi>(sandbox_.get());
|
||||
|
||||
// Initialize curl
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(void* curl_raw_ptr, api_->curl_easy_init());
|
||||
curl_ = std::make_unique<sapi::v::RemotePtr>(curl_raw_ptr);
|
||||
absl::StatusOr<CURL*> curl_handle = api_->curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
return curl_handle.status();
|
||||
} else if (!curl_handle.value()) {
|
||||
return absl::UnavailableError("curl_easy_init returned NULL ");
|
||||
}
|
||||
curl_ = std::make_unique<sapi::v::RemotePtr>(curl_handle.value());
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
|
||||
// Specify request URL
|
||||
sapi::v::ConstCStr sapi_url(kUrl.data());
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(int setopt_url_code,
|
||||
api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_URL,
|
||||
sapi_url.PtrBefore()));
|
||||
ASSERT_EQ(setopt_url_code, CURLE_OK);
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_URL,
|
||||
sapi_url.PtrBefore());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
} else if (curl_code.value() != CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
}
|
||||
|
||||
// Set port
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int setopt_port_code,
|
||||
api_->curl_easy_setopt_long(curl_.get(), CURLOPT_PORT, port_));
|
||||
ASSERT_EQ(setopt_port_code, CURLE_OK);
|
||||
curl_code = api_->curl_easy_setopt_long(curl_.get(), CURLOPT_PORT, port_);
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
} else if (curl_code.value() != CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_long returned with the error code " +
|
||||
curl_code.value());
|
||||
}
|
||||
|
||||
// Generate pointer to the WriteToMemory callback
|
||||
sapi::RPCChannel rpcc(sandbox_->comms());
|
||||
size_t (*_function_ptr)(char*, size_t, size_t, void*);
|
||||
ASSERT_THAT(rpcc.Symbol("WriteToMemory", (void**)&_function_ptr),
|
||||
sapi::IsOk());
|
||||
sapi::v::RemotePtr remote_function_ptr((void*)_function_ptr);
|
||||
void* function_ptr;
|
||||
absl::Status symbol =
|
||||
sandbox_->rpc_channel()->Symbol("WriteToMemoryTests", &function_ptr);
|
||||
if (!symbol.ok()) {
|
||||
return symbol;
|
||||
}
|
||||
sapi::v::RemotePtr remote_function_ptr(function_ptr);
|
||||
|
||||
// Set WriteToMemory as the write function
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int setopt_write_function,
|
||||
api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEFUNCTION,
|
||||
&remote_function_ptr));
|
||||
ASSERT_EQ(setopt_write_function, CURLE_OK);
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEFUNCTION,
|
||||
&remote_function_ptr);
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
} else if (curl_code.value() != CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
}
|
||||
|
||||
// Pass memory chunk object to the callback
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int setopt_write_data,
|
||||
api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEDATA,
|
||||
chunk_.PtrBoth()));
|
||||
ASSERT_EQ(setopt_write_data, CURLE_OK);
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEDATA,
|
||||
chunk_.PtrBoth());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
} else if (curl_code.value() != CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
}
|
||||
|
||||
void CurlTestUtils::CurlTestTearDown() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CurlTestUtils::CurlTestTearDown() {
|
||||
// Cleanup curl
|
||||
ASSERT_THAT(api_->curl_easy_cleanup(curl_.get()), sapi::IsOk());
|
||||
return api_->curl_easy_cleanup(curl_.get());
|
||||
}
|
||||
|
||||
void CurlTestUtils::PerformRequest(std::string& response) {
|
||||
absl::StatusOr<std::string> CurlTestUtils::PerformRequest() {
|
||||
// Perform the request
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(int perform_code,
|
||||
api_->curl_easy_perform(curl_.get()));
|
||||
ASSERT_EQ(perform_code, CURLE_OK);
|
||||
absl::StatusOr<int> curl_code = api_->curl_easy_perform(curl_.get());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
} else if (curl_code.value() != CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_perform returned with the error code " + curl_code.value());
|
||||
}
|
||||
|
||||
// Get pointer to the memory chunk
|
||||
sapi::v::GenericPtr remote_ptr;
|
||||
remote_ptr.SetRemote(&((MemoryStruct*)chunk_.GetRemote())->memory);
|
||||
ASSERT_THAT(sandbox_->TransferFromSandboxee(&remote_ptr), sapi::IsOk());
|
||||
remote_ptr.SetRemote(
|
||||
&(static_cast<sapi::LenValStruct*>(chunk_.GetRemote()))->data);
|
||||
absl::Status transfer = sandbox_->TransferFromSandboxee(&remote_ptr);
|
||||
if (!transfer.ok()) {
|
||||
return transfer;
|
||||
}
|
||||
void* chunk_ptr = (void*)remote_ptr.GetValue();
|
||||
|
||||
// Get the string and store it in response
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
response, sandbox_->GetCString(sapi::v::RemotePtr(chunk_ptr)));
|
||||
// Get the string
|
||||
absl::StatusOr<std::string> response =
|
||||
sandbox_->GetCString(sapi::v::RemotePtr(chunk_ptr));
|
||||
if (!response.ok()) {
|
||||
return response.status();
|
||||
}
|
||||
|
||||
void CurlTestUtils::PerformRequest() {
|
||||
// If the response is not needed, pass a string that will be discarded
|
||||
std::string discarded_response;
|
||||
PerformRequest(discarded_response);
|
||||
return response.value();
|
||||
}
|
||||
|
||||
// Read the socket until str is completely read
|
||||
std::string ReadUntil(const int socket, const std::string& str,
|
||||
const size_t max_request_size) {
|
||||
char buf[max_request_size] = {};
|
||||
size_t read_bytes = 0;
|
||||
|
||||
// Read one char at a time until str is suffix of buf
|
||||
do {
|
||||
if (read_bytes >= max_request_size ||
|
||||
read(socket, buf + read_bytes, 1) == -1) {
|
||||
return "";
|
||||
}
|
||||
++read_bytes;
|
||||
} while (std::string{buf + std::max(size_t{0}, read_bytes - str.size())} !=
|
||||
str);
|
||||
|
||||
buf[read_bytes] = '\0';
|
||||
return std::string{buf};
|
||||
}
|
||||
|
||||
// Parse HTTP headers to return the Content-Length
|
||||
size_t GetContentLength(const std::string& headers) {
|
||||
// Find the Content-Length header
|
||||
const char* length_header_start = strstr(headers.c_str(), "Content-Length: ");
|
||||
|
||||
// There is no Content-Length field
|
||||
if (!length_header_start) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find Content-Length string
|
||||
const char* length_start = length_header_start + strlen("Content-Length: ");
|
||||
size_t length_bytes = strstr(length_start, "\r\n") - length_start;
|
||||
if (length_bytes >= 64) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert Content-Length string value to int
|
||||
char content_length_string[64];
|
||||
strncpy(content_length_string, length_start, length_bytes);
|
||||
|
||||
return atoi(content_length_string);
|
||||
}
|
||||
|
||||
// Read exactly content_bytes from the socket
|
||||
std::string ReadExact(int socket, size_t content_bytes) {
|
||||
char buf[content_bytes + 1] = {};
|
||||
size_t read_bytes = 0;
|
||||
|
||||
// Read until content_bytes chars are read
|
||||
do {
|
||||
int num_bytes;
|
||||
if ((num_bytes = read(socket, buf + read_bytes,
|
||||
sizeof(buf) - read_bytes - 1)) == -1) {
|
||||
return "";
|
||||
}
|
||||
read_bytes += num_bytes;
|
||||
} while (read_bytes < content_bytes);
|
||||
|
||||
buf[content_bytes] = '\0';
|
||||
|
||||
return std::string{buf};
|
||||
}
|
||||
|
||||
void CurlTestUtils::StartMockServer() {
|
||||
// Get ai_list, a list of addrinfo structures, the port will be set later
|
||||
addrinfo hints{AI_PASSIVE, AF_INET, SOCK_STREAM};
|
||||
addrinfo* ai_list;
|
||||
if (getaddrinfo("127.0.0.1", NULL, &hints, &ai_list) < 0) {
|
||||
// Get the socket file descriptor
|
||||
int listening_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
// Create the socket address object
|
||||
// The port is set to 0, meaning that it will be auto assigned
|
||||
// Only local connections can access this socket
|
||||
sockaddr_in socket_address{AF_INET, 0, htonl(INADDR_LOOPBACK)};
|
||||
socklen_t socket_address_size = sizeof(socket_address);
|
||||
if (listening_socket == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop over ai_list, until a socket is created
|
||||
int listening_socket;
|
||||
for (addrinfo* p = ai_list;; p = p->ai_next) {
|
||||
if (p == nullptr) {
|
||||
// Bind the file descriptor to the socket address object
|
||||
if (bind(listening_socket, (sockaddr*)&socket_address, socket_address_size) ==
|
||||
-1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try creating a socket
|
||||
listening_socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||
if (listening_socket >= 0) {
|
||||
// Try binding the socket to the address
|
||||
if (bind(listening_socket, p->ai_addr, p->ai_addrlen) >= 0) {
|
||||
// Assign an arbitrary available port to the socket address object
|
||||
if (getsockname(listening_socket, p->ai_addr, &p->ai_addrlen) == -1) {
|
||||
// Assign an available port to the socket address object
|
||||
if (getsockname(listening_socket, (sockaddr*)&socket_address,
|
||||
&socket_address_size) == -1) {
|
||||
return;
|
||||
}
|
||||
port_ = ntohs(((struct sockaddr_in*)p->ai_addr)->sin_port);
|
||||
|
||||
break;
|
||||
|
||||
} else {
|
||||
close(listening_socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(ai_list);
|
||||
|
||||
// Listen on the socket
|
||||
if (listen(listening_socket, 256) == -1) {
|
||||
return;
|
||||
}
|
||||
// Get the port number
|
||||
port_ = ntohs(socket_address.sin_port);
|
||||
|
||||
// Set server_thread_ operation to socket listening
|
||||
server_thread_ = std::thread([=] {
|
||||
// Create the master fd_set containing listening_socket
|
||||
fd_set master_fd_set;
|
||||
FD_ZERO(&master_fd_set);
|
||||
FD_SET(listening_socket, &master_fd_set);
|
||||
|
||||
// Create an empty fd_set, will be used for making copies of master_fd_set
|
||||
fd_set copy_fd_set;
|
||||
FD_ZERO(©_fd_set);
|
||||
|
||||
int max_fd = listening_socket;
|
||||
|
||||
// Keep calling select and block after a new event happens
|
||||
// Doesn't stop until the process doing tests is terminated
|
||||
for (;;) {
|
||||
copy_fd_set = master_fd_set;
|
||||
|
||||
// Block and wait for a file descriptor to be ready
|
||||
if (select(max_fd + 1, ©_fd_set, nullptr, nullptr, nullptr) == -1) {
|
||||
close(listening_socket);
|
||||
// Listen on the socket (maximum 1 connection)
|
||||
if (listen(listening_socket, 1) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A file descriptor is ready, loop over all the fds to find it
|
||||
for (int i = 0; i <= max_fd; ++i) {
|
||||
// i is not a file desciptor in the set, skip it
|
||||
if (!FD_ISSET(i, ©_fd_set)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == listening_socket) { // CASE 1: a new connection
|
||||
|
||||
sockaddr_storage remote_address;
|
||||
socklen_t remote_address_size = sizeof(remote_address);
|
||||
|
||||
// Accept the connection
|
||||
int accepted_socket =
|
||||
accept(listening_socket, (sockaddr*)&remote_address,
|
||||
&remote_address_size);
|
||||
// File descriptor to the connection socket
|
||||
// This blocks the thread until a connection is established
|
||||
int accepted_socket = accept(listening_socket, (sockaddr*)&socket_address,
|
||||
(socklen_t*)&socket_address_size);
|
||||
if (accepted_socket == -1) {
|
||||
if (errno == ECONNABORTED)
|
||||
continue;
|
||||
else {
|
||||
close(listening_socket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the socket's nonblocking flag to true
|
||||
int flag = fcntl(accepted_socket, F_GETFL, nullptr);
|
||||
fcntl(accepted_socket, F_SETFL, flag | O_NONBLOCK);
|
||||
|
||||
// Add the new socket to the fd_set and update max_fd
|
||||
FD_SET(accepted_socket, &master_fd_set);
|
||||
max_fd = std::max(max_fd, accepted_socket);
|
||||
|
||||
} else { // CASE 2: a request from an existing connection
|
||||
|
||||
constexpr int kMaxRequestSize = 4096;
|
||||
char buf[kMaxRequestSize] = {};
|
||||
|
||||
ssize_t num_bytes = 0;
|
||||
size_t read_bytes = 0;
|
||||
bool close_socket = false;
|
||||
// Read until the end of the headers
|
||||
std::string headers =
|
||||
ReadUntil(accepted_socket, "\r\n\r\n", kMaxRequestSize);
|
||||
|
||||
// Read from the nonblocking socket until recv returns -1 and
|
||||
// errno is EAGAIN or EWOULDBLOCK (busy wait)
|
||||
do {
|
||||
num_bytes = recv(i, buf + read_bytes, sizeof(buf) - read_bytes, 0);
|
||||
|
||||
// An error happened, close the socket
|
||||
if (num_bytes == -1 and errno != EAGAIN and errno != EWOULDBLOCK) {
|
||||
close_socket = true;
|
||||
break;
|
||||
// Get the length of the request content
|
||||
size_t content_length = GetContentLength(headers);
|
||||
if (content_length > kMaxRequestSize - headers.size()) {
|
||||
close(accepted_socket);
|
||||
return;
|
||||
}
|
||||
|
||||
// The connection was closed, close the socket
|
||||
if (num_bytes == 0) {
|
||||
close_socket = true;
|
||||
break;
|
||||
}
|
||||
|
||||
read_bytes += num_bytes;
|
||||
|
||||
} while (num_bytes > 0);
|
||||
|
||||
if (close_socket) {
|
||||
// Close the connection and remove it from fd_set
|
||||
close(i);
|
||||
FD_CLR(i, &master_fd_set);
|
||||
continue;
|
||||
}
|
||||
// Read the request content
|
||||
std::string content = ReadExact(accepted_socket, content_length);
|
||||
|
||||
// Prepare a response for the request
|
||||
std::string http_response =
|
||||
"HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: ";
|
||||
|
||||
if (strncmp(buf, "GET", 3) == 0) {
|
||||
http_response += std::to_string(kSimpleResponse.size()) + "\n\n" +
|
||||
if (headers.substr(0, 3) == "GET") {
|
||||
http_response += std::to_string(kSimpleResponse.size()) + "\r\n\r\n" +
|
||||
std::string{kSimpleResponse};
|
||||
|
||||
} else if (strncmp(buf, "POST", 4) == 0) {
|
||||
char* post_fields = strstr(buf, "\r\n\r\n");
|
||||
post_fields += 4; // Points to the first char after HTTP header
|
||||
http_response += std::to_string(strlen(post_fields)) + "\n\n" +
|
||||
std::string(post_fields);
|
||||
} else if (headers.substr(0, 4) == "POST") {
|
||||
http_response +=
|
||||
std::to_string(content.size()) + "\r\n\r\n" + std::string{content};
|
||||
|
||||
} else {
|
||||
// Close the connection and remove it from fd_set
|
||||
close(i);
|
||||
FD_CLR(i, &master_fd_set);
|
||||
continue;
|
||||
close(accepted_socket);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore any errors, the connection will be closed anyway
|
||||
write(i, http_response.c_str(), http_response.size());
|
||||
write(accepted_socket, http_response.c_str(), http_response.size());
|
||||
|
||||
// Close the connection and remove it from fd_set
|
||||
close(i);
|
||||
FD_CLR(i, &master_fd_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Close the socket
|
||||
close(accepted_socket);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -30,14 +30,12 @@ class CurlTestUtils {
|
|||
};
|
||||
|
||||
// Initialize and set up the curl handle
|
||||
void CurlTestSetUp();
|
||||
absl::Status CurlTestSetUp();
|
||||
// Clean up the curl handle
|
||||
void CurlTestTearDown();
|
||||
absl::Status CurlTestTearDown();
|
||||
|
||||
// Perform a request to the mock server
|
||||
// Optionally, store the response in a string
|
||||
void PerformRequest(std::string& response);
|
||||
void PerformRequest();
|
||||
// Perform a request to the mock server, return 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
|
||||
|
@ -58,7 +56,7 @@ class CurlTestUtils {
|
|||
static constexpr absl::string_view kSimpleResponse = "OK";
|
||||
|
||||
private:
|
||||
sapi::v::Struct<MemoryStruct> chunk_;
|
||||
sapi::v::LenVal chunk_{0};
|
||||
};
|
||||
|
||||
#endif // TESTS_H
|
||||
|
|
|
@ -14,28 +14,26 @@
|
|||
|
||||
#include "test_utils.h"
|
||||
|
||||
class Curl_Test : public CurlTestUtils, public ::testing::Test {
|
||||
class CurlTest : public CurlTestUtils, public ::testing::Test {
|
||||
protected:
|
||||
static void SetUpTestSuite() {
|
||||
void SetUp() override {
|
||||
// Start mock server, get port number and check for any error
|
||||
StartMockServer();
|
||||
ASSERT_TRUE(server_thread_.joinable());
|
||||
ASSERT_TRUE(CurlTestSetUp().ok());
|
||||
}
|
||||
|
||||
void SetUp() override { CurlTestSetUp(); }
|
||||
|
||||
static void TearDownTestSuite() {
|
||||
void TearDown() override {
|
||||
ASSERT_TRUE(CurlTestTearDown().ok());
|
||||
// Detach the server thread
|
||||
server_thread_.detach();
|
||||
}
|
||||
|
||||
void TearDown() override { CurlTestTearDown(); }
|
||||
};
|
||||
|
||||
TEST_F(Curl_Test, EffectiveUrl) {
|
||||
TEST_F(CurlTest, EffectiveUrl) {
|
||||
sapi::v::RemotePtr effective_url_ptr(nullptr);
|
||||
|
||||
PerformRequest();
|
||||
ASSERT_TRUE(PerformRequest().ok());
|
||||
|
||||
// Get effective URL
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
|
@ -53,10 +51,10 @@ TEST_F(Curl_Test, EffectiveUrl) {
|
|||
ASSERT_EQ(effective_url, kUrl);
|
||||
}
|
||||
|
||||
TEST_F(Curl_Test, EffectivePort) {
|
||||
TEST_F(CurlTest, EffectivePort) {
|
||||
sapi::v::Int effective_port;
|
||||
|
||||
PerformRequest();
|
||||
ASSERT_TRUE(PerformRequest().ok());
|
||||
|
||||
// Get effective port
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
|
@ -69,10 +67,10 @@ TEST_F(Curl_Test, EffectivePort) {
|
|||
ASSERT_EQ(effective_port.GetValue(), port_);
|
||||
}
|
||||
|
||||
TEST_F(Curl_Test, ResponseCode) {
|
||||
TEST_F(CurlTest, ResponseCode) {
|
||||
sapi::v::Int response_code;
|
||||
|
||||
PerformRequest();
|
||||
ASSERT_TRUE(PerformRequest().ok());
|
||||
|
||||
// Get response code
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
|
@ -85,10 +83,10 @@ TEST_F(Curl_Test, ResponseCode) {
|
|||
ASSERT_EQ(response_code.GetValue(), 200);
|
||||
}
|
||||
|
||||
TEST_F(Curl_Test, ContentType) {
|
||||
TEST_F(CurlTest, ContentType) {
|
||||
sapi::v::RemotePtr content_type_ptr(nullptr);
|
||||
|
||||
PerformRequest();
|
||||
ASSERT_TRUE(PerformRequest().ok());
|
||||
|
||||
// Get effective URL
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
|
@ -106,15 +104,14 @@ TEST_F(Curl_Test, ContentType) {
|
|||
ASSERT_EQ(content_type, "text/plain");
|
||||
}
|
||||
|
||||
TEST_F(Curl_Test, GETResponse) {
|
||||
std::string response;
|
||||
PerformRequest(response);
|
||||
TEST_F(CurlTest, GETResponse) {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(std::string response, PerformRequest());
|
||||
|
||||
// Compare response with expected response
|
||||
ASSERT_EQ(response, kSimpleResponse);
|
||||
}
|
||||
|
||||
TEST_F(Curl_Test, POSTResponse) {
|
||||
TEST_F(CurlTest, POSTResponse) {
|
||||
sapi::v::ConstCStr post_fields("postfields");
|
||||
|
||||
// Set request method to POST
|
||||
|
@ -137,8 +134,7 @@ TEST_F(Curl_Test, POSTResponse) {
|
|||
post_fields.PtrBefore()));
|
||||
ASSERT_EQ(setopt_post_fields, CURLE_OK);
|
||||
|
||||
std::string response;
|
||||
PerformRequest(response);
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(std::string response, PerformRequest());
|
||||
|
||||
// Compare response with expected response
|
||||
ASSERT_EQ(std::string(post_fields.GetData()), response);
|
||||
|
|
Loading…
Reference in New Issue
Block a user