Implement all curl methods

This commit is contained in:
Federico Stazi 2020-08-12 16:33:45 +00:00
parent ac1112ae4d
commit f47e1cc6ac
13 changed files with 875 additions and 41 deletions

View File

@ -19,6 +19,16 @@ project(curl_sandboxed)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
option(CURL_SAPI_ENABLE_EXAMPLES "" ON)
# Add the callbacks used by the examples
if (CURL_SAPI_ENABLE_EXAMPLES)
list(APPEND CURL_SAPI_CALLBACKS
"${CMAKE_CURRENT_SOURCE_DIR}/examples/callbacks.h"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/callbacks.cc"
)
endif()
# Add folder containing the non-sandboxed custom curl library
add_subdirectory(custom_curl)
@ -35,6 +45,9 @@ add_subdirectory(
# Generate SAPI header
add_sapi_library(curl_sapi
# List of all the methods in https://curl.haxx.se/libcurl/c/allfuncs.html
# Some are added or modified because the original ones are not supported
# by Sandboxed API (details can be found in custom_curl.h)
FUNCTIONS curl_easy_cleanup
curl_easy_duphandle
curl_easy_escape
@ -53,18 +66,66 @@ add_sapi_library(curl_sapi
curl_easy_strerror
curl_easy_unescape
curl_easy_upkeep
curl_free
curl_getdate_sapi
curl_global_cleanup
curl_global_init
curl_global_init_mem
curl_global_sslset
curl_mime_addpart
curl_mime_data
curl_mime_data_cb
curl_mime_encoder
curl_mime_filedata
curl_mime_filename
curl_mime_free
curl_mime_headers
curl_mime_init
curl_mime_name
curl_mime_subparts
curl_mime_type
curl_multi_add_handle
curl_multi_assign
curl_multi_cleanup
curl_multi_fdset_sapi
curl_multi_info_read
curl_multi_init
curl_multi_perform
curl_multi_remove_handle
curl_multi_setopt
curl_multi_setopt_ptr
curl_multi_setopt_long
curl_multi_setopt_curl_off_t
curl_multi_socket_action
curl_multi_strerror
curl_multi_timeout
curl_multi_poll_sapi
curl_multi_wait_sapi
curl_multi_wakeup
curl_share_init
curl_share_setopt
curl_share_setopt_ptr
curl_share_setopt_long
curl_share_strerror
curl_slist_append
curl_slist_free_all
curl_url
curl_url_cleanup
curl_url_dup
curl_url_get
curl_url_set
curl_version
curl_version_info
INPUTS "custom_curl/curl/include/curl/curlver.h"
"custom_curl/curl/include/curl/system.h"
"custom_curl/curl/include/curl/curl.h"
"custom_curl/curl/include/curl/easy.h"
"custom_curl/custom_curl.h"
INPUTS custom_curl/curl/include/curl/curl.h
custom_curl/custom_curl.h
LIBRARY custom_curl
LIBRARY custom_curl_and_callbacks
LIBRARY_NAME Curl
NAMESPACE ""
)
# Include generated SAPI header
@ -73,4 +134,6 @@ target_include_directories(curl_sapi INTERFACE
)
# Add examples
add_subdirectory(examples)
if (CURL_SAPI_ENABLE_EXAMPLES)
add_subdirectory(examples)
endif()

View File

@ -1,22 +1,56 @@
# Curl
# Curl Sandboxed
This library is a sandboxed version of the original [curl](https://curl.haxx.se/libcurl/c/) C library, implemented using sandboxed-api.
## Supported methods
The library currently supports curl's [*Easy interface*](https://curl.haxx.se/libcurl/c/libcurl-easy.html). According to curl's website:
> The easy interface is a synchronous, efficient, quickly used and... yes, easy interface for file transfers.
> Numerous applications have been built using this.
However, all of the methods using function pointers, are not yet supported.
## Examples
The `examples` directory contains the sandboxed versions of example source codes taken from [this](https://curl.haxx.se/libcurl/c/example.html) page on curl's website.
This library is a sandboxed version of curl's C API, [libcurl](https://curl.haxx.se/libcurl/c/), implemented using Sandboxed API.
## Implementation details
Variadic methods are currently not supported by sandboxed-api. Because of this, the sandboxed header `custom_curl.h` wraps the curl library and explicitly defines the variadic methods.
All of libcurl's methods are supported by the library. However, a few of these have different signatures defined in the sandboxed header `custom_curl.h`, which wraps and extends libcurl.
This is necessary because Sandboxed API sandboxes most of libcurl correctly, but encounters some issues when sandboxing a few methods. The simplest solution is wrapping these methods into wrapper methods that accomplish the same tasks but can also be sandboxed.
The next sections describe the issues encountered and contain some information on the signatures of the wrapper methods solving these issues.
#### Variadic methods
Variadic methods are currently not supported by Sandboxed API. To solve this, these methods are defined with an additional explicit parameter in `custom_curl.h`.
The methods are:
- `curl_easy_setopt`. Use `curl_easy_setopt_ptr`, `curl_easy_setopt_long` or `curl_easy_setopt_curl_off_t` instead.
- `curl_easy_getinfo`. Use `curl_easy_getinfo_ptr` instead.
- `curl_multi_setopt`. Use `curl_multi_setopt_ptr`, `curl_multi_setopt_long` or `curl_multi_setopt_curl_off_t` instead.
- `curl_share_setopt`. Use `curl_share_setopt_ptr` or `curl_share_setopt_long` instead
#### Methods with incomplete array arguments
Incomplete array arguments are currently not supported by Sandboxed API. To solve this, methods taking an incomplete array argument have a wrapper in `custom_curl.h`, and take a pointer as the argument.
The methods are:
- `curl_multi_poll`. Use `curl_multi_poll_sapi` instead.
- `curl_multi_wait`. Use `curl_multi_wait_sapi` instead.
#### Methods with conflicts on the generated header
Some methods create conflicts on the generated header because of redefined `#define` directives from files included by the header. To solve this, the conflicting types and methods are redefined in `custom_curl.h`.
The types are:
- `time_t`. Use `time_t_sapi` instead.
- `fd_set`. Use `fd_set_sapi` instead.
The methods are:
- `curl_getdate`. Use `curl_getdate_sapi` instead.
- `curl_multi_fdset`. Use `curl_multi_fdset_sapi` instead.
#### Function pointers
The functions whose pointers will be passed to the library's methods (*callbacks*) can't be implemented in the files making use of the library, but must be in other files. These files must be compiled together with the library, and this is done by adding their absolute path to the cmake variable `CURL_SAPI_CALLBACKS`.
The pointers can then be obtained using an `RPCChannel` object, as shown in `example2.cc`.
## Examples
The `examples` directory contains the sandboxed versions of example source codes taken from [this page](https://curl.haxx.se/libcurl/c/example.html) on curl's website.
To build these examples when building the library, the cmake variable `CURL_SAPI_ENABLE_EXAMPLES` must be set to `ON`.
The `callbacks.h` and `callbacks.cc` files implement all the callbacks used by the examples.
For example, instead of using `curl_easy_setopt`, one of these methods can be used: `curl_easy_setopt_ptr`, `curl_easy_setopt_long` or `curl_easy_setopt_curl_off_t`.

View File

@ -12,21 +12,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# Wrapper library including curl,
# adds the explicit versions of the variadic methods and the callbacks
# The CURL_SAPI_CALLBACKS variable should contain the absolute paths of
# all the files implementing the callbacks
add_library(custom_curl_and_callbacks OBJECT
custom_curl.h
custom_curl.cc
"${CURL_SAPI_CALLBACKS}"
)
set_target_properties(custom_curl_and_callbacks
PROPERTIES LINKER_LANGUAGE C
)
# Flags needed to build curl statically
set(CURL_HIDDEN_SYMBOLS OFF)
set(BUILD_SHARED_LIBS OFF)
# Link the wrapper to the original curl library
add_subdirectory(curl)
# Wrapper library including curl,
# adds the explicit versions of the variadic methods
add_library(custom_curl STATIC
custom_curl.h
custom_curl.cc
)
set_target_properties(custom_curl
PROPERTIES LINKER_LANGUAGE C
)
target_link_libraries(custom_curl
target_link_libraries(custom_curl_and_callbacks
CURL::libcurl
)

View File

@ -36,3 +36,59 @@ CURLcode curl_easy_getinfo_ptr(CURL* handle, CURLINFO option,
void* parameter) {
return curl_easy_getinfo(handle, option, parameter);
}
time_t_sapi curl_getdate_sapi(char *datestring, time_t_sapi *now ) {
return curl_getdate(datestring, now);
}
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) {
return curl_multi_fdset(multi_handle, read_fd_set, write_fd_set, exc_fd_set,
max_fd);
}
CURLMcode curl_mutti_setopt_ptr(CURLM* handle, CURLMoption option,
void* parameter) {
return curl_multi_setopt(handle, option, parameter);
}
CURLMcode curl_multi_setopt_long(CURLM* handle, CURLMoption option,
long parameter) {
return curl_multi_setopt(handle, option, parameter);
}
CURLMcode curl_multi_setopt_curl_off_t(CURLM* handle, CURLMoption option,
curl_off_t parameter) {
return curl_multi_setopt(handle, option, parameter);
}
CURLMcode curl_multi_poll_sapi(CURLM *multi_handle,
struct curl_waitfd* extra_fds,
unsigned int extra_nfds,
int timeout_ms,
int *numfds) {
return curl_multi_poll(multi_handle, extra_fds, extra_nfds, timeout_ms,
numfds);
}
CURLMcode curl_multi_wait_sapi(CURLM *multi_handle,
struct curl_waitfd* extra_fds,
unsigned int extra_nfds,
int timeout_ms,
int *numfds) {
return curl_multi_wait(multi_handle, extra_fds, extra_nfds, timeout_ms,
numfds);
}
CURLSHcode curl_share_setopt_ptr(CURLSH* handle, CURLSHoption option,
void* parameter) {
return curl_share_setopt(handle, option, parameter);
}
CURLSHcode curl_share_setopt_long(CURLSH* handle, CURLSHoption option,
long parameter) {
return curl_share_setopt(handle, option, parameter);
}

View File

@ -12,23 +12,76 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Wrapper for curl library used to implement variadic methods explicitly
// Wrapper for curl library
#ifndef CUSTOM_CURL_H
#define CUSTOM_CURL_H
#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);
// The wrapper method is needed to make the variadic argument explicit
extern "C" CURLcode curl_easy_setopt_long(CURL* handle, CURLoption option,
long 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,
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);
// 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 );
// 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,
fd_set_sapi *write_fd_set,
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,
void* parameter);
// The wrapper method is needed to make the variadic argument explicit
extern "C" 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,
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,
struct curl_waitfd* extra_fds,
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,
struct curl_waitfd* extra_fds,
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,
void* parameter);
// The wrapper method is needed to make the variadic argument explicit
extern "C" CURLSHcode curl_share_setopt_long(CURLSH* handle, CURLSHoption option,
long parameter);
#endif // CUSTOM_CURL_H

View File

@ -23,3 +23,39 @@ target_link_libraries(example1 PRIVATE
curl_sapi
sapi::sapi
)
# Example 2: getinmemory.c
add_executable(example2
example2.cc
)
target_link_libraries(example2 PRIVATE
curl_sapi
sapi::sapi
)
# Example 3: simplessl.c
add_executable(example3
example3.cc
)
target_link_libraries(example3 PRIVATE
curl_sapi
sapi::sapi
)
# Example 4: multi-poll.c
add_executable(example4
example4.cc
)
target_link_libraries(example4 PRIVATE
curl_sapi
sapi::sapi
)
# Example 5: multithread.c
add_executable(example5
example5.cc
)
target_link_libraries(example5 PRIVATE
curl_sapi
sapi::sapi
)

View File

@ -0,0 +1,41 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "callbacks.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
// 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;
char* ptr = (char*)realloc(mem->memory, mem->size + realsize + 1);
if(ptr == NULL) { // 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;
return realsize;
}

View File

@ -0,0 +1,28 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CALLBACKS_H
#define CALLBACKS_H
#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);
#endif // CALLBACKS_H

View File

@ -13,6 +13,7 @@
// limitations under the License.
// Sandboxed version of simple.c
// Simple HTTP GET request
#include <cstdlib>
#include <iostream>
@ -35,31 +36,44 @@ class CurlApiSandboxEx1 : public CurlSandbox {
int main(int argc, char* argv[]) {
absl::Status status;
sapi::StatusOr<CURL*> status_or_curl;
sapi::StatusOr<int> status_or_int;
// Initialize sandbox2 and sapi
CurlApiSandboxEx1 sandbox;
absl::Status status = sandbox.Init();
status = sandbox.Init();
assert(status.ok());
CurlApi api(&sandbox);
sapi::StatusOr<CURL*> status_or_curl = api.curl_easy_init();
// Initialize the curl session
status_or_curl = api.curl_easy_init();
assert(status_or_curl.ok());
sapi::v::RemotePtr curl(status_or_curl.value());
assert(curl.GetValue()); // Checking curl != nullptr
// Specify URL to get
sapi::v::ConstCStr url("http://example.com");
sapi::StatusOr<int> status_or_int =
api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Set the library to follow a redirection
status_or_int = api.curl_easy_setopt_long(&curl, CURLOPT_FOLLOWLOCATION, 1l);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
status_or_int = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 0l);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Perform the request
status_or_int = api.curl_easy_perform(&curl);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Cleanup curl
status = api.curl_easy_cleanup(&curl);
assert(status.ok());

View File

@ -0,0 +1,111 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Sandboxed version of getinmemory.c
// HTTP GET request using callbacks
#include <cstdlib>
#include <iostream>
#include "curl_sapi.sapi.h"
#include "sandboxed_api/util/flag.h"
struct MemoryStruct {
char* memory;
size_t size;
};
class CurlApiSandboxEx2 : public CurlSandbox {
private:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
// Return a new policy
return sandbox2::PolicyBuilder()
.DangerDefaultAllowAll()
.AllowUnrestrictedNetworking()
.AddDirectory("/lib")
.BuildOrDie();
}
};
int main() {
absl::Status status;
sapi::StatusOr<CURL*> status_or_curl;
sapi::StatusOr<int> status_or_int;
// Initialize sandbox2 and sapi
CurlApiSandboxEx2 sandbox;
status = sandbox.Init();
assert(status.ok());
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);
assert(status.ok());
sapi::v::RemotePtr remote_function_ptr((void*)_function_ptr);
// Initialize the curl session
status_or_curl = api.curl_easy_init();
assert(status_or_curl.ok());
sapi::v::RemotePtr curl(status_or_curl.value());
assert(curl.GetValue()); // Checking curl != nullptr
// Specify URL to get
sapi::v::ConstCStr url("http://example.com");
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Set WriteMemoryCallback as the write function
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEFUNCTION,
&remote_function_ptr);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Pass 'chunk' struct to the callback function
sapi::v::Struct<MemoryStruct> chunk;
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEDATA,
chunk.PtrBoth());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Set a user agent
sapi::v::ConstCStr user_agent("libcurl-agent/1.0");
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_USERAGENT,
user_agent.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Perform the request
status_or_int = api.curl_easy_perform(&curl);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Retrieve memory size
sapi::v::Int size;
size.SetRemote(&((MemoryStruct*)chunk.GetRemote())->size);
status = sandbox.TransferFromSandboxee(&size);
assert(status.ok());
std::cout << "memory size: " << size.GetValue() << " bytes" << std::endl;
// Cleanup curl
status = api.curl_easy_cleanup(&curl);
assert(status.ok());
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,147 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Sandboxed version of simplessl.c
// HTTPS GET request
#include <cstdlib>
#include <iostream>
#include "curl_sapi.sapi.h"
#include "sandboxed_api/util/flag.h"
class CurlApiSandboxEx3 : public CurlSandbox {
public:
CurlApiSandboxEx3(std::string ssl_certificate, std::string ssl_key,
std::string ca_certificates)
: ssl_certificate(ssl_certificate),
ssl_key(ssl_key),
ca_certificates(ca_certificates) {}
private:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
// Return a new policy
return sandbox2::PolicyBuilder()
.DangerDefaultAllowAll()
.AllowUnrestrictedNetworking()
.AddDirectory("/lib")
.AddFile(ssl_certificate)
.AddFile(ssl_key)
.AddFile(ca_certificates)
.BuildOrDie();
}
std::string ssl_certificate;
std::string ssl_key;
std::string ca_certificates;
};
int main(int argc, char* argv[]) {
absl::Status status;
sapi::StatusOr<int> status_or_int;
sapi::StatusOr<CURL*> status_or_curl;
// Get input parameters (should be absolute paths)
assert(argc == 5);
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];
// Initialize sandbox2 and sapi
CurlApiSandboxEx3 sandbox(ssl_certificate, ssl_key, ca_certificates);
status = sandbox.Init();
assert(status.ok());
CurlApi api(&sandbox);
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
status_or_int = api.curl_global_init(3l);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Initialize curl easy handle
status_or_curl = api.curl_easy_init();
assert(status_or_curl.ok());
sapi::v::RemotePtr curl(status_or_curl.value());
assert(curl.GetValue()); // Checking curl != nullptr
// 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());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// 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,
ssl_cert_type.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// 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,
sapi_ssl_certificate.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Set the private key for client authentication
sapi::v::ConstCStr sapi_ssl_key(ssl_key.c_str());
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLKEY,
sapi_ssl_key.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// 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,
sapi_ssl_key_password.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// 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,
sapi_ca_certificates.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Verify the authenticity of the server
status_or_int = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 1L);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Perform the request
status_or_int = api.curl_easy_perform(&curl);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Cleanup curl easy handle
status = api.curl_easy_cleanup(&curl);
assert(status.ok());
// Cleanup curl
status = api.curl_global_cleanup();
assert(status.ok());
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,122 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Sandboxed version of multi-poll.c
// HTTP GET request with polling
#include <cstdlib>
#include <iostream>
#include "curl_sapi.sapi.h"
#include "sandboxed_api/util/flag.h"
class CurlApiSandboxEx4 : public CurlSandbox {
private:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
// Return a new policy
return sandbox2::PolicyBuilder()
.DangerDefaultAllowAll()
.AllowUnrestrictedNetworking()
.AddDirectory("/lib")
.BuildOrDie();
}
};
int main() {
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
CurlApiSandboxEx4 sandbox;
status = sandbox.Init();
assert(status.ok());
CurlApi api(&sandbox);
// Number of running handles
sapi::v::Int still_running(1);
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
status_or_int = api.curl_global_init(3l);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Initialize http_handle
status_or_curl = api.curl_easy_init();
assert(status_or_curl.ok());
sapi::v::RemotePtr http_handle(status_or_curl.value());
assert(http_handle.GetValue()); // Checking http_handle != nullptr
// Specify URL to get
sapi::v::ConstCStr url("http://example.com");
status_or_int =
api.curl_easy_setopt_ptr(&http_handle, CURLOPT_URL, url.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Initialize multi_handle
status_or_curlm = api.curl_multi_init();
assert(status_or_curlm.ok());
sapi::v::RemotePtr multi_handle(status_or_curlm.value());
assert(multi_handle.GetValue()); // Checking multi_handle != nullptr
// Add http_handle to the multi stack
status_or_int = api.curl_multi_add_handle(&multi_handle, &http_handle);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
while (still_running.GetValue()) {
sapi::v::Int numfds(0);
// Perform the request
status_or_int = api.curl_multi_perform(&multi_handle,
still_running.PtrBoth());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
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());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLM_OK);
}
}
// Remove http_handle from the multi stack
status_or_int = api.curl_multi_remove_handle(&multi_handle, &http_handle);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Cleanup http_handle
status = api.curl_easy_cleanup(&http_handle);
assert(status.ok());
// Cleanup multi_handle
status_or_int = api.curl_multi_cleanup(&multi_handle);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Cleanup curl
status = api.curl_global_cleanup();
assert(status.ok());
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,125 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Sandboxed version of multithread.c
// Multithreaded HTTP GET requests
#include <pthread.h>
#include <cstdlib>
#include <iostream>
#include "curl_sapi.sapi.h"
#include "sandboxed_api/util/flag.h"
class CurlApiSandboxEx5 : public CurlSandbox {
private:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
// Return a new policy
return sandbox2::PolicyBuilder()
.DangerDefaultAllowAll()
.AllowUnrestrictedNetworking()
.AddDirectory("/lib")
.BuildOrDie();
}
};
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;
// Initialize the curl session
status_or_curl = api.curl_easy_init();
assert(status_or_curl.ok());
sapi::v::RemotePtr curl(status_or_curl.value());
assert(curl.GetValue()); // Checking curl != nullptr
// Specify URL to get
sapi::v::ConstCStr sapi_url(((thread_args*)args)->url);
status_or_int = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL,
sapi_url.PtrBefore());
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Perform the request
status_or_int = api.curl_easy_perform(&curl);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// Cleanup curl
status = api.curl_easy_cleanup(&curl);
assert(status.ok());
return NULL;
}
const char * const urls[kThreadsnumber] = {
"http://example.com",
"http://example.edu",
"http://example.net",
"http://example.org"
};
int main(int argc, char **argv) {
pthread_t tid[kThreadsnumber];
absl::Status status;
sapi::StatusOr<int> status_or_int;
// Initialize sandbox2 and sapi
CurlApiSandboxEx5 sandbox;
status = sandbox.Init();
assert(status.ok());
CurlApi api(&sandbox);
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
status_or_int = api.curl_global_init(3l);
assert(status_or_int.ok());
assert(status_or_int.value() == CURLE_OK);
// 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);
assert(!error);
std::cout << "Thread "<< i << " gets " << urls[i] << std::endl;
}
// Join the threads
for(int i = 0; i< kThreadsnumber; i++) {
pthread_join(tid[i], NULL);
std::cout << "Thread " << i << " terminated" << std::endl;
}
// Cleanup curl
status = api.curl_global_cleanup();
assert(status.ok());
return EXIT_SUCCESS;
}