diff --git a/bazel/external/quiche.BUILD b/bazel/external/quiche.BUILD index 149db513f83f3..59b4d894ab894 100644 --- a/bazel/external/quiche.BUILD +++ b/bazel/external/quiche.BUILD @@ -106,7 +106,10 @@ cc_library( cc_library( name = "quic_platform", srcs = ["quiche/quic/platform/api/quic_mutex.cc"] + envoy_select_quiche( - ["quiche/quic/platform/api/quic_hostname_utils.cc"], + [ + "quiche/quic/platform/api/quic_file_utils.cc", + "quiche/quic/platform/api/quic_hostname_utils.cc", + ], "@envoy", ), hdrs = [ @@ -114,7 +117,10 @@ cc_library( "quiche/quic/platform/api/quic_mutex.h", "quiche/quic/platform/api/quic_str_cat.h", ] + envoy_select_quiche( - ["quiche/quic/platform/api/quic_hostname_utils.h"], + [ + "quiche/quic/platform/api/quic_file_utils.h", + "quiche/quic/platform/api/quic_hostname_utils.h", + ], "@envoy", ), visibility = ["//visibility:public"], @@ -154,7 +160,6 @@ cc_library( "quiche/quic/platform/api/quic_uint128.h", # TODO: uncomment the following files as implementations are added. # "quiche/quic/platform/api/quic_clock.h", - # "quiche/quic/platform/api/quic_file_utils.h", # "quiche/quic/platform/api/quic_flags.h", # "quiche/quic/platform/api/quic_fuzzed_data_provider.h", # "quiche/quic/platform/api/quic_goog_cc_sender.h", diff --git a/source/extensions/quic_listeners/quiche/platform/BUILD b/source/extensions/quic_listeners/quiche/platform/BUILD index f6f8c67631a02..f9aa6755c62d3 100644 --- a/source/extensions/quic_listeners/quiche/platform/BUILD +++ b/source/extensions/quic_listeners/quiche/platform/BUILD @@ -124,6 +124,7 @@ envoy_cc_library( envoy_cc_library( name = "quic_platform_impl_lib", srcs = ["quic_cert_utils_impl.cc"] + envoy_select_quiche([ + "quic_file_utils_impl.cc", "quic_hostname_utils_impl.cc", "quic_test_output_impl.cc", ]), @@ -132,6 +133,7 @@ envoy_cc_library( "quic_mutex_impl.h", "quic_str_cat_impl.h", ] + envoy_select_quiche([ + "quic_file_utils_impl.h", "quic_hostname_utils_impl.h", "quic_string_utils_impl.h", "quic_test_output_impl.h", @@ -147,6 +149,7 @@ envoy_cc_library( visibility = ["//visibility:public"], deps = envoy_select_quiche([ ":string_utils_lib", + "//source/common/filesystem:directory_lib", "//source/common/filesystem:filesystem_lib", "//source/common/http:utility_lib", ]), diff --git a/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.cc b/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.cc new file mode 100644 index 0000000000000..00aaeef0161cb --- /dev/null +++ b/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.cc @@ -0,0 +1,55 @@ +// NOLINT(namespace-envoy) + +// This file is part of the QUICHE platform implementation, and is not to be +// consumed or referenced directly by other Envoy code. It serves purely as a +// porting layer for QUICHE. + +#include "extensions/quic_listeners/quiche/platform/quic_file_utils_impl.h" + +#include "common/filesystem/directory.h" +#include "common/filesystem/filesystem_impl.h" + +#include "absl/strings/str_cat.h" + +namespace quic { +namespace { + +void depthFirstTraverseDirectory(const std::string& dirname, std::vector& files) { + Envoy::Filesystem::Directory directory(dirname); + for (const Envoy::Filesystem::DirectoryEntry& entry : directory) { + switch (entry.type_) { + case Envoy::Filesystem::FileType::Regular: + files.push_back(absl::StrCat(dirname, "/", entry.name_)); + break; + case Envoy::Filesystem::FileType::Directory: + if (entry.name_ != "." && entry.name_ != "..") { + depthFirstTraverseDirectory(absl::StrCat(dirname, "/", entry.name_), files); + } + break; + default: + ASSERT(false, + absl::StrCat("Unknow file entry type ", entry.type_, " under directory ", dirname)); + } + } +} + +} // namespace + +// Traverses the directory |dirname| and returns all of the files it contains. +std::vector ReadFileContentsImpl(const std::string& dirname) { + std::vector files; + depthFirstTraverseDirectory(dirname, files); + return files; +} + +// Reads the contents of |filename| as a string into |contents|. +void ReadFileContentsImpl(QuicStringPiece filename, std::string* contents) { +#ifdef WIN32 + Envoy::Filesystem::InstanceImplWin32 fs; +#else + Envoy::Filesystem::InstanceImplPosix fs; +#endif + *contents = fs.fileReadToEnd(std::string(filename.data(), filename.size())); +} + +} // namespace quic diff --git a/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.h new file mode 100644 index 0000000000000..ceef1dabbab2a --- /dev/null +++ b/source/extensions/quic_listeners/quiche/platform/quic_file_utils_impl.h @@ -0,0 +1,28 @@ +#pragma once + +// NOLINT(namespace-envoy) + +// This file is part of the QUICHE platform implementation, and is not to be +// consumed or referenced directly by other Envoy code. It serves purely as a +// porting layer for QUICHE. + +#include + +#include "quiche/quic/platform/api/quic_string_piece.h" + +namespace quic { + +/** + * Traverses the directory |dirname| and returns all of the files it contains. + * @param dirname full path without trailing '/'. + */ +std::vector ReadFileContentsImpl(const std::string& dirname); + +/** + * Reads the contents of |filename| as a string into |contents|. + * @param filename the full path to the file. + * @param contents output location of the file content. + */ +void ReadFileContentsImpl(QuicStringPiece filename, std::string* contents); + +} // namespace quic diff --git a/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc b/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc index 8f0b4ebf9e880..e22003edfeb52 100644 --- a/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc +++ b/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc @@ -4,9 +4,13 @@ // consumed or referenced directly by other Envoy code. It serves purely as a // porting layer for QUICHE. +#include +#include + #include "test/extensions/transport_sockets/tls/ssl_test_utility.h" #include "test/test_common/environment.h" #include "test/test_common/logging.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -20,6 +24,7 @@ #include "quiche/quic/platform/api/quic_estimate_memory_usage.h" #include "quiche/quic/platform/api/quic_expect_bug.h" #include "quiche/quic/platform/api/quic_exported_stats.h" +#include "quiche/quic/platform/api/quic_file_utils.h" #include "quiche/quic/platform/api/quic_hostname_utils.h" #include "quiche/quic/platform/api/quic_logging.h" #include "quiche/quic/platform/api/quic_map_util.h" @@ -478,5 +483,61 @@ TEST(QuicPlatformTest, QuicTestOutput) { QuicRecordTestOutput("quic_test_output.3", "output 3 content\n")); } +class FileUtilsTest : public testing::Test { +public: + FileUtilsTest() : dir_path_(Envoy::TestEnvironment::temporaryPath("envoy_test")) { + files_to_remove_.push(dir_path_); + } + +protected: + void SetUp() override { Envoy::TestUtility::createDirectory(dir_path_); } + + void TearDown() override { + while (!files_to_remove_.empty()) { + const std::string& f = files_to_remove_.top(); + Envoy::TestEnvironment::removePath(f); + files_to_remove_.pop(); + } + } + + void addSubDirs(std::list sub_dirs) { + for (const std::string& dir_name : sub_dirs) { + const std::string full_path = dir_path_ + "/" + dir_name; + Envoy::TestUtility::createDirectory(full_path); + files_to_remove_.push(full_path); + } + } + + void addFiles(std::list files) { + for (const std::string& file_name : files) { + const std::string full_path = dir_path_ + "/" + file_name; + { const std::ofstream file(full_path); } + files_to_remove_.push(full_path); + } + } + + const std::string dir_path_; + std::stack files_to_remove_; +}; + +TEST_F(FileUtilsTest, ReadDirContents) { + addSubDirs({"sub_dir1", "sub_dir2", "sub_dir1/sub_dir1_1"}); + addFiles({"file", "sub_dir1/sub_file1", "sub_dir1/sub_dir1_1/sub_file1_1", "sub_dir2/sub_file2"}); + + EXPECT_THAT(ReadFileContents(dir_path_), + testing::UnorderedElementsAre(dir_path_ + "/file", dir_path_ + "/sub_dir1/sub_file1", + dir_path_ + "/sub_dir1/sub_dir1_1/sub_file1_1", + dir_path_ + "/sub_dir2/sub_file2")); +} + +TEST_F(FileUtilsTest, ReadFileContents) { + const std::string data = "test string\ntest"; + const std::string file_path = + Envoy::TestEnvironment::writeStringToFileForTest("test_envoy", data); + std::string output; + ReadFileContents(file_path, &output); + EXPECT_EQ(data, output); +} + } // namespace } // namespace quic