diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 0000000..86eb663 --- /dev/null +++ b/.bazelignore @@ -0,0 +1,4 @@ +# Using CMake or own WORKSPACE +oss-internship-2020 +# Uses its own WORKSPACE +sandboxed_api/examples/hello_sapi diff --git a/.gitmodules b/.gitmodules index aef07fd..d79419f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,18 @@ +[submodule "oss-internship-2020/sapi_lodepng/lodepng"] + path = oss-internship-2020/lodepng/lodepng + url = https://github.com/lvandeve/lodepng +[submodule "oss-internship-2020/jsonnet/jsonnet"] + path = oss-internship-2020/jsonnet/jsonnet + url = https://github.com/google/jsonnet.git [submodule "oss-internship-2020/openjpeg/openjpeg"] path = oss-internship-2020/openjpeg/openjpeg url = https://github.com/uclouvain/openjpeg.git [submodule "oss-internship-2020/pffft/master"] path = oss-internship-2020/pffft/master url = https://bitbucket.org/jpommier/pffft/src/master/ -[submodule "oss-internship-2020/curl/curl_wrapper/curl"] - path = oss-internship-2020/curl/curl_wrapper/curl - url = https://github.com/curl/curl [submodule "oss-internship-2020/gdal/gdal"] path = oss-internship-2020/gdal/gdal url = https://github.com/OSGeo/gdal/tree/master/gdal +[submodule "oss-internship-2020/curl/curl_wrapper/curl"] + path = oss-internship-2020/curl/curl_wrapper/curl + url = git@github.com:curl/curl.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 20b732e..6d141be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,9 @@ include(SapiBuildDefs) # Allow the header generator to auto-configure include paths set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# Allow the header generator to auto-configure include paths +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + if (SAPI_FORCE_COLOR_OUTPUT) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # GCC add_compile_options(-fdiagnostics-color=always) diff --git a/cmake/SapiBuildDefs.cmake b/cmake/SapiBuildDefs.cmake index 5b9ce28..cd0e43d 100644 --- a/cmake/SapiBuildDefs.cmake +++ b/cmake/SapiBuildDefs.cmake @@ -132,44 +132,44 @@ function(add_sapi_library) set(_sapi_embed_dir "${CMAKE_CURRENT_BINARY_DIR}") set(_sapi_embed_name "${_sapi_NAME}") endif() + + set(_sapi_isystem "${_sapi_NAME}.isystem}") + list(APPEND _sapi_generator_args + "--sapi_name=${_sapi_LIBRARY_NAME}" + "--sapi_out=${_sapi_gen_header}" + "--sapi_embed_dir=${_sapi_embed_dir}" + "--sapi_embed_name=${_sapi_embed_name}" + "--sapi_functions=${_sapi_funcs}" + "--sapi_ns=${_sapi_NAMESPACE}" + "--sapi_isystem=${_sapi_isystem}" + ) + list(JOIN _sapi_full_inputs "," _sapi_full_inputs) if(SAPI_ENABLE_GENERATOR) - add_custom_command( - OUTPUT "${_sapi_gen_header}" - COMMAND sapi_generator_tool - "--sapi_name=${_sapi_LIBRARY_NAME}" - "--sapi_out=${_sapi_gen_header}" - "--sapi_embed_dir=${_sapi_embed_dir}" - "--sapi_embed_name=${_sapi_embed_name}" - "--sapi_functions=${_sapi_funcs}" - "--sapi_ns=${_sapi_NAMESPACE}" - ${_sapi_full_inputs} - COMMENT "Generating interface" - DEPENDS ${_sapi_INPUTS} - VERBATIM + list(APPEND _sapi_generator_command + sapi_generator_tool + -p "${CMAKE_CURRENT_BINARY_DIR}" + ${_sapi_generator_args} + ${_sapi_full_inputs} ) else() - set(_sapi_isystem "${_sapi_NAME}.isystem") - list(JOIN _sapi_full_inputs "," _sapi_full_inputs) - add_custom_command( - OUTPUT "${_sapi_gen_header}" "${_sapi_isystem}" - COMMAND sh -c - "${CMAKE_CXX_COMPILER} -E -x c++ -v /dev/null 2>&1 | \ - awk '/> search starts here:/{f=1;next}/^End of search/{f=0}f{print $1}' \ - > \"${_sapi_isystem}\"" - COMMAND "${SAPI_PYTHON3_EXECUTABLE}" -B - "${SAPI_SOURCE_DIR}/sandboxed_api/tools/generator2/sapi_generator.py" - "--sapi_name=${_sapi_LIBRARY_NAME}" - "--sapi_out=${_sapi_gen_header}" - "--sapi_embed_dir=${_sapi_embed_dir}" - "--sapi_embed_name=${_sapi_embed_name}" - "--sapi_functions=${_sapi_funcs}" - "--sapi_ns=${_sapi_NAMESPACE}" - "--sapi_isystem=${_sapi_isystem}" - "--sapi_in=${_sapi_full_inputs}" - COMMENT "Generating interface" - VERBATIM + list(APPEND _sapi_generator_command + "${SAPI_PYTHON3_EXECUTABLE}" -B + "${SAPI_SOURCE_DIR}/sandboxed_api/tools/generator2/sapi_generator.py" + ${_sapi_generator_args} + "--sapi_in=${_sapi_full_inputs}" ) endif() + add_custom_command( + OUTPUT "${_sapi_gen_header}" "${_sapi_isystem}" + COMMAND sh -c + "${CMAKE_CXX_COMPILER} -E -x c++ -v /dev/null 2>&1 | \ + awk '/> search starts here:/{f=1;next}/^End of search/{f=0}f{print $1}' \ + > \"${_sapi_isystem}\"" + COMMAND ${_sapi_generator_command} + COMMENT "Generating interface" + DEPENDS ${_sapi_INPUTS} + VERBATIM + ) # Library with the interface if(NOT _sapi_SOURCES) diff --git a/oss-internship-2020/curl/CMakeLists.txt b/oss-internship-2020/curl/CMakeLists.txt index 8d2be38..074b6c6 100644 --- a/oss-internship-2020/curl/CMakeLists.txt +++ b/oss-internship-2020/curl/CMakeLists.txt @@ -12,15 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.12) project(libcurl_sandbox) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) -option(CURL_SAPI_ENABLE_EXAMPLES "" ON) -option(CURL_SAPI_ENABLE_TESTS "" ON) +option(SAPI_CURL_ENABLE_EXAMPLES "" ON) +option(SAPI_CURL_ENABLE_TESTS "" ON) # Add callbacks used by examples and tests if (CURL_SAPI_ENABLE_EXAMPLES OR CURL_SAPI_ENABLE_TESTS) @@ -35,8 +35,8 @@ add_subdirectory(curl_wrapper) # Setup Sandboxed API set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree") -set(SAPI_ENABLE_EXAMPLES ${CURL_SAPI_ENABLE_EXAMPLES} CACHE BOOL "" FORCE) -set(SAPI_ENABLE_TESTS ${CURL_SAPI_ENABLE_TESTS} CACHE BOOL "" FORCE) +set(SAPI_ENABLE_EXAMPLES ${SAPI_CURL_ENABLE_EXAMPLES} CACHE BOOL "" FORCE) +set(SAPI_ENABLE_TESTS ${SAPI_CURL_ENABLE_TESTS} CACHE BOOL "" FORCE) add_subdirectory( "${SAPI_ROOT}" "${CMAKE_BINARY_DIR}/sandboxed-api-build" @@ -125,7 +125,7 @@ add_sapi_library(curl_sapi LIBRARY_NAME Curl - NAMESPACE "" + NAMESPACE curl ) # Include generated SAPI header @@ -134,11 +134,11 @@ target_include_directories(curl_sapi INTERFACE ) # Add examples -if (CURL_SAPI_ENABLE_EXAMPLES) +if (SAPI_CURL_ENABLE_EXAMPLES) add_subdirectory(examples) endif() # Add tests -if (CURL_SAPI_ENABLE_TESTS) +if (SAPI_CURL_ENABLE_TESTS) add_subdirectory(tests) endif() diff --git a/oss-internship-2020/curl/README.md b/oss-internship-2020/curl/README.md index 3000838..dcbdc7c 100644 --- a/oss-internship-2020/curl/README.md +++ b/oss-internship-2020/curl/README.md @@ -38,12 +38,15 @@ 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 +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 @@ -51,8 +54,10 @@ 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. +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 @@ -60,11 +65,15 @@ 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 types are: -The methods are: - `curl_getdate`. Use `curl_getdate_sapi` instead. - -`curl_multi_fdset`. Use `curl_multi_fdset_sapi` instead. +- `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 diff --git a/oss-internship-2020/curl/callbacks/callbacks.h b/oss-internship-2020/curl/callbacks/callbacks.h index 306e2eb..b6324b3 100644 --- a/oss-internship-2020/curl/callbacks/callbacks.h +++ b/oss-internship-2020/curl/callbacks/callbacks.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef TESTS_CALLBACKS_H -#define TESTS_CALLBACKS_H +#ifndef CALLBACKS_H_ +#define CALLBACKS_H_ #include @@ -21,4 +21,4 @@ extern "C" size_t WriteToMemory(char* contents, size_t size, size_t num_bytes, void* userp); -#endif // TESTS_CALLBACKS_H +#endif // CALLBACKS_H_ diff --git a/oss-internship-2020/curl/curl_wrapper/curl_wrapper.h b/oss-internship-2020/curl/curl_wrapper/curl_wrapper.h index 4ef612b..4969abb 100644 --- a/oss-internship-2020/curl/curl_wrapper/curl_wrapper.h +++ b/oss-internship-2020/curl/curl_wrapper/curl_wrapper.h @@ -14,8 +14,8 @@ // Wrapper for curl library -#ifndef CURL_WRAPPER_H -#define CURL_WRAPPER_H +#ifndef CURL_WRAPPER_H_ +#define CURL_WRAPPER_H_ #include @@ -77,6 +77,7 @@ CURLSHcode curl_share_setopt_ptr(CURLSH* handle, CURLSHoption option, // The wrapper method is needed to make the variadic argument explicit CURLSHcode curl_share_setopt_long(CURLSH* handle, CURLSHoption option, long parameter); -} -#endif // CURL_WRAPPER_H +} // extern "C" + +#endif // CURL_WRAPPER_H_ diff --git a/oss-internship-2020/curl/examples/example1.cc b/oss-internship-2020/curl/examples/example1.cc index e5ee5fe..588ba2b 100644 --- a/oss-internship-2020/curl/examples/example1.cc +++ b/oss-internship-2020/curl/examples/example1.cc @@ -19,59 +19,67 @@ #include "../sandbox.h" // NOLINT(build/include) +namespace { + +absl::Status Example1() { + // Initialize sandbox2 and sapi + curl::CurlSapiSandbox sandbox; + SAPI_RETURN_IF_ERROR(sandbox.Init()); + curl::CurlApi api(&sandbox); + + // Initialize the curl session + curl::CURL* curl_handle; + SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init()); + sapi::v::RemotePtr curl(curl_handle); + if (!curl_handle) { + return absl::UnavailableError("curl_easy_init failed: curl is NULL"); + } + + int curl_code; + + // Specify URL to get + sapi::v::ConstCStr url("http://example.com"); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, + url.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); + } + + // Set the library to follow a redirection + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long( + &curl, curl::CURLOPT_FOLLOWLOCATION, 1l)); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code); + } + + // Disable authentication of peer certificate + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long( + &curl, curl::CURLOPT_SSL_VERIFYPEER, 0l)); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code); + } + + // Perform the request + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl)); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_perform failed: " + curl_code); + } + + // Cleanup curl + SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl)); + + return absl::OkStatus(); +} + +} // namespace + int main(int argc, char* argv[]) { gflags::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); - absl::Status status; - - // Initialize sandbox2 and sapi - CurlSapiSandbox sandbox; - status = sandbox.Init(); - if (!status.ok()) { - LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status; - } - CurlApi api(&sandbox); - - // Initialize the curl session - absl::StatusOr curl_handle = api.curl_easy_init(); - if (!curl_handle.ok()) { - LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status(); - } - sapi::v::RemotePtr curl(curl_handle.value()); - if (!curl.GetValue()) LOG(FATAL) << "curl_easy_init failed: curl is NULL"; - - absl::StatusOr curl_code; - - // Specify URL to get - sapi::v::ConstCStr url("http://example.com"); - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); - } - - // Set the library to follow a redirection - curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_FOLLOWLOCATION, 1l); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status(); - } - - // Disable authentication of peer certificate - curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 0l); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status(); - } - - // Perform the request - curl_code = api.curl_easy_perform(&curl); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status(); - } - - // Cleanup curl - status = api.curl_easy_cleanup(&curl); - if (!status.ok()) { - LOG(FATAL) << "curl_easy_cleanup failed: " << status; + if (absl::Status status = Example1(); !status.ok()) { + LOG(ERROR) << "Example1 failed: " << status.ToString(); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/oss-internship-2020/curl/examples/example2.cc b/oss-internship-2020/curl/examples/example2.cc index c7abe0c..1117a03 100644 --- a/oss-internship-2020/curl/examples/example2.cc +++ b/oss-internship-2020/curl/examples/example2.cc @@ -20,87 +20,89 @@ #include "../sandbox.h" // NOLINT(build/include) -int main(int argc, char* argv[]) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - google::InitGoogleLogging(argv[0]); - - absl::Status status; +namespace { +absl::Status Example2() { // Initialize sandbox2 and sapi - CurlSapiSandbox sandbox; - status = sandbox.Init(); - if (!status.ok()) { - LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status; - } - CurlApi api(&sandbox); + curl::CurlSapiSandbox sandbox; + SAPI_RETURN_IF_ERROR(sandbox.Init()); + curl::CurlApi api(&sandbox); // Generate pointer to WriteMemoryCallback function void* function_ptr; - status = sandbox.rpc_channel()->Symbol("WriteToMemory", &function_ptr); - if (!status.ok()) { - LOG(FATAL) << "sapi::Sandbox::rpc_channel().Symbol failed: " << status; - } - sapi::v::RemotePtr remote_function_ptr(function_ptr); + SAPI_RETURN_IF_ERROR( + sandbox.rpc_channel()->Symbol("WriteToMemory", &function_ptr)); + sapi::v::RemotePtr write_to_memory(function_ptr); // Initialize the curl session - absl::StatusOr curl_handle = api.curl_easy_init(); - if (!curl_handle.ok()) { - LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status(); - } - sapi::v::RemotePtr curl(curl_handle.value()); - if (!curl.GetValue()) { - LOG(FATAL) << "curl_easy_init failed: curl is NULL"; + curl::CURL* curl_handle; + SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init()); + sapi::v::RemotePtr curl(curl_handle); + if (!curl_handle) { + return absl::UnavailableError("curl_easy_init failed: curl is NULL"); } - absl::StatusOr curl_code; + int curl_code; // Specify URL to get sapi::v::ConstCStr url("http://example.com"); - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, + url.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Set WriteMemoryCallback as the write function - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEFUNCTION, - &remote_function_ptr); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_WRITEFUNCTION, + &write_to_memory)); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Pass 'chunk' struct to the callback function sapi::v::LenVal chunk(0); - curl_code = - api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEDATA, chunk.PtrBoth()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_WRITEDATA, + chunk.PtrBoth())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Set a user agent sapi::v::ConstCStr user_agent("libcurl-agent/1.0"); - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_USERAGENT, - user_agent.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_USERAGENT, + user_agent.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Perform the request - curl_code = api.curl_easy_perform(&curl); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl)); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_perform failed: " + curl_code); } // Retrieve memory size - status = sandbox.TransferFromSandboxee(&chunk); - if (!status.ok()) { - LOG(FATAL) << "sandbox.TransferFromSandboxee failed: " << status; - } + SAPI_RETURN_IF_ERROR(sandbox.TransferFromSandboxee(&chunk)); std::cout << "memory size: " << chunk.GetDataSize() << " bytes" << std::endl; // Cleanup curl - status = api.curl_easy_cleanup(&curl); - if (!status.ok()) { - LOG(FATAL) << "curl_easy_cleanup failed: " << status; + SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl)); + + return absl::OkStatus(); +} + +} // namespace + +int main(int argc, char* argv[]) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + google::InitGoogleLogging(argv[0]); + + if (absl::Status status = Example2(); !status.ok()) { + LOG(ERROR) << "Example2 failed: " << status.ToString(); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/oss-internship-2020/curl/examples/example3.cc b/oss-internship-2020/curl/examples/example3.cc index 1a73c93..98c5095 100644 --- a/oss-internship-2020/curl/examples/example3.cc +++ b/oss-internship-2020/curl/examples/example3.cc @@ -19,7 +19,9 @@ #include "../sandbox.h" // NOLINT(build/include) -class CurlSapiSandboxEx3 : public CurlSapiSandbox { +namespace { + +class CurlSapiSandboxEx3 : public curl::CurlSapiSandbox { public: CurlSapiSandboxEx3(std::string ssl_certificate, std::string ssl_key, std::string ca_certificates) @@ -42,7 +44,7 @@ class CurlSapiSandboxEx3 : public CurlSapiSandbox { .AddFile(ssl_key) .AddFile(ca_certificates); // Provide the new PolicyBuilder to ModifyPolicy in CurlSandbox - return CurlSapiSandbox::ModifyPolicy(policy_builder.get()); + return curl::CurlSapiSandbox::ModifyPolicy(policy_builder.get()); } std::string ssl_certificate; @@ -50,116 +52,121 @@ class CurlSapiSandboxEx3 : public CurlSapiSandbox { std::string ca_certificates; }; -int main(int argc, char* argv[]) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - google::InitGoogleLogging(argv[0]); - - absl::Status status; - - // Get input parameters (should be absolute paths) - if (argc != 5) { - LOG(FATAL) << "wrong number of arguments (4 expected)"; - } - std::string ssl_certificate = argv[1]; - std::string ssl_key = argv[2]; - std::string ssl_key_password = argv[3]; - std::string ca_certificates = argv[4]; - +absl::Status Example3(std::string ssl_certificate, std::string ssl_key, + std::string ssl_key_password, + std::string ca_certificates) { // Initialize sandbox2 and sapi CurlSapiSandboxEx3 sandbox(ssl_certificate, ssl_key, ca_certificates); - status = sandbox.Init(); - if (!status.ok()) { - LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status; - } - CurlApi api(&sandbox); + SAPI_RETURN_IF_ERROR(sandbox.Init()); + curl::CurlApi api(&sandbox); - absl::StatusOr curl_code; + int curl_code; // Initialize curl (CURL_GLOBAL_DEFAULT = 3) - curl_code = api.curl_global_init(3l); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_global_init failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l)); + if (curl_code != 0) { + return absl::UnavailableError("curl_global_init failed: " + curl_code); } // Initialize curl easy handle - absl::StatusOr curl_handle = api.curl_easy_init(); - if (!curl_handle.ok()) { - LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status(); - } - sapi::v::RemotePtr curl(curl_handle.value()); - if (!curl.GetValue()) { - LOG(FATAL) << "curl_easy_init failed: curl is NULL"; + curl::CURL* curl_handle; + SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init()); + sapi::v::RemotePtr curl(curl_handle); + if (!curl_handle) { + return absl::UnavailableError("curl_easy_init failed: curl is NULL"); } // Specify URL to get (using HTTPS) sapi::v::ConstCStr url("https://example.com"); - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, + url.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Set the SSL certificate type to "PEM" sapi::v::ConstCStr ssl_cert_type("PEM"); - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERTTYPE, - ssl_cert_type.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERTTYPE, + ssl_cert_type.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Set the certificate for client authentication sapi::v::ConstCStr sapi_ssl_certificate(ssl_certificate.c_str()); - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERT, - sapi_ssl_certificate.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERT, + sapi_ssl_certificate.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Set the private key for client authentication sapi::v::ConstCStr sapi_ssl_key(ssl_key.c_str()); - curl_code = - api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLKEY, sapi_ssl_key.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLKEY, + sapi_ssl_key.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Set the password used to protect the private key sapi::v::ConstCStr sapi_ssl_key_password(ssl_key_password.c_str()); - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_KEYPASSWD, - sapi_ssl_key_password.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_KEYPASSWD, + sapi_ssl_key_password.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Set the file with the certificates vaildating the server sapi::v::ConstCStr sapi_ca_certificates(ca_certificates.c_str()); - curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_CAINFO, - sapi_ca_certificates.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_CAINFO, + sapi_ca_certificates.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Verify the authenticity of the server - curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 1L); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long( + &curl, curl::CURLOPT_SSL_VERIFYPEER, 1L)); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code); } // Perform the request - curl_code = api.curl_easy_perform(&curl); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl)); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_perform failed: " + curl_code); } // Cleanup curl easy handle - status = api.curl_easy_cleanup(&curl); - if (!status.ok()) { - LOG(FATAL) << "curl_easy_cleanup failed: " << status; - } + SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl)); // Cleanup curl - status = api.curl_global_cleanup(); - if (!status.ok()) { - LOG(FATAL) << "curl_global_cleanup failed: " << status; + SAPI_RETURN_IF_ERROR(api.curl_global_cleanup()); + + return absl::OkStatus(); +} + +} // namespace + +int main(int argc, char* argv[]) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + google::InitGoogleLogging(argv[0]); + + // Get input parameters (should be absolute paths) + if (argc != 5) { + LOG(ERROR) << "wrong number of arguments (4 expected)"; + return EXIT_FAILURE; + } + + if (absl::Status status = Example3(argv[1], argv[2], argv[3], argv[4]); + !status.ok()) { + LOG(ERROR) << "Example3 failed: " << status.ToString(); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/oss-internship-2020/curl/examples/example4.cc b/oss-internship-2020/curl/examples/example4.cc index 9103866..88b8f5e 100644 --- a/oss-internship-2020/curl/examples/example4.cc +++ b/oss-internship-2020/curl/examples/example4.cc @@ -21,107 +21,113 @@ #include "curl_sapi.sapi.h" // NOLINT(build/include) #include "sandboxed_api/util/flag.h" -int main(int argc, char* argv[]) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - google::InitGoogleLogging(argv[0]); - - absl::Status status; +namespace { +absl::Status Example4() { // Initialize sandbox2 and sapi - CurlSapiSandbox sandbox; - status = sandbox.Init(); - if (!status.ok()) { - LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status; - } - CurlApi api(&sandbox); + curl::CurlSapiSandbox sandbox; + SAPI_RETURN_IF_ERROR(sandbox.Init()); + curl::CurlApi api(&sandbox); // Number of running handles sapi::v::Int still_running(1); - absl::StatusOr curl_code; + int curl_code; // Initialize curl (CURL_GLOBAL_DEFAULT = 3) - curl_code = api.curl_global_init(3l); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_global_init failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l)); + if (curl_code != 0) { + return absl::UnavailableError("curl_global_init failed: " + curl_code); } // Initialize http_handle - absl::StatusOr curl_handle = api.curl_easy_init(); - if (!curl_handle.ok()) { - LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status(); - } - sapi::v::RemotePtr http_handle(curl_handle.value()); - if (!http_handle.GetValue()) { - LOG(FATAL) << "curl_easy_init failed: http_handle is NULL"; + curl::CURL* curl_handle; + SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init()); + sapi::v::RemotePtr http_handle(curl_handle); + if (!curl_handle) { + return absl::UnavailableError("curl_easy_init failed: curl is NULL"); } // Specify URL to get sapi::v::ConstCStr url("http://example.com"); - curl_code = - api.curl_easy_setopt_ptr(&http_handle, CURLOPT_URL, url.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_easy_setopt_ptr(&http_handle, curl::CURLOPT_URL, + url.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Initialize multi_handle - absl::StatusOr curlm_handle = api.curl_multi_init(); - if (!curlm_handle.ok()) { - LOG(FATAL) << "curl_multi_init failed: " << curlm_handle.status(); - } - sapi::v::RemotePtr multi_handle(curlm_handle.value()); - if (!multi_handle.GetValue()) { - LOG(FATAL) << "curl_multi_init failed: multi_handle is NULL"; + curl::CURLM* curlm_handle; + SAPI_ASSIGN_OR_RETURN(curlm_handle, api.curl_multi_init()); + sapi::v::RemotePtr multi_handle(curlm_handle); + if (!curlm_handle) { + return absl::UnavailableError( + "curl_multi_init failed: multi_handle is NULL"); } // Add http_handle to the multi stack - curl_code = api.curl_multi_add_handle(&multi_handle, &http_handle); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_multi_add_handle failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_multi_add_handle(&multi_handle, &http_handle)); + if (curl_code != 0) { + return absl::UnavailableError("curl_multi_add_handle failed: " + curl_code); } while (still_running.GetValue()) { sapi::v::Int numfds(0); // Perform the request - curl_code = api.curl_multi_perform(&multi_handle, still_running.PtrBoth()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_mutli_perform failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_multi_perform( + &multi_handle, still_running.PtrBoth())); + if (curl_code != 0) { + return absl::UnavailableError("curl_mutli_perform failed: " + curl_code); } if (still_running.GetValue()) { // Wait for an event or timeout sapi::v::NullPtr null_ptr; - curl_code = api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0, 1000, - numfds.PtrBoth()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_multi_poll_sapi failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN( + curl_code, api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0, 1000, + numfds.PtrBoth())); + if (curl_code != 0) { + return absl::UnavailableError("curl_multi_poll_sapi failed: " + + curl_code); } } } // Remove http_handle from the multi stack - curl_code = api.curl_multi_remove_handle(&multi_handle, &http_handle); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_multi_remove_handle failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, + api.curl_multi_remove_handle(&multi_handle, &http_handle)); + if (curl_code != 0) { + return absl::UnavailableError("curl_multi_remove_handle failed: " + + curl_code); } // Cleanup http_handle - status = api.curl_easy_cleanup(&http_handle); - if (!status.ok()) { - LOG(FATAL) << "curl_easy_cleanup failed: " << status; - } + SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&http_handle)); // Cleanup multi_handle - curl_code = api.curl_multi_cleanup(&multi_handle); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_multi_cleanup failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_multi_cleanup(&multi_handle)); + if (curl_code != 0) { + return absl::UnavailableError("curl_multi_cleanup failed: " + curl_code); } // Cleanup curl - status = api.curl_global_cleanup(); - if (!status.ok()) { - LOG(FATAL) << "curl_global_cleanup failed: " << status; + SAPI_RETURN_IF_ERROR(api.curl_global_cleanup()); + + return absl::OkStatus(); +} + +} // namespace + +int main(int argc, char* argv[]) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + google::InitGoogleLogging(argv[0]); + + if (absl::Status status = Example4(); !status.ok()) { + LOG(ERROR) << "Example4 failed: " << status.ToString(); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/oss-internship-2020/curl/examples/example5.cc b/oss-internship-2020/curl/examples/example5.cc index 8cc6a16..b1f94f3 100644 --- a/oss-internship-2020/curl/examples/example5.cc +++ b/oss-internship-2020/curl/examples/example5.cc @@ -15,87 +15,90 @@ // Sandboxed version of multithread.c // Multithreaded HTTP GET requests -#include - #include +#include // NOLINT(build/c++11) +#include // NOLINT(build/c++11) #include "../sandbox.h" // NOLINT(build/include) -void pull_one_url(const std::string& url, CurlApi& api) { +namespace { + +absl::Status pull_one_url(const std::string& url, curl::CurlApi& api) { // Initialize the curl session - absl::StatusOr curl_handle = api.curl_easy_init(); - if (!curl_handle.ok()) { - LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status(); - } - sapi::v::RemotePtr curl(curl_handle.value()); - if (!curl.GetValue()) { - LOG(FATAL) << "curl_easy_init failed: curl is NULL"; + curl::CURL* curl_handle; + SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init()); + sapi::v::RemotePtr curl(curl_handle); + if (!curl_handle) { + return absl::UnavailableError("curl_easy_init failed: curl is NULL"); } - absl::StatusOr curl_code; + int curl_code; // Specify URL to get sapi::v::ConstCStr sapi_url(url.c_str()); - curl_code = - api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, sapi_url.PtrBefore()); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, + sapi_url.PtrBefore())); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code); } // Perform the request - curl_code = api.curl_easy_perform(&curl); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status(); + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl)); + if (curl_code != 0) { + return absl::UnavailableError("curl_easy_perform failed: " + curl_code); } - // Cleanup curl - absl::Status status = api.curl_easy_cleanup(&curl); - if (!status.ok()) { - LOG(FATAL) << "curl_easy_cleanup failed: " << status; - } + // Cleanup curl easy handle + SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl)); + + return absl::OkStatus(); } const std::vector urls = { "http://example.com", "http://example.edu", "http://example.net", "http://example.org"}; +absl::Status Example5() { + // Initialize sandbox2 and sapi + curl::CurlSapiSandbox sandbox; + SAPI_RETURN_IF_ERROR(sandbox.Init()); + curl::CurlApi api(&sandbox); + + int curl_code; + + // Initialize curl (CURL_GLOBAL_DEFAULT = 3) + SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l)); + if (curl_code != 0) { + return absl::UnavailableError("curl_global_init failed: " + curl_code); + } + + // Create the threads (by using futures) + std::vector> futures; + for (auto& url : urls) { + futures.emplace_back( + std::async(pull_one_url, std::ref(url), std::ref(api))); + } + + // Join the threads and check for errors + for (auto& future : futures) { + SAPI_RETURN_IF_ERROR(future.get()); + } + + // Cleanup curl + SAPI_RETURN_IF_ERROR(api.curl_global_cleanup()); + + return absl::OkStatus(); +} + +} // namespace + int main(int argc, char* argv[]) { gflags::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); - absl::Status status; - - // Initialize sandbox2 and sapi - CurlSapiSandbox sandbox; - status = sandbox.Init(); - if (!status.ok()) { - LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status; - } - CurlApi api(&sandbox); - - absl::StatusOr curl_code; - - // Initialize curl (CURL_GLOBAL_DEFAULT = 3) - curl_code = api.curl_global_init(3l); - if (!curl_code.ok() || curl_code.value() != CURLE_OK) { - LOG(FATAL) << "curl_global_init failed: " << curl_code.status(); - } - - // Create the threads - std::vector threads; - for (auto& url : urls) { - threads.emplace_back(pull_one_url, std::ref(url), std::ref(api)); - } - - // Join the threads - for (auto& thread : threads) { - thread.join(); - } - - // Cleanup curl - status = api.curl_global_cleanup(); - if (!status.ok()) { - LOG(FATAL) << "curl_global_cleanup failed: " << status; + if (absl::Status status = Example5(); !status.ok()) { + LOG(ERROR) << "Example5 failed: " << status.ToString(); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/oss-internship-2020/curl/examples/example6.cc b/oss-internship-2020/curl/examples/example6.cc index 15fb1c2..de075f8 100644 --- a/oss-internship-2020/curl/examples/example6.cc +++ b/oss-internship-2020/curl/examples/example6.cc @@ -20,6 +20,8 @@ #include "../sandbox.h" // NOLINT(build/include) #include "sandboxed_api/transaction.h" +namespace { + class CurlTransaction : public sapi::Transaction { public: explicit CurlTransaction(std::unique_ptr sandbox) @@ -36,7 +38,7 @@ class CurlTransaction : public sapi::Transaction { }; absl::Status CurlTransaction::Main() { - CurlApi api(sandbox()); + curl::CurlApi api(sandbox()); // Initialize the curl session SAPI_ASSIGN_OR_RETURN(void* curl_remote, api.curl_easy_init()); @@ -47,13 +49,13 @@ absl::Status CurlTransaction::Main() { sapi::v::ConstCStr url("http://example.com"); SAPI_ASSIGN_OR_RETURN( int setopt_url_code, - api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore())); - TRANSACTION_FAIL_IF_NOT(setopt_url_code == CURLE_OK, + api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore())); + TRANSACTION_FAIL_IF_NOT(setopt_url_code == curl::CURLE_OK, "curl_easy_setopt_ptr failed"); // Perform the request SAPI_ASSIGN_OR_RETURN(int perform_code, api.curl_easy_perform(&curl)); - TRANSACTION_FAIL_IF_NOT(setopt_url_code == CURLE_OK, + TRANSACTION_FAIL_IF_NOT(setopt_url_code == curl::CURLE_OK, "curl_easy_perform failed"); // Cleanup curl @@ -63,8 +65,10 @@ absl::Status CurlTransaction::Main() { return absl::OkStatus(); } +} // namespace + int main(int argc, char* argv[]) { - CurlTransaction curl{std::make_unique()}; + CurlTransaction curl{std::make_unique()}; absl::Status status = curl.Run(); CHECK(status.ok()) << "CurlTransaction failed"; diff --git a/oss-internship-2020/curl/sandbox.h b/oss-internship-2020/curl/sandbox.h index 914617f..4e12d35 100644 --- a/oss-internship-2020/curl/sandbox.h +++ b/oss-internship-2020/curl/sandbox.h @@ -24,7 +24,9 @@ #include "curl_sapi.sapi.h" // NOLINT(build/include) #include "sandboxed_api/sandbox2/util/bpf_helper.h" -class CurlSapiSandbox : public CurlSandbox { +namespace curl { + +class CurlSapiSandbox : public curl::CurlSandbox { protected: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder* policy_builder) override { @@ -64,4 +66,6 @@ class CurlSapiSandbox : public CurlSandbox { } }; +} // namespace curl + #endif // SANDBOX_H_ diff --git a/oss-internship-2020/curl/tests/test_utils.cc b/oss-internship-2020/curl/tests/test_utils.cc index 8ea2897..061fee6 100644 --- a/oss-internship-2020/curl/tests/test_utils.cc +++ b/oss-internship-2020/curl/tests/test_utils.cc @@ -28,17 +28,17 @@ int CurlTestUtils::port_; std::thread CurlTestUtils::server_thread_; -absl::Status CurlTestUtils::CurlTestSetUp() { +absl::Status curl::tests::CurlTestUtils::CurlTestSetUp() { // Initialize sandbox2 and sapi - sandbox_ = std::make_unique(); + sandbox_ = std::make_unique(); absl::Status init = sandbox_->Init(); if (!init.ok()) { return init; } - api_ = std::make_unique(sandbox_.get()); + api_ = std::make_unique(sandbox_.get()); // Initialize curl - absl::StatusOr curl_handle = api_->curl_easy_init(); + absl::StatusOr curl_handle = api_->curl_easy_init(); if (!curl_handle.ok()) { return curl_handle.status(); } @@ -51,23 +51,24 @@ absl::Status CurlTestUtils::CurlTestSetUp() { // Specify request URL sapi::v::ConstCStr sapi_url(kUrl.data()); - curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_URL, + curl_code = api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_URL, sapi_url.PtrBefore()); if (!curl_code.ok()) { return curl_code.status(); } - if (curl_code.value() != CURLE_OK) { + if (curl_code.value() != curl::CURLE_OK) { return absl::UnavailableError( "curl_easy_setopt_ptr returned with the error code " + curl_code.value()); } // Set port - curl_code = api_->curl_easy_setopt_long(curl_.get(), CURLOPT_PORT, port_); + curl_code = + api_->curl_easy_setopt_long(curl_.get(), curl::CURLOPT_PORT, port_); if (!curl_code.ok()) { return curl_code.status(); } - if (curl_code.value() != CURLE_OK) { + if (curl_code.value() != curl::CURLE_OK) { return absl::UnavailableError( "curl_easy_setopt_long returned with the error code " + curl_code.value()); @@ -83,12 +84,12 @@ absl::Status CurlTestUtils::CurlTestSetUp() { sapi::v::RemotePtr remote_function_ptr(function_ptr); // Set WriteToMemory as the write function - curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEFUNCTION, - &remote_function_ptr); + curl_code = api_->curl_easy_setopt_ptr( + curl_.get(), curl::CURLOPT_WRITEFUNCTION, &remote_function_ptr); if (!curl_code.ok()) { return curl_code.status(); } - if (curl_code.value() != CURLE_OK) { + if (curl_code.value() != curl::CURLE_OK) { return absl::UnavailableError( "curl_easy_setopt_ptr returned with the error code " + curl_code.value()); @@ -96,12 +97,12 @@ absl::Status CurlTestUtils::CurlTestSetUp() { // Pass memory chunk object to the callback chunk_ = std::make_unique(0); - curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEDATA, + curl_code = api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_WRITEDATA, chunk_->PtrBoth()); if (!curl_code.ok()) { return curl_code.status(); } - if (curl_code.value() != CURLE_OK) { + if (curl_code.value() != curl::CURLE_OK) { return absl::UnavailableError( "curl_easy_setopt_ptr returned with the error code " + curl_code.value()); @@ -110,18 +111,18 @@ absl::Status CurlTestUtils::CurlTestSetUp() { return absl::OkStatus(); } -absl::Status CurlTestUtils::CurlTestTearDown() { +absl::Status curl::tests::CurlTestUtils::CurlTestTearDown() { // Cleanup curl return api_->curl_easy_cleanup(curl_.get()); } -absl::StatusOr CurlTestUtils::PerformRequest() { +absl::StatusOr curl::tests::CurlTestUtils::PerformRequest() { // Perform the request absl::StatusOr curl_code = api_->curl_easy_perform(curl_.get()); if (!curl_code.ok()) { return curl_code.status(); } - if (curl_code.value() != CURLE_OK) { + if (curl_code.value() != curl::CURLE_OK) { return absl::UnavailableError( "curl_easy_perform returned with the error code " + curl_code.value()); } @@ -267,7 +268,7 @@ void ServerLoop(int listening_socket, sockaddr_in socket_address) { } // namespace -void CurlTestUtils::StartMockServer() { +void curl::tests::CurlTestUtils::StartMockServer() { // Get the socket file descriptor int listening_socket = socket(AF_INET, SOCK_STREAM, 0); diff --git a/oss-internship-2020/curl/tests/test_utils.h b/oss-internship-2020/curl/tests/test_utils.h index fa74769..05e3a1a 100644 --- a/oss-internship-2020/curl/tests/test_utils.h +++ b/oss-internship-2020/curl/tests/test_utils.h @@ -21,6 +21,8 @@ #include "sandboxed_api/util/flag.h" #include "sandboxed_api/util/status_matchers.h" +namespace curl::tests { + // Helper class that can be used to test Curl Sandboxed class CurlTestUtils { protected: @@ -39,8 +41,8 @@ class CurlTestUtils { // Responds with the POST request fields to a POST request static void StartMockServer(); - std::unique_ptr sandbox_; - std::unique_ptr api_; + std::unique_ptr sandbox_; + std::unique_ptr api_; std::unique_ptr curl_; static std::thread server_thread_; @@ -52,4 +54,6 @@ class CurlTestUtils { std::unique_ptr chunk_; }; +} // namespace curl::tests + #endif // TESTS_H_ diff --git a/oss-internship-2020/curl/tests/tests.cc b/oss-internship-2020/curl/tests/tests.cc index c786169..87f78ed 100644 --- a/oss-internship-2020/curl/tests/tests.cc +++ b/oss-internship-2020/curl/tests/tests.cc @@ -14,7 +14,9 @@ #include "test_utils.h" // NOLINT(build/include) -class CurlTest : public CurlTestUtils, public ::testing::Test { +namespace { + +class CurlTest : public curl::tests::CurlTestUtils, public ::testing::Test { protected: void SetUp() override { // Start mock server, get port number and check for any error @@ -38,9 +40,9 @@ TEST_F(CurlTest, EffectiveUrl) { // Get effective URL SAPI_ASSERT_OK_AND_ASSIGN( int getinfo_code, - api_->curl_easy_getinfo_ptr(curl_.get(), CURLINFO_EFFECTIVE_URL, + api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_EFFECTIVE_URL, effective_url_ptr.PtrBoth())); - ASSERT_EQ(getinfo_code, CURLE_OK); + ASSERT_EQ(getinfo_code, curl::CURLE_OK); // Store effective URL in a string SAPI_ASSERT_OK_AND_ASSIGN(std::string effective_url, @@ -74,9 +76,9 @@ TEST_F(CurlTest, ResponseCode) { // Get response code SAPI_ASSERT_OK_AND_ASSIGN( int getinfo_code, - api_->curl_easy_getinfo_ptr(curl_.get(), CURLINFO_RESPONSE_CODE, + api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_RESPONSE_CODE, response_code.PtrBoth())); - ASSERT_EQ(getinfo_code, CURLE_OK); + ASSERT_EQ(getinfo_code, curl::CURLE_OK); // Check response code ASSERT_EQ(response_code.GetValue(), 200); @@ -120,19 +122,21 @@ TEST_F(CurlTest, POSTResponse) { // Set the size of the POST fields SAPI_ASSERT_OK_AND_ASSIGN( int setopt_post_fields_size, - api_->curl_easy_setopt_long(curl_.get(), CURLOPT_POSTFIELDSIZE, + api_->curl_easy_setopt_long(curl_.get(), curl::CURLOPT_POSTFIELDSIZE, post_fields.GetSize())); - ASSERT_EQ(setopt_post_fields_size, CURLE_OK); + ASSERT_EQ(setopt_post_fields_size, curl::CURLE_OK); // Set the POST fields SAPI_ASSERT_OK_AND_ASSIGN( int setopt_post_fields, - api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_POSTFIELDS, + api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_POSTFIELDS, post_fields.PtrBefore())); - ASSERT_EQ(setopt_post_fields, CURLE_OK); + ASSERT_EQ(setopt_post_fields, curl::CURLE_OK); SAPI_ASSERT_OK_AND_ASSIGN(std::string response, PerformRequest()); // Compare response with expected response ASSERT_EQ(std::string(post_fields.GetData()), response); } + +} // namespace diff --git a/oss-internship-2020/guetzli/BUILD.bazel b/oss-internship-2020/guetzli/BUILD.bazel index b00b12e..f4b4271 100644 --- a/oss-internship-2020/guetzli/BUILD.bazel +++ b/oss-internship-2020/guetzli/BUILD.bazel @@ -24,6 +24,7 @@ cc_library( srcs = ["guetzli_entry_points.cc"], hdrs = ["guetzli_entry_points.h"], deps = [ + "@com_google_absl//absl/status:statusor", "@com_google_sandboxed_api//sandboxed_api:lenval_core", "@com_google_sandboxed_api//sandboxed_api:vars", "@guetzli//:guetzli_lib", @@ -53,9 +54,7 @@ sapi_library( cc_binary( name = "guetzli_sandboxed", srcs = ["guetzli_sandboxed.cc"], - deps = [ - ":guetzli_sapi", - ], + deps = [":guetzli_sapi"], ) cc_test( diff --git a/oss-internship-2020/guetzli/WORKSPACE b/oss-internship-2020/guetzli/WORKSPACE.bazel similarity index 100% rename from oss-internship-2020/guetzli/WORKSPACE rename to oss-internship-2020/guetzli/WORKSPACE.bazel diff --git a/oss-internship-2020/guetzli/guetzli_entry_points.cc b/oss-internship-2020/guetzli/guetzli_entry_points.cc index 8de94b6..98ae384 100644 --- a/oss-internship-2020/guetzli/guetzli_entry_points.cc +++ b/oss-internship-2020/guetzli/guetzli_entry_points.cc @@ -25,8 +25,8 @@ #include "guetzli/jpeg_data_reader.h" #include "guetzli/quality.h" #include "png.h" // NOLINT(build/include) +#include "absl/status/statusor.h" #include "sandboxed_api/sandbox2/util/fileops.h" -#include "sandboxed_api/util/statusor.h" namespace { @@ -51,7 +51,7 @@ sapi::LenValStruct CreateLenValFromData(const void* data, size_t size) { return {size, new_data}; } -sapi::StatusOr ReadFromFd(int fd) { +absl::StatusOr ReadFromFd(int fd) { struct stat file_data; int status = fstat(fd, &file_data); @@ -70,9 +70,9 @@ sapi::StatusOr ReadFromFd(int fd) { return result; } -sapi::StatusOr PrepareDataForProcessing( +absl::StatusOr PrepareDataForProcessing( const ProcessingParams& processing_params) { - sapi::StatusOr input = ReadFromFd(processing_params.remote_fd); + absl::StatusOr input = ReadFromFd(processing_params.remote_fd); if (!input.ok()) { return input.status(); @@ -96,7 +96,7 @@ inline uint8_t BlendOnBlack(const uint8_t val, const uint8_t alpha) { } // Modified version of ReadPNG from original guetzli.cc -sapi::StatusOr ReadPNG(const std::string& data) { +absl::StatusOr ReadPNG(const std::string& data) { std::vector rgb; int xsize, ysize; png_structp png_ptr = diff --git a/oss-internship-2020/guetzli/guetzli_sandboxed.cc b/oss-internship-2020/guetzli/guetzli_sandboxed.cc index 944a572..0e064c7 100644 --- a/oss-internship-2020/guetzli/guetzli_sandboxed.cc +++ b/oss-internship-2020/guetzli/guetzli_sandboxed.cc @@ -17,7 +17,6 @@ #include "guetzli_transaction.h" // NOLINT(build/include) #include "sandboxed_api/sandbox2/util/fileops.h" -#include "sandboxed_api/util/statusor.h" namespace { diff --git a/oss-internship-2020/guetzli/guetzli_sapi_test.cc b/oss-internship-2020/guetzli/guetzli_sapi_test.cc index cd8bc91..b275036 100644 --- a/oss-internship-2020/guetzli/guetzli_sapi_test.cc +++ b/oss-internship-2020/guetzli/guetzli_sapi_test.cc @@ -83,7 +83,7 @@ TEST_F(GuetzliSapiTest, ProcessRGB) { *processing_params.mutable_data() = { in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb}; sapi::v::LenVal output(0); - sapi::StatusOr processing_result = + absl::StatusOr processing_result = api_->ProcessRgb(processing_params.PtrBefore(), output.PtrBoth()); ASSERT_TRUE(processing_result.value_or(false)) << "Error processing rgb data"; std::string reference_data = @@ -108,7 +108,7 @@ TEST_F(GuetzliSapiTest, ProcessJpeg) { *processing_params.mutable_data() = { in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb}; sapi::v::LenVal output(0); - sapi::StatusOr processing_result = + absl::StatusOr processing_result = api_->ProcessJpeg(processing_params.PtrBefore(), output.PtrBoth()); ASSERT_TRUE(processing_result.value_or(false)) << "Error processing jpg data"; std::string reference_data = diff --git a/oss-internship-2020/guetzli/guetzli_transaction.cc b/oss-internship-2020/guetzli/guetzli_transaction.cc index 2bd6e8a..d3bc1bd 100644 --- a/oss-internship-2020/guetzli/guetzli_transaction.cc +++ b/oss-internship-2020/guetzli/guetzli_transaction.cc @@ -99,7 +99,7 @@ absl::Status GuetzliTransaction::LinkOutFile(int out_fd) const { return absl::OkStatus(); } -sapi::StatusOr GuetzliTransaction::GetImageTypeFromFd(int fd) const { +absl::StatusOr GuetzliTransaction::GetImageTypeFromFd(int fd) const { static const unsigned char kPNGMagicBytes[] = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n', }; diff --git a/oss-internship-2020/guetzli/guetzli_transaction.h b/oss-internship-2020/guetzli/guetzli_transaction.h index 2996908..2cda32d 100644 --- a/oss-internship-2020/guetzli/guetzli_transaction.h +++ b/oss-internship-2020/guetzli/guetzli_transaction.h @@ -48,7 +48,7 @@ class GuetzliTransaction : public sapi::Transaction { absl::Status Main() final; absl::Status LinkOutFile(int out_fd) const; - sapi::StatusOr GetImageTypeFromFd(int fd) const; + absl::StatusOr GetImageTypeFromFd(int fd) const; const TransactionParams params_; ImageType image_type_ = ImageType::kJpeg; diff --git a/oss-internship-2020/jsonnet/CMakeLists.txt b/oss-internship-2020/jsonnet/CMakeLists.txt new file mode 100644 index 0000000..c7759b5 --- /dev/null +++ b/oss-internship-2020/jsonnet/CMakeLists.txt @@ -0,0 +1,58 @@ +# 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. + +cmake_minimum_required(VERSION 3.10) + +project(jsonnet-sapi C CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +add_subdirectory(jsonnet) + +add_subdirectory(examples) + +set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree") +set(SAPI_ENABLE_EXAMPLES OFF CACHE BOOL "") +set(SAPI_ENABLE_TESTS OFF CACHE BOOL "") + +add_subdirectory("${SAPI_ROOT}" + "${CMAKE_BINARY_DIR}/sandboxed-api-build" + EXCLUDE_FROM_ALL) + +add_sapi_library(jsonnet_sapi + FUNCTIONS c_jsonnet_evaluate_snippet + c_jsonnet_make + c_jsonnet_destroy + c_read_input + c_write_output_file + c_jsonnet_realloc + c_jsonnet_evaluate_snippet_multi + c_write_multi_output_files + c_write_output_stream + c_jsonnet_evaluate_snippet_stream + c_jsonnet_fmt_snippet + INPUTS jsonnet_helper.h + LIBRARY jsonnet_helper + LIBRARY_NAME Jsonnet + NAMESPACE "" +) + +target_include_directories(jsonnet_sapi INTERFACE + "${PROJECT_BINARY_DIR}" +) + +target_link_libraries(jsonnet_sapi PUBLIC jsonnet_helper) + +add_subdirectory(tests) diff --git a/oss-internship-2020/jsonnet/README.md b/oss-internship-2020/jsonnet/README.md new file mode 100644 index 0000000..43e46db --- /dev/null +++ b/oss-internship-2020/jsonnet/README.md @@ -0,0 +1,84 @@ +# Jsonnet Sandboxed API + +This library provides sandboxed version of the +[Jsonnet](https://github.com/google/jsonnet) library. + +## Examples + +The `examples/` directory contains code to produce three command-line tools -- +`jsonnet_sandboxed`, `jsonnet_yaml_stream_sandboxed` and +`jsonnet_multiple_files_sandboxed` to evaluate jsonnet code. The first one +enables the user to evaluate jsonnet code held in one file and writing to one +output file. The second evaluates one jsonnet file into one file, which can be +interepreted as YAML stream. The third one is for evaluating one jsonnet file +into multiple output files. All three tools are based on what can be found +[here](https://github.com/google/jsonnet/blob/master/cmd/jsonnet.cpp). + +Apart from these, there is also a file producing `jsonnet_formatter_sandboxed` +executable. It is based on a tool found from +[here](https://github.com/google/jsonnet/blob/master/cmd/jsonnetfmt.cpp). It is +a jsonnet code formatter -- it changes poorly written jsonnet files into their +canonical form. + +## Build + +To build these examples, after cloning the whole Sandbox API project, you also +need to run + +``` +git submodule update --init --recursive +``` +anywhere in the project tree in order to clone the `jsonnet` submodule. +Then in the `sandboxed-api/oss-internship-2020/jsonnet` run + +``` +mkdir build && cd build +cmake -G Ninja +ninja +``` + +To run `jsonnet_sandboxed` (or `jsonnet_yaml_stream_sandboxed` or +`jsonnet_formatter_sandboxed` in a similar way): + +``` +cd examples +./jsonnet_sandboxed \ + absolute/path/to/the/input_file.jsonnet \ + absolute/path/to/the/output_file +``` + +To run `jsonnet_mutiple_files_sandboxed`: + +``` +cd examples +./jsonnet_mutiple_files_sandboxed \ + absolute/path/to/the/input_file.jsonnet \ + absolute/path/to/the/output_directory +``` + +All three tools support evaluating one input file (possibly relying on multiple +other files, e.x. by jsonnet `import` command; the files must be held in the +same directory as input file) into one or more output files. Example jsonnet +codes to evaluate in a one-in-one-out manner can be found +[here](https://github.com/google/jsonnet/tree/master/examples). Example code +producing multiple output files or YAML stream files can be found in the +`examples/jsonnet_codes` directory (along with some other examples copied with +minimal changes from the library files), in files called +`multiple_files_example.jsonnet` and `yaml_stream_example.jsonnet`, +respectively. In the `examples/jsonnet_codes_expected_output` directory one can +found outputs the mentioned above files' evaluation should produce. + +The formatter reads one input file and produces one output file as a result. +Example code for this tool can also be found in `examples/jsonnet_codes` +directory, in a file called `formatter_example.jsonnet`. + +## Testing + +A few tests prepared with a use of +[Google Test](https://github.com/google/googletest) framework can be found in +the `tests/` directory. To run them type: + +``` +cd tests +./tests +``` diff --git a/oss-internship-2020/jsonnet/examples/CMakeLists.txt b/oss-internship-2020/jsonnet/examples/CMakeLists.txt new file mode 100644 index 0000000..eafe2d0 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/CMakeLists.txt @@ -0,0 +1,75 @@ +# 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. + +file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/gen_files") +file(COPY "${PROJECT_SOURCE_DIR}/jsonnet/cmd/jsonnet.cpp" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/") +file(COPY "${PROJECT_SOURCE_DIR}/jsonnet.patch" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/") + +add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/gen_files/write_helper.cc + COMMAND cd ${PROJECT_BINARY_DIR}/gen_files && patch < ${PROJECT_SOURCE_DIR}/jsonnet.patch > /dev/null + COMMAND mv ${PROJECT_BINARY_DIR}/gen_files/jsonnet.cpp ${PROJECT_BINARY_DIR}/gen_files/write_helper.cc +) + +list(APPEND JSONNET_SAPI_HEADERS + ${PROJECT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/headers + ${PROJECT_BINARY_DIR}/gen_files +) + +add_library(jsonnet_helper STATIC + ${PROJECT_SOURCE_DIR}/jsonnet_helper.cc + ${PROJECT_SOURCE_DIR}/jsonnet_helper.h + ${PROJECT_SOURCE_DIR}/jsonnet/cmd/utils.h + ${PROJECT_SOURCE_DIR}/jsonnet/cmd/utils.cpp + ${PROJECT_BINARY_DIR}/gen_files/write_helper.cc +) + +target_include_directories(jsonnet_helper PUBLIC + ${JSONNET_SAPI_HEADERS} +) + +target_link_libraries(jsonnet_helper + libjsonnet_for_binaries +) + +foreach(exe base multiple_files yaml_stream formatter) + add_executable(jsonnet_${exe}_sandboxed + jsonnet_${exe}_example.cc + ) + + target_link_libraries(jsonnet_${exe}_sandboxed PRIVATE + libjsonnet + jsonnet_helper + jsonnet_sapi + sandbox2::file_base + sandbox2::fileops + sapi::sapi + ) + + target_include_directories(jsonnet_${exe}_sandboxed PUBLIC + ${JSONNET_SAPI_HEADERS} + ) +endforeach() + +add_executable(jsonnet_base_transacted + jsonnet_base_transaction.cc +) + +target_link_libraries(jsonnet_base_transacted PRIVATE + libjsonnet + jsonnet_helper + jsonnet_sapi + sapi::sapi +) diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_base_example.cc b/oss-internship-2020/jsonnet/examples/jsonnet_base_example.cc new file mode 100644 index 0000000..519f803 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_base_example.cc @@ -0,0 +1,95 @@ +// 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 +#include + +#include "jsonnet_base_sandbox.h" // NOLINT(build/include) +#include "sandboxed_api/sandbox2/util/fileops.h" +#include "sandboxed_api/sandbox2/util/path.h" + +absl::Status JsonnetMain(std::string in_file, std::string out_file) { + using sandbox2::file::JoinPath; + using sandbox2::file_util::fileops::Basename; + + // Initialize sandbox. + JsonnetBaseSandbox sandbox(in_file, out_file); + SAPI_RETURN_IF_ERROR(sandbox.Init()) + + JsonnetApi api(&sandbox); + + // Initialize library's main structure. + SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make()); + sapi::v::RemotePtr vm_pointer(jsonnet_vm); + + // Read input file. + std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file))); + sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str()); + SAPI_ASSIGN_OR_RETURN(char* input, + api.c_read_input(false, in_file_var.PtrBefore())); + + // Process jsonnet data. + sapi::v::RemotePtr input_pointer(input); + sapi::v::Int error; + SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet( + &vm_pointer, in_file_var.PtrBefore(), + &input_pointer, error.PtrAfter())); + CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: " + << error.GetValue() << "\n" + << "Make sure all files used by your jsonnet file " + "are in the same directory as your file."; + + // Write data to file. + std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file))); + sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str()); + sapi::v::RemotePtr output_pointer(output); + + SAPI_ASSIGN_OR_RETURN( + bool success, + api.c_write_output_file(&output_pointer, out_file_var.PtrBefore())); + CHECK(success) << "Writing to output file failed: " << success; + + // Clean up. + SAPI_ASSIGN_OR_RETURN(char* result, + api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0)); + SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer)); + SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer)); + + return absl::OkStatus(); +} + +int main(int argc, char* argv[]) { + using sandbox2::file_util::fileops::Basename; + + google::InitGoogleLogging(argv[0]); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + if (!(argc == 3)) { + std::cerr << "Usage:\n" + << Basename(argv[0]) + << " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n"; + return EXIT_FAILURE; + } + + std::string in_file(argv[1]); + std::string out_file(argv[2]); + + absl::Status status = JsonnetMain(in_file, out_file); + if (!status.ok()) { + LOG(ERROR) << "Failed: " << status.ToString(); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_base_transaction.cc b/oss-internship-2020/jsonnet/examples/jsonnet_base_transaction.cc new file mode 100644 index 0000000..2d199b5 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_base_transaction.cc @@ -0,0 +1,88 @@ +// 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 "jsonnet_base_transaction.h" // NOLINT(build/include) + +#include "sandboxed_api/sandbox2/util/fileops.h" +#include "sandboxed_api/sandbox2/util/path.h" + +absl::Status JsonnetTransaction::Main() { + using sandbox2::file::JoinPath; + using sandbox2::file_util::fileops::Basename; + + JsonnetApi api(sandbox()); + + // Initialize library's main structure. + SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make()); + sapi::v::RemotePtr vm_pointer(jsonnet_vm); + + // Read input file. + std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file))); + sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str()); + SAPI_ASSIGN_OR_RETURN(char* input, + api.c_read_input(false, in_file_var.PtrBefore())); + + // Process jsonnet data. + sapi::v::RemotePtr input_pointer(input); + sapi::v::Int error; + SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet( + &vm_pointer, in_file_var.PtrBefore(), + &input_pointer, error.PtrAfter())); + TRANSACTION_FAIL_IF_NOT(error.GetValue() == 0, + "Jsonnet code evaluation failed."); + + // Write data to file. + std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file))); + sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str()); + sapi::v::RemotePtr output_pointer(output); + SAPI_ASSIGN_OR_RETURN( + bool success, + api.c_write_output_file(&output_pointer, out_file_var.PtrBefore())); + TRANSACTION_FAIL_IF_NOT(success, "Writing to output file failed."); + + // Clean up. + SAPI_ASSIGN_OR_RETURN(char* result, + api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0)); + + SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer)); + SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer)); + + return absl::OkStatus(); +} + +int main(int argc, char* argv[]) { + using sandbox2::file_util::fileops::Basename; + + google::InitGoogleLogging(argv[0]); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + if (!(argc == 3)) { + std::cerr << "Usage:\n" + << Basename(argv[0]) + << " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n"; + return EXIT_FAILURE; + } + + std::string in_file(argv[1]); + std::string out_file(argv[2]); + + JsonnetTransaction jsonnet_transaction(in_file, out_file); + + auto result = jsonnet_transaction.Run(); + + LOG(INFO) << "Transaction result: " << result.message(); + CHECK(result.ok()); + + return EXIT_SUCCESS; +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes/arith.jsonnet b/oss-internship-2020/jsonnet/examples/jsonnet_codes/arith.jsonnet new file mode 100644 index 0000000..c967b95 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes/arith.jsonnet @@ -0,0 +1,50 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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. +*/ + +{ + concat_array: [1, 2, 3] + [4], + concat_string: '123' + 4, + equality1: 1 == '1', + equality2: [{}, { x: 3 - 1 }] + == [{}, { x: 2 }], + ex1: 1 + 2 * 3 / (4 + 5), + // Bitwise operations first cast to int. + ex2: self.ex1 | 3, + // Modulo operator. + ex3: self.ex1 % 2, + // Boolean logic + ex4: (4 > 3) && (1 <= 3) || false, + // Mixing objects together + obj: { a: 1, b: 2 } + { b: 3, c: 4 }, + // Test if a field is in an object + obj_member: 'foo' in { foo: 1 }, + // String formatting + str1: 'The value of self.ex2 is ' + + self.ex2 + '.', + str2: 'The value of self.ex2 is %g.' + % self.ex2, + str3: 'ex1=%0.2f, ex2=%0.2f' + % [self.ex1, self.ex2], + // By passing self, we allow ex1 and ex2 to + // be extracted internally. + str4: 'ex1=%(ex1)0.2f, ex2=%(ex2)0.2f' + % self, + // Do textual templating of entire files: + str5: ||| + ex1=%(ex1)0.2f + ex2=%(ex2)0.2f + ||| % self, +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes/formatter_example.jsonnet b/oss-internship-2020/jsonnet/examples/jsonnet_codes/formatter_example.jsonnet new file mode 100644 index 0000000..29ef188 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes/formatter_example.jsonnet @@ -0,0 +1,32 @@ +// 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. + +// This is a poorly written jsonnet file. Given to the formatter executable will be changed into a canonical jsonnet file form. +local b = import "somefile.libsonnet"; # comment +local a = import "differentfile.libsonnet"; // another comment in different style + +local SomeStuff = {bar: "foo"}; + + local funtion_to_do_addition(x,y)=x+y; + + { +"this": ((3)) , +"that that": +funtion_to_do_addition(4,2), +arrArr: [[ + 1, 2, 5 + ], + 3, 10, 19 + ] +} + SomeStuff diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes/imports.jsonnet b/oss-internship-2020/jsonnet/examples/jsonnet_codes/imports.jsonnet new file mode 100644 index 0000000..7b26dd2 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes/imports.jsonnet @@ -0,0 +1,30 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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. +*/ + +local martinis = import 'martinis.libsonnet'; + +{ + 'Vodka Martini': martinis['Vodka Martini'], + Manhattan: { + ingredients: [ + { kind: 'Rye', qty: 2.5 }, + { kind: 'Sweet Red Vermouth', qty: 1 }, + { kind: 'Angostura', qty: 'dash' }, + ], + garnish: importstr 'garnish.txt', + served: 'Straight Up', + }, +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes/multiple_files_example.jsonnet b/oss-internship-2020/jsonnet/examples/jsonnet_codes/multiple_files_example.jsonnet new file mode 100644 index 0000000..4856eee --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes/multiple_files_example.jsonnet @@ -0,0 +1,26 @@ +// 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. + +// This is a jsonnet code which evaluates to mutliple output files. +{ + "first_file.json": { + name: 'This is the first file created by the multiple-files example code.', + caption: 'The other one\'s name is -> ' + $["second_file.json"].name, + }, + "second_file.json": { + name: 'And that is the other one.', + caption: 'If it was the first one, variable name would hold what\'s in variable.', + first_name: $["first_file.json"].name, + }, +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes/negroni.jsonnet b/oss-internship-2020/jsonnet/examples/jsonnet_codes/negroni.jsonnet new file mode 100644 index 0000000..4f42b27 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes/negroni.jsonnet @@ -0,0 +1,29 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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. +*/ + +local utils = import 'utils.libsonnet'; +{ + Negroni: { + // Divide 3oz among the 3 ingredients. + ingredients: utils.equal_parts(3, [ + 'Farmers Gin', + 'Sweet Red Vermouth', + 'Campari', + ]), + garnish: 'Orange Peel', + served: 'On The Rocks', + }, +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes/utils.libsonnet b/oss-internship-2020/jsonnet/examples/jsonnet_codes/utils.libsonnet new file mode 100644 index 0000000..7fd1fcc --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes/utils.libsonnet @@ -0,0 +1,26 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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. +*/ + +{ + equal_parts(size, ingredients):: + // Define a function-scoped variable. + local qty = size / std.length(ingredients); + // Return an array. + [ + { kind: i, qty: qty } + for i in ingredients + ], +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes/yaml_stream_example.jsonnet b/oss-internship-2020/jsonnet/examples/jsonnet_codes/yaml_stream_example.jsonnet new file mode 100644 index 0000000..ca7520a --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes/yaml_stream_example.jsonnet @@ -0,0 +1,26 @@ +// 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. + +// This is a jsonnet code which evaluates to json file, which can be interpreted as YAML stream. +local + first_object = { + name: 'First object\'s name.', + age: 'Just created!', + }, + second_object = { + name: 'Hi, my name is .', + sibling: first_object.name + }; + +[first_object, second_object] diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/arith.golden b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/arith.golden new file mode 100644 index 0000000..a23901c --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/arith.golden @@ -0,0 +1,26 @@ +{ + "concat_array": [ + 1, + 2, + 3, + 4 + ], + "concat_string": "1234", + "equality1": false, + "equality2": true, + "ex1": 1.6666666666666665, + "ex2": 3, + "ex3": 1.6666666666666665, + "ex4": true, + "obj": { + "a": 1, + "b": 3, + "c": 4 + }, + "obj_member": true, + "str1": "The value of self.ex2 is 3.", + "str2": "The value of self.ex2 is 3.", + "str3": "ex1=1.67, ex2=3.00", + "str4": "ex1=1.67, ex2=3.00", + "str5": "ex1=1.67\nex2=3.00\n" +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/first_file.json b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/first_file.json new file mode 100644 index 0000000..eb28fde --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/first_file.json @@ -0,0 +1,4 @@ +{ + "caption": "The other one's name is -> And that is the other one.", + "name": "This is the first file created by the multiple-files example code." +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/negroni.golden b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/negroni.golden new file mode 100644 index 0000000..b25b2fc --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/negroni.golden @@ -0,0 +1,20 @@ +{ + "Negroni": { + "garnish": "Orange Peel", + "ingredients": [ + { + "kind": "Farmers Gin", + "qty": 1 + }, + { + "kind": "Sweet Red Vermouth", + "qty": 1 + }, + { + "kind": "Campari", + "qty": 1 + } + ], + "served": "On The Rocks" + } +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/second_file.json b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/second_file.json new file mode 100644 index 0000000..5afb469 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/second_file.json @@ -0,0 +1,5 @@ +{ + "caption": "If it was the first one, variable name would hold what's in variable.", + "first_name": "This is the first file created by the multiple-files example code.", + "name": "And that is the other one." +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/yaml_stream_example.yaml b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/yaml_stream_example.yaml new file mode 100644 index 0000000..231a5d0 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_codes_expected_output/yaml_stream_example.yaml @@ -0,0 +1,11 @@ +--- +{ + "age": "Just created!", + "name": "First object's name." +} +--- +{ + "name": "Hi, my name is .", + "sibling": "First object's name." +} +... diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_formatter_example.cc b/oss-internship-2020/jsonnet/examples/jsonnet_formatter_example.cc new file mode 100644 index 0000000..f236e16 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_formatter_example.cc @@ -0,0 +1,128 @@ +// 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 +#include + +#include +#include + +#include "jsonnet_sapi.sapi.h" // NOLINT(build/include) +#include "sandboxed_api/util/flag.h" +#include "sandboxed_api/sandbox2/util/fileops.h" +#include "sandboxed_api/sandbox2/util/path.h" + +class JsonnetSapiSandbox : public JsonnetSandbox { + public: + explicit JsonnetSapiSandbox(std::string in_file, std::string out_file) + : in_file_(std::move(in_file)), out_file_(std::move(out_file)) {} + + // We need only the input file here, not the whole input directory + std::unique_ptr ModifyPolicy( + sandbox2::PolicyBuilder*) override { + return sandbox2::PolicyBuilder() + .AllowStaticStartup() + .AllowOpen() + .AllowRead() + .AllowWrite() + .AllowStat() + .AllowSystemMalloc() + .AllowExit() + .AllowSyscalls({ + __NR_futex, + __NR_close, + }) + .AddDirectoryAt(dirname(&out_file_[0]), "/output", /*is_ro=*/false) + .AddFile(in_file_, true) + .BuildOrDie(); + } + + private: + std::string in_file_; + std::string out_file_; +}; + +absl::Status JsonnetMain(std::string in_file, std::string out_file) { + using sandbox2::file::JoinPath; + using sandbox2::file_util::fileops::Basename; + + // Initialize sandbox. + JsonnetSapiSandbox sandbox(in_file, out_file); + SAPI_RETURN_IF_ERROR(sandbox.Init()) + + JsonnetApi api(&sandbox); + + // Initialize library's main structure. + SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make()); + sapi::v::RemotePtr vm_pointer(jsonnet_vm); + + // Read input file. + std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file))); + sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str()); + SAPI_ASSIGN_OR_RETURN(char* input, + api.c_read_input(false, in_file_var.PtrBefore())); + + // Process jsonnet data. + sapi::v::RemotePtr input_pointer(input); + sapi::v::Int error; + SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_fmt_snippet( + &vm_pointer, in_file_var.PtrBefore(), + &input_pointer, error.PtrAfter())); + + CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: " + << error.GetValue() << "\n"; + + // Write data to file. + std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file))); + sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str()); + sapi::v::RemotePtr output_pointer(output); + + SAPI_ASSIGN_OR_RETURN( + bool success, + api.c_write_output_file(&output_pointer, out_file_var.PtrBefore())); + CHECK(success) << "Writing to output file failed: " << success; + + // Clean up. + SAPI_ASSIGN_OR_RETURN(char* result, + api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0)); + SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer)); + SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer)); + + return absl::OkStatus(); +} + +int main(int argc, char* argv[]) { + using sandbox2::file_util::fileops::Basename; + + google::InitGoogleLogging(argv[0]); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + if (!(argc == 3)) { + std::cerr << "Usage:\n" + << Basename(argv[0]) + << " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n"; + return EXIT_FAILURE; + } + + std::string in_file(argv[1]); + std::string out_file(argv[2]); + + absl::Status status = JsonnetMain(in_file, out_file); + if (!status.ok()) { + LOG(ERROR) << "Failed: " << status.ToString(); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_multiple_files_example.cc b/oss-internship-2020/jsonnet/examples/jsonnet_multiple_files_example.cc new file mode 100644 index 0000000..c26f9b3 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_multiple_files_example.cc @@ -0,0 +1,132 @@ +// 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 +#include + +#include +#include + +#include "jsonnet_sapi.sapi.h" // NOLINT(build/include) +#include "sandboxed_api/util/flag.h" +#include "sandboxed_api/sandbox2/util/fileops.h" +#include "sandboxed_api/sandbox2/util/path.h" + +class JsonnetSapiSandbox : public JsonnetSandbox { + public: + explicit JsonnetSapiSandbox(std::string in_file, std::string out_directory) + : in_file_(std::move(in_file)), + out_directory_(std::move(out_directory)) {} + + // We need a slightly different policy than the default one + std::unique_ptr ModifyPolicy( + sandbox2::PolicyBuilder*) override { + return sandbox2::PolicyBuilder() + .AllowStaticStartup() + .AllowOpen() + .AllowRead() + .AllowWrite() + .AllowStat() + .AllowSystemMalloc() + .AllowExit() + .AllowSyscalls({ + __NR_futex, + __NR_close, + }) + .AddDirectoryAt(sandbox2::file::CleanPath(&out_directory_[0]), + "/output", + /*is_ro=*/false) + .AddDirectoryAt(dirname(&in_file_[0]), "/input", true) + .BuildOrDie(); + } + + private: + std::string in_file_; + std::string out_directory_; +}; + +absl::Status JsonnetMain(std::string in_file, std::string out_file) { + using sandbox2::file::JoinPath; + using sandbox2::file_util::fileops::Basename; + + // Initialize sandbox. + JsonnetSapiSandbox sandbox(in_file, out_file); + SAPI_RETURN_IF_ERROR(sandbox.Init()) + + JsonnetApi api(&sandbox); + + // Initialize library's main structure. + SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make()); + sapi::v::RemotePtr vm_pointer(jsonnet_vm); + + // Read input file. + std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file))); + sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str()); + SAPI_ASSIGN_OR_RETURN(char* input, + api.c_read_input(false, in_file_var.PtrBefore())); + + // Process jsonnet data. + sapi::v::RemotePtr input_pointer(input); + sapi::v::Int error; + SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet_multi( + &vm_pointer, in_file_var.PtrBefore(), + &input_pointer, error.PtrAfter())); + CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: " + << error.GetValue() << "\n" + << "Make sure all files used by your jsonnet file " + "are in the same directory as your file."; + + // Write data to file. + std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file))); + sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str()); + sapi::v::RemotePtr output_pointer(output); + + SAPI_ASSIGN_OR_RETURN( + bool success, + api.c_write_output_file(&output_pointer, out_file_var.PtrBefore())); + CHECK(success) << "Writing to output file failed: " << success; + + // Clean up. + SAPI_ASSIGN_OR_RETURN(char* result, + api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0)); + SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer)); + SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer)); + + return absl::OkStatus(); +} + +int main(int argc, char* argv[]) { + using sandbox2::file_util::fileops::Basename; + + google::InitGoogleLogging(argv[0]); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + if (!(argc == 3)) { + std::cerr << "Usage:\n" + << Basename(argv[0]) + << " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n"; + return EXIT_FAILURE; + } + + std::string in_file(argv[1]); + std::string out_file(argv[2]); + + absl::Status status = JsonnetMain(in_file, out_file); + if (!status.ok()) { + LOG(ERROR) << "Failed: " << status.ToString(); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/oss-internship-2020/jsonnet/examples/jsonnet_yaml_stream_example.cc b/oss-internship-2020/jsonnet/examples/jsonnet_yaml_stream_example.cc new file mode 100644 index 0000000..7a92809 --- /dev/null +++ b/oss-internship-2020/jsonnet/examples/jsonnet_yaml_stream_example.cc @@ -0,0 +1,95 @@ +// 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 +#include + +#include "jsonnet_base_sandbox.h" // NOLINT(build/include) +#include "sandboxed_api/sandbox2/util/fileops.h" +#include "sandboxed_api/sandbox2/util/path.h" + +absl::Status JsonnetMain(std::string in_file, std::string out_file) { + using sandbox2::file::JoinPath; + using sandbox2::file_util::fileops::Basename; + + // Initialize sandbox. + JsonnetBaseSandbox sandbox(in_file, out_file); + SAPI_RETURN_IF_ERROR(sandbox.Init()) + + JsonnetApi api(&sandbox); + + // Initialize library's main structure. + SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make()); + sapi::v::RemotePtr vm_pointer(jsonnet_vm); + + // Read input file. + std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file))); + sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str()); + SAPI_ASSIGN_OR_RETURN(char* input, + api.c_read_input(false, in_file_var.PtrBefore())); + + // Process jsonnet data. + sapi::v::RemotePtr input_pointer(input); + sapi::v::Int error; + SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet_stream( + &vm_pointer, in_file_var.PtrBefore(), + &input_pointer, error.PtrAfter())); + CHECK(!error.GetValue()) + << "Jsonnet code evaluation failed: " << error.GetValue() << "\n" + << "Make sure all files used by your jsonnet file are in the same " + "directory as your file."; + + // Write data to file. + std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file))); + sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str()); + sapi::v::RemotePtr output_pointer(output); + + SAPI_ASSIGN_OR_RETURN( + bool success, + api.c_write_output_file(&output_pointer, out_file_var.PtrBefore())); + CHECK(success) << "Writing to output file failed: " << success; + + // Clean up. + SAPI_ASSIGN_OR_RETURN(char* result, + api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0)); + SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer)); + SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer)); + + return absl::OkStatus(); +} + +int main(int argc, char* argv[]) { + using sandbox2::file_util::fileops::Basename; + + google::InitGoogleLogging(argv[0]); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + if (!(argc == 3)) { + std::cerr << "Usage:\n" + << Basename(argv[0]) + << " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n"; + return EXIT_FAILURE; + } + + std::string in_file(argv[1]); + std::string out_file(argv[2]); + + absl::Status status = JsonnetMain(in_file, out_file); + if (!status.ok()) { + LOG(ERROR) << "Failed: " << status.ToString(); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/oss-internship-2020/jsonnet/headers/jsonnet_base_sandbox.h b/oss-internship-2020/jsonnet/headers/jsonnet_base_sandbox.h new file mode 100644 index 0000000..4d2eb1e --- /dev/null +++ b/oss-internship-2020/jsonnet/headers/jsonnet_base_sandbox.h @@ -0,0 +1,55 @@ +// 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 JSONNET_BASE_SANDBOX_H_ +#define JSONNET_BASE_SANDBOX_H_ + +#include +#include + +#include "jsonnet_sapi.sapi.h" // NOLINT(build/include) +#include "sandboxed_api/util/flag.h" +#include "sandboxed_api/transaction.h" +#include "sandboxed_api/vars.h" + +class JsonnetBaseSandbox : public JsonnetSandbox { + public: + explicit JsonnetBaseSandbox(std::string in_file, std::string out_file) + : in_file_(in_file), out_file_(out_file) {} + + std::unique_ptr ModifyPolicy( + sandbox2::PolicyBuilder *) override { + return sandbox2::PolicyBuilder() + .AllowStaticStartup() + .AllowOpen() + .AllowRead() + .AllowWrite() + .AllowStat() + .AllowSystemMalloc() + .AllowExit() + .AllowSyscalls({ + __NR_futex, + __NR_close, + }) + .AddDirectoryAt(dirname(&out_file_[0]), "/output", /*is_ro=*/false) + .AddDirectoryAt(dirname(&in_file_[0]), "/input", true) + .BuildOrDie(); + } + + private: + std::string in_file_; + std::string out_file_; +}; + +#endif // JSONNET_BASE_SANDBOX_H_ diff --git a/oss-internship-2020/jsonnet/headers/jsonnet_base_transaction.h b/oss-internship-2020/jsonnet/headers/jsonnet_base_transaction.h new file mode 100644 index 0000000..7208ae3 --- /dev/null +++ b/oss-internship-2020/jsonnet/headers/jsonnet_base_transaction.h @@ -0,0 +1,38 @@ +// 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 JSNONNET_BASE_TRANSACTION_H_ +#define JSNONNET_BASE_TRANSACTION_H_ + +#include "jsonnet_base_sandbox.h" // NOLINT(build/include) + +class JsonnetTransaction : public sapi::Transaction { + public: + JsonnetTransaction(std::string in_file, std::string out_file) + : sapi::Transaction( + std::make_unique(in_file, out_file)), + in_file_(in_file), + out_file_(out_file) { + sapi::Transaction::set_retry_count(0); // Try once, no retries + sapi::Transaction::SetTimeLimit(0); // Infinite time limit + } + + private: + std::string in_file_; + std::string out_file_; + + absl::Status Main() override; +}; + +#endif // JSNONNET_BASE_TRANSACTION_H_ diff --git a/oss-internship-2020/jsonnet/headers/jsonnet_tests.h b/oss-internship-2020/jsonnet/headers/jsonnet_tests.h new file mode 100644 index 0000000..cd58b65 --- /dev/null +++ b/oss-internship-2020/jsonnet/headers/jsonnet_tests.h @@ -0,0 +1,57 @@ +// 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 JSONNET_TESTS_H_ +#define JSONNET_TESTS_H_ + +#include + +#include +#include +#include +#include +#include +#include + +#include "jsonnet_base_sandbox.h" // NOLINT(build/include) +#include "jsonnet_sapi.sapi.h" // NOLINT(build/include) +#include "gtest/gtest.h" +#include "sandboxed_api/util/flag.h" +#include "sandboxed_api/sandbox2/util/path.h" +#include "sandboxed_api/util/status_matchers.h" + +class JsonnetTestHelper { + protected: + enum Evaluation { kBase, kMultipleFiles, kYamlStream }; + + void TestSetUp(); + void TestTearDown(); + + void ReadInput(const char* filename); + void EvaluateJsonnetCode(Evaluation type, bool expected_correct); + void WriteOutput(const char* filename_or_directory, Evaluation type); + std::string ReadOutput(const char* filename); + + std::unique_ptr sandbox_; + std::unique_ptr api_; + std::unique_ptr input_; + std::unique_ptr output_; + std::unique_ptr vm_; + + std::string input_filename_in_sandboxee_; + bool jsonnet_vm_was_used_; + bool input_was_read_; +}; + +#endif // JSONNET_TESTS_H_ diff --git a/oss-internship-2020/jsonnet/jsonnet b/oss-internship-2020/jsonnet/jsonnet new file mode 160000 index 0000000..3e25595 --- /dev/null +++ b/oss-internship-2020/jsonnet/jsonnet @@ -0,0 +1 @@ +Subproject commit 3e25595d5c4acd32a1c3951a57471986b90d3bad diff --git a/oss-internship-2020/jsonnet/jsonnet.patch b/oss-internship-2020/jsonnet/jsonnet.patch new file mode 100644 index 0000000..57f1812 --- /dev/null +++ b/oss-internship-2020/jsonnet/jsonnet.patch @@ -0,0 +1,664 @@ +--- jsonnet.cpp 2020-09-09 12:15:33.687539042 +0000 ++++ write_helper.cpp 2020-09-25 15:38:37.317147682 +0000 +@@ -14,559 +14,125 @@ + limitations under the License. + */ + +-#include +-#include +-#include ++// We need two functions defined in jsonnet.cpp file, used for writing output ++// (multiple files and yaml streams) -- with minor changes (e.x. return type). + +-#include + #include + #include +-#include + #include +-#include +-#include + #include + +-#include "utils.h" ++#include "jsonnet_helper.h" // NOLINT(build/include) + +-extern "C" { +-#include +-} +- +-#ifdef _WIN32 +-const char PATH_SEP = ';'; +-#else +-const char PATH_SEP = ':'; +-#endif +- +-void version(std::ostream &o) +-{ +- o << "Jsonnet commandline interpreter " << jsonnet_version() << std::endl; +-} +- +-void usage(std::ostream &o) +-{ +- version(o); +- o << "\n"; +- o << "jsonnet {