1 // Copyright 2015 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "webservd/config.h"
16
17 #include <base/files/file_util.h>
18 #include <base/json/json_reader.h>
19 #include <base/logging.h>
20 #include <base/values.h>
21 #include <brillo/errors/error_codes.h>
22
23 #include "webservd/error_codes.h"
24
25 namespace webservd {
26
27 #ifdef __ANDROID__
28 const char kDefaultLogDirectory[] = "/data/misc/webservd/logs";
29 #else
30 const char kDefaultLogDirectory[] = "/var/log/webservd";
31 #endif
32
33 namespace {
34
35 const char kLogDirectoryKey[] = "log_directory";
36 const char kProtocolHandlersKey[] = "protocol_handlers";
37 const char kNameKey[] = "name";
38 const char kPortKey[] = "port";
39 const char kUseTLSKey[] = "use_tls";
40 const char kInterfaceKey[] = "interface";
41
42 // Default configuration for the web server.
43 const char kDefaultConfig[] = R"({
44 "protocol_handlers": [
45 {
46 "name": "http",
47 "port": 80,
48 "use_tls": false
49 },
50 {
51 "name": "https",
52 "port": 443,
53 "use_tls": true
54 }
55 ]
56 })";
57
LoadHandlerConfig(const base::DictionaryValue * handler_value,Config::ProtocolHandler * handler_config,brillo::ErrorPtr * error)58 bool LoadHandlerConfig(const base::DictionaryValue* handler_value,
59 Config::ProtocolHandler* handler_config,
60 brillo::ErrorPtr* error) {
61 int port = 0;
62 if (!handler_value->GetInteger(kPortKey, &port)) {
63 brillo::Error::AddTo(error,
64 FROM_HERE,
65 webservd::errors::kDomain,
66 webservd::errors::kInvalidConfig,
67 "Port is missing");
68 return false;
69 }
70 if (port < 1 || port > 0xFFFF) {
71 brillo::Error::AddToPrintf(error,
72 FROM_HERE,
73 webservd::errors::kDomain,
74 webservd::errors::kInvalidConfig,
75 "Invalid port value: %d", port);
76 return false;
77 }
78 handler_config->port = port;
79
80 // Allow "use_tls" to be omitted, so not returning an error here.
81 bool use_tls = false;
82 if (handler_value->GetBoolean(kUseTLSKey, &use_tls))
83 handler_config->use_tls = use_tls;
84
85 // "interface" is also optional.
86 std::string interface_name;
87 if (handler_value->GetString(kInterfaceKey, &interface_name))
88 handler_config->interface_name = interface_name;
89
90 return true;
91 }
92
93 } // anonymous namespace
94
~ProtocolHandler()95 Config::ProtocolHandler::~ProtocolHandler() {
96 if (socket_fd != -1)
97 close(socket_fd);
98 }
99
LoadDefaultConfig(Config * config)100 void LoadDefaultConfig(Config* config) {
101 LOG(INFO) << "Loading default server configuration...";
102 CHECK(LoadConfigFromString(kDefaultConfig, config, nullptr));
103 }
104
LoadConfigFromFile(const base::FilePath & json_file_path,Config * config)105 bool LoadConfigFromFile(const base::FilePath& json_file_path, Config* config) {
106 std::string config_json;
107 LOG(INFO) << "Loading server configuration from " << json_file_path.value();
108 return base::ReadFileToString(json_file_path, &config_json) &&
109 LoadConfigFromString(config_json, config, nullptr);
110 }
111
LoadConfigFromString(const std::string & config_json,Config * config,brillo::ErrorPtr * error)112 bool LoadConfigFromString(const std::string& config_json,
113 Config* config,
114 brillo::ErrorPtr* error) {
115 std::string error_msg;
116 std::unique_ptr<const base::Value> value{
117 base::JSONReader::ReadAndReturnError(
118 config_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error_msg)
119 .release()};
120
121 if (!value) {
122 brillo::Error::AddToPrintf(error, FROM_HERE,
123 brillo::errors::json::kDomain,
124 brillo::errors::json::kParseError,
125 "Error parsing server configuration: %s",
126 error_msg.c_str());
127 return false;
128 }
129
130 const base::DictionaryValue* dict_value = nullptr; // Owned by |value|
131 if (!value->GetAsDictionary(&dict_value)) {
132 brillo::Error::AddTo(error,
133 FROM_HERE,
134 brillo::errors::json::kDomain,
135 brillo::errors::json::kObjectExpected,
136 "JSON object is expected.");
137 return false;
138 }
139
140 // "log_directory" is optional, so ignoring the return value here.
141 dict_value->GetString(kLogDirectoryKey, &config->log_directory);
142
143 const base::ListValue* protocol_handlers = nullptr; // Owned by |value|
144 if (dict_value->GetList(kProtocolHandlersKey, &protocol_handlers)) {
145 for (base::Value* handler_value : *protocol_handlers) {
146 const base::DictionaryValue* handler_dict = nullptr; // Owned by |value|
147 if (!handler_value->GetAsDictionary(&handler_dict)) {
148 brillo::Error::AddTo(
149 error,
150 FROM_HERE,
151 brillo::errors::json::kDomain,
152 brillo::errors::json::kObjectExpected,
153 "Protocol handler definition must be a JSON object");
154 return false;
155 }
156
157 std::string name;
158 if (!handler_dict->GetString(kNameKey, &name)) {
159 brillo::Error::AddTo(
160 error,
161 FROM_HERE,
162 errors::kDomain,
163 errors::kInvalidConfig,
164 "Protocol handler definition must include its name");
165 return false;
166 }
167
168 Config::ProtocolHandler handler_config;
169 handler_config.name = name;
170 if (!LoadHandlerConfig(handler_dict, &handler_config, error)) {
171 brillo::Error::AddToPrintf(
172 error,
173 FROM_HERE,
174 errors::kDomain,
175 errors::kInvalidConfig,
176 "Unable to parse config for protocol handler '%s'",
177 name.c_str());
178 return false;
179 }
180 config->protocol_handlers.push_back(std::move(handler_config));
181 }
182 }
183 return true;
184 }
185
186 } // namespace webservd
187