mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-30 03:34:26 +03:00
First release of open-appsec source code
This commit is contained in:
4
components/messaging_downloader/CMakeLists.txt
Executable file
4
components/messaging_downloader/CMakeLists.txt
Executable file
@@ -0,0 +1,4 @@
|
||||
add_library(messaging_downloader_server messaging_downloader_server.cc)
|
||||
add_library(messaging_downloader_client messaging_downloader_client.cc)
|
||||
|
||||
add_subdirectory(messaging_downloader_ut)
|
230
components/messaging_downloader/messaging_downloader_client.cc
Executable file
230
components/messaging_downloader/messaging_downloader_client.cc
Executable file
@@ -0,0 +1,230 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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 <unordered_map>
|
||||
|
||||
#include "messaging_downloader_client.h"
|
||||
#include "i_messaging.h"
|
||||
#include "config.h"
|
||||
#include "rest.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_COMMUNICATION);
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MessagingDownloaderClientRequest : public ClientRest
|
||||
{
|
||||
public:
|
||||
MessagingDownloaderClientRequest()
|
||||
{
|
||||
file_name = "";
|
||||
url = "";
|
||||
port = 80;
|
||||
response_port = 0;
|
||||
status = false;
|
||||
}
|
||||
|
||||
MessagingDownloaderClientRequest(
|
||||
const string &_file_name,
|
||||
const string &_url,
|
||||
const unsigned int _port,
|
||||
const unsigned int _response_port
|
||||
) :
|
||||
file_name(_file_name),
|
||||
url(_url),
|
||||
port(_port),
|
||||
response_port(_response_port),
|
||||
status(false)
|
||||
{}
|
||||
|
||||
bool getStatus() const { return status.get(); }
|
||||
const string & getUuid() const { return uuid.get(); }
|
||||
|
||||
C2S_PARAM(string, file_name);
|
||||
C2S_PARAM(string, url);
|
||||
C2S_PARAM(unsigned int, port);
|
||||
C2S_PARAM(unsigned int, response_port);
|
||||
|
||||
S2C_PARAM(string, uuid);
|
||||
S2C_PARAM(bool, status);
|
||||
};
|
||||
|
||||
class DownloaderCbHandler
|
||||
{
|
||||
public:
|
||||
void
|
||||
addCallback(const string &uuid, I_MessagingDownloader::OnCompleteCB &cb)
|
||||
{
|
||||
DownloaderCbHandler::uuid_to_cb[uuid] = cb;
|
||||
}
|
||||
|
||||
static void
|
||||
handleDownloadCB(const string &uuid, Maybe<string> &downloaded_file)
|
||||
{
|
||||
dbgTrace(D_COMMUNICATION) << "Handling downloading complete callback. UUID: " << uuid;
|
||||
if(DownloaderCbHandler::uuid_to_cb.find(uuid) == DownloaderCbHandler::uuid_to_cb.end()) {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to execute download completion callback.";
|
||||
return;
|
||||
}
|
||||
if (DownloaderCbHandler::uuid_to_cb.at(uuid) != nullptr) {
|
||||
DownloaderCbHandler::uuid_to_cb.at(uuid)(downloaded_file);
|
||||
DownloaderCbHandler::uuid_to_cb.erase(uuid);
|
||||
} else {
|
||||
string curr_status;
|
||||
if (downloaded_file.ok()) {
|
||||
curr_status = ". File path: " + downloaded_file.unpack();
|
||||
} else {
|
||||
curr_status = ". Error: " + downloaded_file.getErr();
|
||||
}
|
||||
dbgWarning(D_COMMUNICATION)
|
||||
<< "Illegal download completion callback for downloading process with UUID: "
|
||||
<< uuid
|
||||
<< curr_status;
|
||||
}
|
||||
dbgTrace(D_COMMUNICATION) << "Successfully handled the downloading complete callback. UUID: " << uuid;
|
||||
}
|
||||
|
||||
static unordered_map<string, I_MessagingDownloader::OnCompleteCB> uuid_to_cb;
|
||||
};
|
||||
|
||||
unordered_map<string, I_MessagingDownloader::OnCompleteCB> DownloaderCbHandler::uuid_to_cb;
|
||||
|
||||
class MessagingDownloaderClientRes : public ServerRest
|
||||
{
|
||||
public:
|
||||
void
|
||||
doCall() override
|
||||
{
|
||||
dbgTrace(D_COMMUNICATION) << "Received response from the downloading server.";
|
||||
if (status.get() && filepath.isActive()) {
|
||||
Maybe<string> response(filepath.get());
|
||||
DownloaderCbHandler::handleDownloadCB(uuid.get(), response);
|
||||
} else {
|
||||
if (!error.isActive()) error = "unknown error";
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to download. Error: " << error.get();
|
||||
Maybe<string> response = genError(error.get());
|
||||
DownloaderCbHandler::handleDownloadCB(uuid.get(), response);
|
||||
}
|
||||
}
|
||||
|
||||
C2S_PARAM(string, uuid);
|
||||
C2S_PARAM(bool, status);
|
||||
C2S_OPTIONAL_PARAM(string, filepath);
|
||||
C2S_OPTIONAL_PARAM(string, error);
|
||||
};
|
||||
|
||||
class MessagingDownloaderClient::Impl : Singleton::Provide<I_MessagingDownloader>::From<MessagingDownloaderClient>
|
||||
{
|
||||
public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
i_msg = Singleton::Consume<I_Messaging>::by<MessagingDownloaderClient>();
|
||||
Singleton::Consume<I_RestApi>::by<MessagingDownloaderClient>()->addRestCall<MessagingDownloaderClientRes>(
|
||||
RestAction::SHOW,
|
||||
"download-status"
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
fini()
|
||||
{
|
||||
i_msg = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
downloadFile(
|
||||
const string &file_name,
|
||||
const string &url,
|
||||
I_MessagingDownloader::OnCompleteCB cb = nullptr,
|
||||
const unsigned int port = 0
|
||||
) override
|
||||
{
|
||||
dbgTrace(D_COMMUNICATION)
|
||||
<< "Processing new download request."
|
||||
<< "File name: "
|
||||
<< file_name
|
||||
<< "URL: "
|
||||
<< url;
|
||||
|
||||
auto response_port = Singleton::Consume<I_Environment>::by<MessagingDownloaderClient>()->get<int>(
|
||||
"Listening Port"
|
||||
);
|
||||
|
||||
if (!response_port.ok()) {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to get the service listening port.";
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<int> download_ports = {
|
||||
getConfigurationWithDefault(8164, "Downloader", "Downloader Primary Port"),
|
||||
getConfigurationWithDefault(8167, "Downloader", "Downloader Secondary Port")
|
||||
};
|
||||
|
||||
MessagingDownloaderClientRequest download_obj(
|
||||
file_name,
|
||||
url,
|
||||
port,
|
||||
response_port.unpack()
|
||||
);
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
conn_flags.setFlag(MessageConnConfig::EXPECT_REPLY);
|
||||
if (i_msg != nullptr) {
|
||||
dbgTrace(D_COMMUNICATION) << "Sending request to the downloading service.";
|
||||
bool res = false;
|
||||
for (int port: download_ports) {
|
||||
dbgTrace(D_COMMUNICATION) << "Trying to request downloading with downloading service port " << port;
|
||||
res = i_msg->sendObject(
|
||||
download_obj,
|
||||
I_Messaging::Method::POST,
|
||||
"127.0.0.1",
|
||||
port,
|
||||
conn_flags,
|
||||
"/add-download-file"
|
||||
);
|
||||
if (res) break;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
dbgInfo(D_COMMUNICATION) << "Failed to request for file downloading";
|
||||
return false;
|
||||
}
|
||||
dbgTrace(D_COMMUNICATION) << "Successfully requested for downloading.";
|
||||
cb_handler.addCallback(download_obj.getUuid(), cb);
|
||||
} else {
|
||||
dbgDebug(D_COMMUNICATION) << "Failed to request downloading. Illegal messaging infrastructure.";
|
||||
}
|
||||
return download_obj.getStatus();
|
||||
}
|
||||
|
||||
private:
|
||||
I_Messaging *i_msg;
|
||||
DownloaderCbHandler cb_handler;
|
||||
};
|
||||
|
||||
MessagingDownloaderClient::MessagingDownloaderClient()
|
||||
:
|
||||
Component("MessagingDownloaderClient"),
|
||||
pimpl(make_unique<Impl>())
|
||||
{}
|
||||
MessagingDownloaderClient::~MessagingDownloaderClient() {}
|
||||
|
||||
void MessagingDownloaderClient::init() { pimpl->init(); }
|
||||
void MessagingDownloaderClient::fini() { pimpl->fini(); }
|
||||
|
||||
void
|
||||
MessagingDownloaderClient::preload()
|
||||
{
|
||||
registerExpectedConfiguration<int>("Downloader", "Downloader Primary Port");
|
||||
registerExpectedConfiguration<int>("Downloader", "Downloader Secondary Port");
|
||||
};
|
375
components/messaging_downloader/messaging_downloader_server.cc
Executable file
375
components/messaging_downloader/messaging_downloader_server.cc
Executable file
@@ -0,0 +1,375 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (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 "messaging_downloader_server.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
|
||||
#include "i_messaging.h"
|
||||
#include "rest.h"
|
||||
#include "config.h"
|
||||
#include "url_parser.h"
|
||||
#include "agent_core_utilities.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_COMMUNICATION);
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MessagingDownloaderResponser : public ClientRest
|
||||
{
|
||||
public:
|
||||
MessagingDownloaderResponser()=delete;
|
||||
|
||||
MessagingDownloaderResponser(string &_uuid, const Maybe<string> &_filepath)
|
||||
:
|
||||
uuid(_uuid),
|
||||
status(_filepath.ok())
|
||||
{
|
||||
if (_filepath.ok()) {
|
||||
filepath = _filepath.unpack();
|
||||
} else {
|
||||
error = _filepath.getErr();
|
||||
}
|
||||
}
|
||||
C2S_PARAM(string, uuid);
|
||||
C2S_PARAM(bool, status);
|
||||
C2S_OPTIONAL_PARAM(string, filepath)
|
||||
C2S_OPTIONAL_PARAM(string, error)
|
||||
};
|
||||
|
||||
class MessagingDownloaderReceiver : public ServerRest
|
||||
{
|
||||
public:
|
||||
void
|
||||
doCall() override
|
||||
{
|
||||
dbgTrace(D_COMMUNICATION) << "Received new downloading request.";
|
||||
|
||||
stringstream uuid_ss;
|
||||
uuid_ss << boost::uuids::random_generator()();
|
||||
uuid = uuid_ss.str();
|
||||
|
||||
if (!port.isActive()) {
|
||||
dbgTrace(D_COMMUNICATION) << "Request does not contain explicit port.";
|
||||
port = 0;
|
||||
}
|
||||
|
||||
dbgInfo(D_COMMUNICATION)
|
||||
<< "Downloading a file and using the next parameters: "
|
||||
<< "file_name: "
|
||||
<< file_name.get()
|
||||
<< ", url: "
|
||||
<< url.get()
|
||||
<< ", uuid: "
|
||||
<< uuid.get()
|
||||
<< ", port: "
|
||||
<< port.get()
|
||||
<< ", notification port: "
|
||||
<< response_port.get();
|
||||
|
||||
unsigned int response_port_cap = response_port.get();
|
||||
string uuid_capture = uuid.get();
|
||||
status = Singleton::Consume<I_MessagingDownloader>::from<MessagingDownloaderServer>()->downloadFile(
|
||||
file_name.get(),
|
||||
url.get(),
|
||||
[uuid_capture, response_port_cap](const Maybe<string> &downloaded_file) mutable
|
||||
{
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
MessagingDownloaderResponser res(uuid_capture, downloaded_file);
|
||||
dbgTrace(D_COMMUNICATION) << "Sending the download status to the client.";
|
||||
bool res_status = Singleton::Consume<I_Messaging>::by<MessagingDownloaderServer>()->sendNoReplyObject(
|
||||
res,
|
||||
I_Messaging::Method::POST,
|
||||
"127.0.0.1",
|
||||
response_port_cap,
|
||||
conn_flags,
|
||||
"/show-download-status"
|
||||
);
|
||||
if (!res_status) {
|
||||
dbgInfo(D_COMMUNICATION) << "Failed to send the download status.";
|
||||
} else {
|
||||
dbgDebug(D_COMMUNICATION)
|
||||
<< "Successfully sent the download status. Notification port: "
|
||||
<< response_port_cap
|
||||
<< ", Status: "
|
||||
<< downloaded_file.ok();
|
||||
}
|
||||
},
|
||||
port.get()
|
||||
);
|
||||
}
|
||||
|
||||
C2S_PARAM(string, file_name);
|
||||
C2S_PARAM(string, url);
|
||||
C2S_PARAM(int, response_port);
|
||||
C2S_PARAM(int, port);
|
||||
S2C_PARAM(string, uuid);
|
||||
S2C_PARAM(bool, status);
|
||||
};
|
||||
|
||||
class DownloadingInstance
|
||||
{
|
||||
public:
|
||||
DownloadingInstance()=default;
|
||||
|
||||
DownloadingInstance(
|
||||
const string &_file_name,
|
||||
const string &_url,
|
||||
const unsigned int _port
|
||||
) :
|
||||
file_name(_file_name),
|
||||
url(_url),
|
||||
port(_port),
|
||||
url_parser(_url)
|
||||
{
|
||||
parseURL();
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
genJson() const
|
||||
{
|
||||
return string("");
|
||||
}
|
||||
|
||||
bool
|
||||
loadJson(const string &_body)
|
||||
{
|
||||
body = vector<char>(_body.begin(), _body.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
const vector<char> &
|
||||
getResponse() const
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const DownloadingInstance &other) const
|
||||
{
|
||||
return file_name == other.file_name &&
|
||||
host == other.host &&
|
||||
url == other.url &&
|
||||
port == other.port &&
|
||||
is_secure == other.is_secure &&
|
||||
origin_is_fog == other.origin_is_fog;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const DownloadingInstance &other) const
|
||||
{
|
||||
return file_name < other.file_name ||
|
||||
host < other.host ||
|
||||
url < other.url ||
|
||||
port < other.port ||
|
||||
is_secure < other.is_secure ||
|
||||
origin_is_fog < other.origin_is_fog;
|
||||
}
|
||||
|
||||
const string & getFileName() const { return file_name; }
|
||||
const string & getHost() const { return host; }
|
||||
const string & getUrl() const { return url; }
|
||||
unsigned int getPort() const { return port; }
|
||||
bool getIsSecure() const { return is_secure; }
|
||||
bool getIsFogOrigin() const { return origin_is_fog; }
|
||||
|
||||
private:
|
||||
void
|
||||
parseURL()
|
||||
{
|
||||
dbgTrace(D_COMMUNICATION) << "Parsing the URL to extract the relevant info. URL: " << url;
|
||||
origin_is_fog = false;
|
||||
auto maybe_host = url_parser.getBaseURL();
|
||||
if (!maybe_host.ok()) {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to parse the URL";
|
||||
return;
|
||||
}
|
||||
host = maybe_host.unpack();
|
||||
is_secure = url_parser.isOverSSL();
|
||||
if (port == 0 && url_parser.getPort() != "") {
|
||||
try {
|
||||
port = stoi(url_parser.getPort());
|
||||
} catch (exception &e) {
|
||||
port = 443;
|
||||
dbgInfo(D_COMMUNICATION)
|
||||
<< "Failed to parse the port for the downloading request. Error "
|
||||
<< e.what()
|
||||
<< ". Using the default port "
|
||||
<< port;
|
||||
}
|
||||
} else {
|
||||
dbgTrace(D_COMMUNICATION) << "Using explicitly defined port. Port: " << port;
|
||||
}
|
||||
|
||||
I_AgentDetails *agent_details = Singleton::Consume<I_AgentDetails>::by<MessagingDownloaderServer>();
|
||||
if (agent_details->getFogDomain().ok()) {
|
||||
string fog_domain = agent_details->getFogDomain().unpack();
|
||||
if (host.find(fog_domain) != string::npos) {
|
||||
origin_is_fog = true;
|
||||
}
|
||||
} else {
|
||||
dbgTrace(D_COMMUNICATION) << "Failed to receive fog domain.";
|
||||
}
|
||||
}
|
||||
|
||||
string file_name = "";
|
||||
string url = "";
|
||||
unsigned int port = 0;
|
||||
URLParser url_parser;
|
||||
vector<char> body = {};
|
||||
string host = "";
|
||||
bool is_secure = true;
|
||||
bool origin_is_fog = true;
|
||||
};
|
||||
|
||||
class MessagingDownloaderServer::Impl : Singleton::Provide<I_MessagingDownloader>::From<MessagingDownloaderServer>
|
||||
{
|
||||
public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
i_msg = Singleton::Consume<I_Messaging>::by<MessagingDownloaderServer>();
|
||||
i_mainloop = Singleton::Consume<I_MainLoop>::by<MessagingDownloaderServer>();
|
||||
auto rest = Singleton::Consume<I_RestApi>::by<MessagingDownloaderServer>();
|
||||
rest->addRestCall<MessagingDownloaderReceiver>(RestAction::ADD, "download-file");
|
||||
string default_downloading_dir = "/tmp/cp_nano_downloader/";
|
||||
download_dir = getConfigurationWithDefault(
|
||||
default_downloading_dir,
|
||||
"Downloader",
|
||||
"Downloading Directory"
|
||||
);
|
||||
NGEN::Filesystem::makeDirRecursive(download_dir);
|
||||
}
|
||||
|
||||
void
|
||||
fini()
|
||||
{
|
||||
i_msg = nullptr;
|
||||
i_mainloop = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
downloadFile(
|
||||
const string &file_name,
|
||||
const string &url,
|
||||
OnCompleteCB on_complete_func = nullptr,
|
||||
const unsigned int port = 443
|
||||
) override
|
||||
{
|
||||
dbgTrace(D_COMMUNICATION) << "Handling new download request. URL: " << url << ". File name: " << file_name;
|
||||
DownloadingInstance req(file_name, url, port);
|
||||
if (downloading_queue.find(req) != downloading_queue.end()) {
|
||||
dbgInfo(D_COMMUNICATION) << "Failed to download the file. Similar download request already exists.";
|
||||
return false;
|
||||
}
|
||||
if (!isValidPath(file_name)) {
|
||||
dbgInfo(D_COMMUNICATION) << "Failed to validate the download path. Path: " << download_dir + file_name;
|
||||
return false;
|
||||
}
|
||||
downloading_queue.insert(req);
|
||||
|
||||
i_mainloop->addOneTimeRoutine(
|
||||
I_MainLoop::RoutineType::RealTime,
|
||||
[this, req, on_complete_func]() mutable
|
||||
{
|
||||
Flags<MessageConnConfig> conn_flags;
|
||||
if (req.getIsSecure()) conn_flags.setFlag(MessageConnConfig::SECURE_CONN);
|
||||
if (!req.getIsFogOrigin()) conn_flags.setFlag(MessageConnConfig::EXTERNAL);
|
||||
auto on_exit = make_scope_exit([this, &req]() { downloading_queue.erase(req); } );
|
||||
bool response = i_msg->sendObject(
|
||||
req,
|
||||
I_Messaging::Method::GET,
|
||||
req.getHost(),
|
||||
req.getPort(),
|
||||
conn_flags,
|
||||
req.getUrl()
|
||||
);
|
||||
if (response) {
|
||||
dbgTrace(D_COMMUNICATION) << "Successfully received a response from the downloading file host.";
|
||||
std::ofstream downloaded_file;
|
||||
downloaded_file.open(download_dir + req.getFileName());
|
||||
if (!downloaded_file.is_open()) {
|
||||
dbgInfo(D_COMMUNICATION)
|
||||
<< "Failed to download file. Error: Failed to open the file "
|
||||
<< req.getFileName();
|
||||
Maybe<string> err = genError("Failed to open the file");
|
||||
on_complete_func(err);
|
||||
if (i_mainloop != nullptr) i_mainloop->yield(true);
|
||||
}
|
||||
auto &res_body = req.getResponse();
|
||||
downloaded_file.write(res_body.data(), res_body.size());
|
||||
downloaded_file.close();
|
||||
dbgInfo(D_COMMUNICATION) << "Successfully downloaded the file. File name: " << req.getFileName();
|
||||
Maybe<string> filepath = download_dir + req.getFileName();
|
||||
on_complete_func(filepath);
|
||||
} else {
|
||||
dbgInfo(D_COMMUNICATION) << "Failed to download file. File name: " << req.getFileName();
|
||||
Maybe<string> err = genError("Failed during the downloading process.");
|
||||
on_complete_func(err);
|
||||
}
|
||||
},
|
||||
"Download file routine for '" + file_name + "'",
|
||||
false
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool
|
||||
isValidPath(const string &file_name)
|
||||
{
|
||||
struct stat info;
|
||||
string file_to_download = download_dir + file_name;
|
||||
dbgTrace(D_COMMUNICATION) << "Validating the downloading file path. Path: " << file_to_download;
|
||||
if (stat(download_dir.c_str(), &info) != 0) {
|
||||
dbgDebug(D_COMMUNICATION) << "Failed to access the downloading directory";
|
||||
return false;
|
||||
}
|
||||
if (stat(file_to_download.c_str(), &info) == 0) {
|
||||
dbgDebug(D_COMMUNICATION)
|
||||
<< "The file with the name '"
|
||||
<< file_name
|
||||
<< "' is already exist in the downloading directory";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
I_Messaging *i_msg;
|
||||
I_MainLoop *i_mainloop;
|
||||
string download_dir;
|
||||
set<DownloadingInstance> downloading_queue;
|
||||
};
|
||||
|
||||
MessagingDownloaderServer::MessagingDownloaderServer()
|
||||
:
|
||||
Component("MessagingDownloaderServer"),
|
||||
pimpl(make_unique<Impl>())
|
||||
{}
|
||||
|
||||
MessagingDownloaderServer::~MessagingDownloaderServer() {}
|
||||
|
||||
void MessagingDownloaderServer::init() { pimpl->init(); }
|
||||
void MessagingDownloaderServer::fini() { pimpl->fini(); }
|
||||
|
||||
void
|
||||
MessagingDownloaderServer::preload()
|
||||
{
|
||||
registerExpectedConfiguration<string>("Downloader", "Downloading Directory");
|
||||
};
|
2
components/messaging_downloader/messaging_downloader_ut/CMakeLists.txt
Executable file
2
components/messaging_downloader/messaging_downloader_ut/CMakeLists.txt
Executable file
@@ -0,0 +1,2 @@
|
||||
add_subdirectory(downloader_server_ut)
|
||||
add_subdirectory(downloader_client_ut)
|
@@ -0,0 +1,9 @@
|
||||
link_directories(${BOOST_ROOT}/lib)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/core/include)
|
||||
link_directories(${CMAKE_BINARY_DIR}/core/include)
|
||||
|
||||
add_unit_test(
|
||||
downloader_client_ut
|
||||
"downloader_client_ut.cc"
|
||||
"singleton;messaging_downloader_client;time_proxy;mainloop;rest;metric;event_is;message;-lboost_context;agent_core_utilities;orchestration_modules;connkey;-lboost_regex;-lboost_filesystem"
|
||||
)
|
@@ -0,0 +1,113 @@
|
||||
#include "messaging_downloader_client.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "environment.h"
|
||||
#include "singleton.h"
|
||||
#include "config.h"
|
||||
#include "config_component.h"
|
||||
#include "mainloop.h"
|
||||
#include "cptest.h"
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_messaging.h"
|
||||
#include "mock/mock_rest_api.h"
|
||||
#include "mock/mock_agent_details.h"
|
||||
#include "mock/mock_time_get.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
class MessagingDownloaderClientTest : public Test
|
||||
{
|
||||
public:
|
||||
MessagingDownloaderClientTest()
|
||||
{
|
||||
EXPECT_CALL(
|
||||
rest,
|
||||
mockRestCall(RestAction::SHOW, "download-status", _)
|
||||
).WillOnce(WithArg<2>(Invoke(this, &MessagingDownloaderClientTest::restHandler)));
|
||||
|
||||
EXPECT_CALL(rest, mockRestCall(RestAction::ADD, "declare-boolean-variable", _)).WillOnce(Return(true));
|
||||
|
||||
Debug::setUnitTestFlag(D_COMMUNICATION, Debug::DebugLevel::TRACE);
|
||||
Debug::setNewDefaultStdout(&capture_debug);
|
||||
|
||||
messaging_downloader.preload();
|
||||
env.preload();
|
||||
env.init();
|
||||
messaging_downloader.init();
|
||||
}
|
||||
|
||||
~MessagingDownloaderClientTest()
|
||||
{
|
||||
boost::filesystem::remove_all("/tmp/test_download_dir/");
|
||||
messaging_downloader.fini();
|
||||
}
|
||||
|
||||
bool
|
||||
restHandler(const unique_ptr<RestInit> &rest_ptr)
|
||||
{
|
||||
rest_handler = rest_ptr->getRest();
|
||||
return true;
|
||||
}
|
||||
|
||||
unique_ptr<ServerRest> rest_handler;
|
||||
ostringstream capture_debug;
|
||||
I_MainLoop::Routine downloading_routine;
|
||||
MessagingDownloaderClient messaging_downloader;
|
||||
NiceMock<MockTimeGet> mock_time;
|
||||
NiceMock<MockAgentDetails> mock_agent_details;
|
||||
StrictMock<MockMessaging> mock_msg;
|
||||
StrictMock<MockRestApi> rest;
|
||||
StrictMock<MockMainLoop> mock_ml;
|
||||
::Environment env;
|
||||
ConfigComponent conf;
|
||||
};
|
||||
|
||||
TEST_F(MessagingDownloaderClientTest, do_nothing)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_F(MessagingDownloaderClientTest, request_download)
|
||||
{
|
||||
string file_name = "test_file";
|
||||
string url = "https://download_test.com/test_download";
|
||||
Singleton::Consume<I_Environment>::by<MessagingDownloaderClient>()->registerValue<int>("Listening Port", 6464);
|
||||
|
||||
stringstream ss;
|
||||
ss << "{\n \"file_name\": \"" << file_name << "\","
|
||||
<< "\n \"url\": \"" << url << "\","
|
||||
<< "\n \"port\": 0,\n \"response_port\": 6464\n}";
|
||||
|
||||
EXPECT_CALL(mock_msg, sendMessage(
|
||||
true,
|
||||
ss.str(),
|
||||
I_Messaging::Method::POST,
|
||||
"127.0.0.1",
|
||||
8164,
|
||||
_,
|
||||
"/add-download-file",
|
||||
_,
|
||||
_,
|
||||
_
|
||||
)).WillOnce(Return(Maybe<string>(string("{\"uuid\": \"111\", \"status\": true}"))));
|
||||
|
||||
bool is_cb_run = false;
|
||||
bool res = Singleton::Consume<I_MessagingDownloader>::from<MessagingDownloaderClient>()->downloadFile(
|
||||
file_name,
|
||||
url,
|
||||
[&is_cb_run](const Maybe<string>& filepath)
|
||||
{
|
||||
is_cb_run = true;
|
||||
EXPECT_TRUE(filepath.ok());
|
||||
EXPECT_EQ(filepath.unpack(), "/tmp/test_download_dir/test_file");
|
||||
}
|
||||
);
|
||||
EXPECT_TRUE(res);
|
||||
|
||||
stringstream is;
|
||||
is << "{\"uuid\": \"111\", \"status\": true, \"filepath\": \"/tmp/test_download_dir/test_file\"}";
|
||||
EXPECT_FALSE(is_cb_run);
|
||||
rest_handler->performRestCall(is);
|
||||
EXPECT_TRUE(is_cb_run);
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
link_directories(${BOOST_ROOT}/lib)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/core/include)
|
||||
link_directories(${CMAKE_BINARY_DIR}/core/include)
|
||||
|
||||
add_unit_test(
|
||||
downloader_server_ut
|
||||
"downloader_server_ut.cc"
|
||||
"singleton;messaging_downloader_server;time_proxy;mainloop;rest;metric;event_is;message;-lboost_context;agent_core_utilities;orchestration_modules;agent_details;connkey;-lboost_regex;-lboost_filesystem"
|
||||
)
|
@@ -0,0 +1,304 @@
|
||||
#include "messaging_downloader_server.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "environment.h"
|
||||
#include "singleton.h"
|
||||
#include "config.h"
|
||||
#include "config_component.h"
|
||||
#include "mainloop.h"
|
||||
#include "cptest.h"
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_messaging.h"
|
||||
#include "mock/mock_rest_api.h"
|
||||
#include "mock/mock_agent_details.h"
|
||||
#include "mock/mock_time_get.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
class MessagingDownloaderServerTest : public Test
|
||||
{
|
||||
public:
|
||||
MessagingDownloaderServerTest()
|
||||
{
|
||||
setConfiguration(string("/tmp/test_download_dir/"), "Downloader", "Downloading Directory");
|
||||
EXPECT_CALL(
|
||||
rest,
|
||||
mockRestCall(RestAction::ADD, "download-file", _)
|
||||
).WillOnce(WithArg<2>(Invoke(this, &MessagingDownloaderServerTest::restHandler)));
|
||||
|
||||
Maybe<string> fog_addr(string("test.fog.com"));
|
||||
EXPECT_CALL(
|
||||
mock_agent_details,
|
||||
getFogDomain()
|
||||
).WillRepeatedly(Return(fog_addr));
|
||||
|
||||
Debug::setUnitTestFlag(D_COMMUNICATION, Debug::DebugLevel::TRACE);
|
||||
Debug::setNewDefaultStdout(&capture_debug);
|
||||
|
||||
messaging_downloader.preload();
|
||||
messaging_downloader.init();
|
||||
}
|
||||
|
||||
~MessagingDownloaderServerTest()
|
||||
{
|
||||
boost::filesystem::remove_all("/tmp/test_download_dir/");
|
||||
messaging_downloader.fini();
|
||||
}
|
||||
|
||||
bool
|
||||
restHandler(const unique_ptr<RestInit> &rest_ptr)
|
||||
{
|
||||
rest_handler = rest_ptr->getRest();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
expectRequestSuccess(
|
||||
string &test_file_name,
|
||||
string &host,
|
||||
string &url,
|
||||
string &uuid,
|
||||
unsigned int port,
|
||||
unsigned int response_port,
|
||||
string &success_msg
|
||||
)
|
||||
{
|
||||
EXPECT_CALL(
|
||||
mock_ml,
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, _, false)
|
||||
).WillOnce(DoAll(SaveArg<1>(&downloading_routine), Return(0)));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_msg,
|
||||
sendMessage(true, "", I_Messaging::Method::GET, host, port, _, url, _, _, _)
|
||||
).WillOnce(Return(Maybe<string>(string("test_body"))));
|
||||
|
||||
stringstream expected_response;
|
||||
expected_response
|
||||
<< "\n \"status\": true,"
|
||||
<< "\n \"filepath\": \"/tmp/test_download_dir/" << test_file_name << "\"\n}";
|
||||
|
||||
string saved_response;
|
||||
|
||||
EXPECT_CALL(mock_msg, sendMessage(
|
||||
false,
|
||||
_,
|
||||
I_Messaging::Method::POST,
|
||||
"127.0.0.1",
|
||||
response_port,
|
||||
_,
|
||||
"/show-download-status",
|
||||
_,
|
||||
_,
|
||||
_
|
||||
)).WillOnce(DoAll(SaveArg<1>(&saved_response), Return(Maybe<string>(string()))));
|
||||
|
||||
|
||||
stringstream is;
|
||||
is << "{\"file_name\": \"" << test_file_name << "\","
|
||||
<< "\"response_port\": " << response_port << ","
|
||||
<< "\"url\": \"" << url << "\","
|
||||
<< "\"port\": " << port << ","
|
||||
<< "\"uuid\": \"" << uuid << "\"}";
|
||||
|
||||
rest_handler->performRestCall(is);
|
||||
downloading_routine();
|
||||
EXPECT_THAT(saved_response, HasSubstr(expected_response.str()));
|
||||
EXPECT_THAT(capture_debug.str(), HasSubstr(success_msg));
|
||||
}
|
||||
|
||||
unique_ptr<ServerRest> rest_handler;
|
||||
ostringstream capture_debug;
|
||||
I_MainLoop::Routine downloading_routine;
|
||||
MessagingDownloaderServer messaging_downloader;
|
||||
NiceMock<MockTimeGet> mock_time;
|
||||
StrictMock<MockAgentDetails> mock_agent_details;
|
||||
StrictMock<MockMessaging> mock_msg;
|
||||
StrictMock<MockRestApi> rest;
|
||||
StrictMock<MockMainLoop> mock_ml;
|
||||
::Environment env;
|
||||
ConfigComponent conf;
|
||||
};
|
||||
|
||||
TEST_F(MessagingDownloaderServerTest, do_nothing)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_F(MessagingDownloaderServerTest, add_one_secured_request)
|
||||
{
|
||||
string test_file_name = "test_file_name";
|
||||
string host = "test_host";
|
||||
string url = "https://test_host/test_url";
|
||||
string uuid = "111";
|
||||
string success_msg = "Successfully downloaded the file. File name: " + test_file_name;
|
||||
unsigned int port = 443;
|
||||
unsigned int response_port = 123;
|
||||
expectRequestSuccess(test_file_name, host, url, uuid, port, response_port, success_msg);
|
||||
}
|
||||
|
||||
TEST_F(MessagingDownloaderServerTest, add_one_non_secured_request)
|
||||
{
|
||||
string test_file_name = "test_file_name";
|
||||
string host = "test_host";
|
||||
string url = "http://test_host/test_url";
|
||||
string uuid = "111";
|
||||
string success_msg = "Successfully downloaded the file. File name: " + test_file_name;
|
||||
unsigned int port = 80;
|
||||
unsigned int response_port = 123;
|
||||
expectRequestSuccess(test_file_name, host, url, uuid, port, response_port, success_msg);
|
||||
}
|
||||
|
||||
TEST_F(MessagingDownloaderServerTest, add_multiple_requests)
|
||||
{
|
||||
string test_file_name1 = "test_file_name1";
|
||||
string test_file_name2 = "test_file_name2";
|
||||
string host = "test_host";
|
||||
string url = "https://test_host/test_url";
|
||||
string uuid = "111";
|
||||
string success_msg1 = "Successfully downloaded the file. File name: " + test_file_name1;
|
||||
string success_msg2 = "Successfully downloaded the file. File name: " + test_file_name2;
|
||||
unsigned int port = 443;
|
||||
unsigned int response_port = 123;
|
||||
expectRequestSuccess(test_file_name1, host, url, uuid, port, response_port, success_msg1);
|
||||
expectRequestSuccess(test_file_name2, host, url, uuid, port, response_port, success_msg2);
|
||||
}
|
||||
|
||||
TEST_F(MessagingDownloaderServerTest, add_same_request_twice)
|
||||
{
|
||||
string test_file_name = "test_file_name";
|
||||
string host = "test_host";
|
||||
string url = "https://test_host/test_url";
|
||||
string uuid = "111";
|
||||
unsigned int response_port = 123;
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_ml,
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, _, false)
|
||||
).WillOnce(DoAll(SaveArg<1>(&downloading_routine), Return(0)));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_msg,
|
||||
sendMessage(true, "", I_Messaging::Method::GET, host, 442, _, url, _, _, _)
|
||||
).WillOnce(Return(Maybe<string>(string("test_body"))));
|
||||
|
||||
stringstream expected_response;
|
||||
expected_response
|
||||
<< "\n \"status\": true,"
|
||||
<< "\n \"filepath\": \"/tmp/test_download_dir/" << test_file_name << "\"\n}";
|
||||
|
||||
string saved_response;
|
||||
|
||||
EXPECT_CALL(mock_msg, sendMessage(
|
||||
false,
|
||||
_,
|
||||
I_Messaging::Method::POST,
|
||||
"127.0.0.1",
|
||||
response_port,
|
||||
_,
|
||||
"/show-download-status",
|
||||
_,
|
||||
_,
|
||||
_
|
||||
)).WillOnce(DoAll(SaveArg<1>(&saved_response), Return(Maybe<string>(string()))));
|
||||
|
||||
stringstream is;
|
||||
is
|
||||
<< "{\"file_name\": \"" << test_file_name << "\","
|
||||
<< "\"response_port\": " << response_port << ","
|
||||
<< "\"uuid\": \"" << uuid << "\","
|
||||
<< "\"port\": 442,"
|
||||
<< "\"url\": \"" << url << "\"}";
|
||||
|
||||
rest_handler->performRestCall(is);
|
||||
rest_handler->doCall();
|
||||
downloading_routine();
|
||||
|
||||
EXPECT_THAT(saved_response, HasSubstr(expected_response.str()));
|
||||
EXPECT_THAT(
|
||||
capture_debug.str(),
|
||||
HasSubstr("Failed to download the file. Similar download request already exists.")
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(MessagingDownloaderServerTest, add_request_that_fails)
|
||||
{
|
||||
string test_file_name = "test_file_name";
|
||||
string host = "test_host";
|
||||
string url = "https://test_host/test_url";
|
||||
string uuid = "111";
|
||||
unsigned int response_port = 123;
|
||||
unsigned int additional_port_test = 123;
|
||||
|
||||
Maybe<string> err = genError("no");
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_ml,
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, _, false)
|
||||
).WillOnce(DoAll(SaveArg<1>(&downloading_routine), Return(0)));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_msg,
|
||||
sendMessage(true, "", I_Messaging::Method::GET, host, additional_port_test, _, url, _, _, _)
|
||||
).WillOnce(Return(err));
|
||||
|
||||
stringstream expected_response;
|
||||
expected_response
|
||||
<< "\n \"status\": false,"
|
||||
<< "\n \"error\": \"Failed during the downloading process.\"\n}";
|
||||
|
||||
string saved_response;
|
||||
|
||||
EXPECT_CALL(mock_msg, sendMessage(
|
||||
false,
|
||||
_,
|
||||
I_Messaging::Method::POST,
|
||||
"127.0.0.1",
|
||||
response_port,
|
||||
_,
|
||||
"/show-download-status",
|
||||
_,
|
||||
_,
|
||||
_
|
||||
)).WillOnce(DoAll(SaveArg<1>(&saved_response), Return(Maybe<string>(string()))));
|
||||
|
||||
stringstream is;
|
||||
is
|
||||
<< "{\"file_name\": \"" << test_file_name << "\","
|
||||
<< "\"response_port\": " << response_port << ","
|
||||
<< "\"url\": \"" << url << "\","
|
||||
<< "\"port\": " << additional_port_test << ","
|
||||
<< "\"uuid\": \"" << uuid << "\"}";
|
||||
|
||||
rest_handler->performRestCall(is);
|
||||
downloading_routine();
|
||||
EXPECT_THAT(saved_response, HasSubstr(expected_response.str()));
|
||||
EXPECT_THAT(capture_debug.str(), HasSubstr("Failed to download file. File name: test_file_name"));
|
||||
}
|
||||
|
||||
TEST_F(MessagingDownloaderServerTest, download_with_same_filename)
|
||||
{
|
||||
string test_file_name = "test_file_name";
|
||||
string host = "test_host";
|
||||
string url1 = "https://test_host/test_url1";
|
||||
string url2 = "https://test_host/test_url2";
|
||||
string uuid = "111";
|
||||
unsigned int port = 443;
|
||||
string success_msg = "Successfully downloaded the file. File name: " + test_file_name;
|
||||
unsigned int response_port = 123;
|
||||
expectRequestSuccess(test_file_name, host, url1, uuid, port, response_port, success_msg);
|
||||
|
||||
stringstream is;
|
||||
is
|
||||
<< "{\"file_name\": \"" << test_file_name << "\","
|
||||
<< "\"response_port\": " << response_port << ","
|
||||
<< "\"port\": " << port << ","
|
||||
<< "\"url\": \"" << url2 << "\"}";
|
||||
|
||||
rest_handler->performRestCall(is);
|
||||
EXPECT_THAT(
|
||||
capture_debug.str(),
|
||||
HasSubstr("The file with the name 'test_file_name' is already exist in the downloading directory")
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user