blob: 62e512c998c3ac90d8b3322a4ba6248be00c6342 [file] [log] [blame]
// Copyright 2015 The Android Open Source Project
//
// 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 "webservd/config.h"
#include <base/files/file_util.h>
#include <base/json/json_reader.h>
#include <base/logging.h>
#include <base/values.h>
#include <brillo/errors/error_codes.h>
#include "webservd/error_codes.h"
namespace webservd {
#ifdef __ANDROID__
const char kDefaultLogDirectory[] = "/data/misc/webservd/logs";
#else
const char kDefaultLogDirectory[] = "/var/log/webservd";
#endif
namespace {
const char kLogDirectoryKey[] = "log_directory";
const char kProtocolHandlersKey[] = "protocol_handlers";
const char kNameKey[] = "name";
const char kPortKey[] = "port";
const char kUseTLSKey[] = "use_tls";
const char kInterfaceKey[] = "interface";
// Default configuration for the web server.
const char kDefaultConfig[] = R"({
"protocol_handlers": [
{
"name": "http",
"port": 80,
"use_tls": false
},
{
"name": "https",
"port": 443,
"use_tls": true
}
]
})";
bool LoadHandlerConfig(const base::DictionaryValue* handler_value,
Config::ProtocolHandler* handler_config,
brillo::ErrorPtr* error) {
int port = 0;
if (!handler_value->GetInteger(kPortKey, &port)) {
brillo::Error::AddTo(error,
FROM_HERE,
webservd::errors::kDomain,
webservd::errors::kInvalidConfig,
"Port is missing");
return false;
}
if (port < 1 || port > 0xFFFF) {
brillo::Error::AddToPrintf(error,
FROM_HERE,
webservd::errors::kDomain,
webservd::errors::kInvalidConfig,
"Invalid port value: %d", port);
return false;
}
handler_config->port = port;
// Allow "use_tls" to be omitted, so not returning an error here.
bool use_tls = false;
if (handler_value->GetBoolean(kUseTLSKey, &use_tls))
handler_config->use_tls = use_tls;
// "interface" is also optional.
std::string interface_name;
if (handler_value->GetString(kInterfaceKey, &interface_name))
handler_config->interface_name = interface_name;
return true;
}
} // anonymous namespace
Config::ProtocolHandler::~ProtocolHandler() {
if (socket_fd != -1)
close(socket_fd);
}
void LoadDefaultConfig(Config* config) {
LOG(INFO) << "Loading default server configuration...";
CHECK(LoadConfigFromString(kDefaultConfig, config, nullptr));
}
bool LoadConfigFromFile(const base::FilePath& json_file_path, Config* config) {
std::string config_json;
LOG(INFO) << "Loading server configuration from " << json_file_path.value();
return base::ReadFileToString(json_file_path, &config_json) &&
LoadConfigFromString(config_json, config, nullptr);
}
bool LoadConfigFromString(const std::string& config_json,
Config* config,
brillo::ErrorPtr* error) {
std::string error_msg;
auto value = base::JSONReader::ReadAndReturnError(
config_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error_msg);
if (!value) {
brillo::Error::AddToPrintf(error, FROM_HERE,
brillo::errors::json::kDomain,
brillo::errors::json::kParseError,
"Error parsing server configuration: %s",
error_msg.c_str());
return false;
}
auto dict_value = base::DictionaryValue::From(std::move(value));
if (!dict_value) {
brillo::Error::AddTo(error,
FROM_HERE,
brillo::errors::json::kDomain,
brillo::errors::json::kObjectExpected,
"JSON object is expected.");
return false;
}
// "log_directory" is optional, so ignoring the return value here.
dict_value->GetString(kLogDirectoryKey, &config->log_directory);
const base::ListValue* protocol_handlers = nullptr; // Owned by |dict_value|
if (dict_value->GetList(kProtocolHandlersKey, &protocol_handlers)) {
for (base::Value* handler_value : *protocol_handlers) {
const base::DictionaryValue* handler_dict = nullptr; // Owned by
// |dict_value|
if (!handler_value->GetAsDictionary(&handler_dict)) {
brillo::Error::AddTo(
error,
FROM_HERE,
brillo::errors::json::kDomain,
brillo::errors::json::kObjectExpected,
"Protocol handler definition must be a JSON object");
return false;
}
std::string name;
if (!handler_dict->GetString(kNameKey, &name)) {
brillo::Error::AddTo(
error,
FROM_HERE,
errors::kDomain,
errors::kInvalidConfig,
"Protocol handler definition must include its name");
return false;
}
Config::ProtocolHandler handler_config;
handler_config.name = name;
if (!LoadHandlerConfig(handler_dict, &handler_config, error)) {
brillo::Error::AddToPrintf(
error,
FROM_HERE,
errors::kDomain,
errors::kInvalidConfig,
"Unable to parse config for protocol handler '%s'",
name.c_str());
return false;
}
config->protocol_handlers.push_back(std::move(handler_config));
}
}
return true;
}
} // namespace webservd