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