1
#include "source/common/config/datasource.h"
2

            
3
#include "envoy/config/core/v3/base.pb.h"
4

            
5
#include "source/common/config/utility.h"
6

            
7
#include "fmt/format.h"
8

            
9
namespace Envoy {
10
namespace Config {
11
namespace DataSource {
12

            
13
/**
14
 * Read contents of the file.
15
 * @param path file path.
16
 * @param api reference to the Api.
17
 * @param allow_empty return an empty string if the file is empty.
18
 * @param max_size max size limit of file to read, default 0 means no limit, and if the file data
19
 * would exceed the limit, it will return an error status.
20
 * @return std::string with file contents. or an error status if the file does not exist or
21
 * cannot be read.
22
 */
23
absl::StatusOr<std::string> readFile(const std::string& path, Api::Api& api, bool allow_empty,
24
18096
                                     uint64_t max_size) {
25
18096
  auto& file_system = api.fileSystem();
26

            
27
18096
  if (max_size > 0) {
28
58
    if (!file_system.fileExists(path)) {
29
30
      return absl::InvalidArgumentError(fmt::format("file {} does not exist", path));
30
30
    }
31
28
    const ssize_t size = file_system.fileSize(path);
32
28
    if (size < 0) {
33
1
      return absl::InvalidArgumentError(absl::StrCat("cannot determine size of file ", path));
34
1
    }
35
27
    if (static_cast<uint64_t>(size) > max_size) {
36
2
      return absl::InvalidArgumentError(
37
2
          fmt::format("file {} size is {} bytes; maximum is {}", path, size, max_size));
38
2
    }
39
27
  }
40

            
41
18063
  auto file_content_or_error = file_system.fileReadToEnd(path);
42
18063
  RETURN_IF_NOT_OK_REF(file_content_or_error.status());
43

            
44
18049
  if (!allow_empty && file_content_or_error.value().empty()) {
45
2
    return absl::InvalidArgumentError(fmt::format("file {} is empty", path));
46
2
  }
47

            
48
18047
  return file_content_or_error.value();
49
18049
}
50

            
51
absl::StatusOr<std::string> read(const envoy::config::core::v3::DataSource& source,
52
45324
                                 bool allow_empty, Api::Api& api, uint64_t max_size) {
53
45324
  std::string data;
54
45324
  switch (source.specifier_case()) {
55
18086
  case envoy::config::core::v3::DataSource::SpecifierCase::kFilename:
56
18086
    return readFile(source.filename(), api, allow_empty, max_size);
57
772
  case envoy::config::core::v3::DataSource::SpecifierCase::kInlineBytes:
58
772
    data = source.inline_bytes();
59
772
    break;
60
4818
  case envoy::config::core::v3::DataSource::SpecifierCase::kInlineString:
61
4818
    data = source.inline_string();
62
4818
    break;
63
69
  case envoy::config::core::v3::DataSource::SpecifierCase::kEnvironmentVariable: {
64
69
    const char* environment_variable = std::getenv(source.environment_variable().c_str());
65
69
    if (environment_variable == nullptr) {
66
8
      return absl::InvalidArgumentError(
67
8
          fmt::format("Environment variable doesn't exist: {}", source.environment_variable()));
68
8
    }
69
61
    data = environment_variable;
70
61
    break;
71
69
  }
72
21579
  default:
73
21579
    if (!allow_empty) {
74
4
      return absl::InvalidArgumentError(fmt::format("Unexpected DataSource::specifier_case(): {}",
75
4
                                                    static_cast<int>(source.specifier_case())));
76
4
    }
77
45324
  }
78
27226
  if (!allow_empty && data.empty()) {
79
6
    return absl::InvalidArgumentError("DataSource cannot be empty");
80
6
  }
81
27220
  return data;
82
27226
}
83

            
84
38730
absl::optional<std::string> getPath(const envoy::config::core::v3::DataSource& source) {
85
38730
  return source.specifier_case() == envoy::config::core::v3::DataSource::SpecifierCase::kFilename
86
38730
             ? absl::make_optional(source.filename())
87
38730
             : absl::nullopt;
88
38730
}
89

            
90
606
bool usesFileWatching(const ProtoDataSource& source, const ProviderOptions& options) {
91
606
  return ((source.has_watched_directory() || options.modify_watch) &&
92
606
          source.specifier_case() == envoy::config::core::v3::DataSource::kFilename);
93
606
}
94

            
95
} // namespace DataSource
96
} // namespace Config
97
} // namespace Envoy