blob: 954cea377792cfe5e26d1775e5a16b77f125cf36 [file]
#ifndef THIRD_PARTY_GBMCWEB_INCLUDE_IMAGE_UPLOAD_H_
#define THIRD_PARTY_GBMCWEB_INCLUDE_IMAGE_UPLOAD_H_
#include <algorithm>
#include <chrono> // NOLINT
#include <fstream> // NOLINT
#include <functional> // NOLINT
#include <memory> // NOLINT
#include <string>
#include "boost/uuid/uuid.hpp" // NOLINT
#include "boost/uuid/uuid_generators.hpp" // NOLINT
#include "boost/uuid/uuid_io.hpp" // NOLINT
#include "app.hpp"
#include "http_request.hpp"
#include "logging.hpp"
#include "async_resp.hpp"
#include "dbus_utility.hpp"
#include "managed_store.hpp"
#include "sdbusplus/bus/match.hpp"
#include "sdbusplus/message.hpp"
#include "sdbusplus/message/native_types.hpp"
#ifdef UNIT_TEST_BUILD
#include "test/g3/mock_managed_store.hpp" // NOLINT
#endif
namespace crow {
namespace image_upload {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
inline void uploadImageHandler(
const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
// Only allow one FW update at a time
if (fwUpdateMatcher != nullptr) {
asyncResp->res.addHeader("Retry-After", "30");
asyncResp->res.result(boost::beast::http::status::service_unavailable);
return;
}
// Make this const static so it survives outside this method
static boost::asio::steady_timer timeout(*req.ioService,
std::chrono::seconds(5));
timeout.expires_after(std::chrono::seconds(15));
auto timeoutHandler = [asyncResp](const boost::system::error_code& ec) {
fwUpdateMatcher = nullptr;
if (ec == boost::asio::error::operation_aborted) {
// expected, we were canceled before the timer completed.
return;
}
BMCWEB_LOG_ERROR << "Timed out waiting for Version interface";
if (ec) {
BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
return;
}
asyncResp->res.result(boost::beast::http::status::bad_request);
asyncResp->res.jsonValue["data"]["description"] =
"Version already exists or failed to be extracted";
asyncResp->res.jsonValue["message"] = "400 Bad Request";
asyncResp->res.jsonValue["status"] = "error";
};
std::function<void(sdbusplus::message_t&)> callback =
[asyncResp](sdbusplus::message_t& m) {
BMCWEB_LOG_DEBUG << "Match fired";
sdbusplus::message::object_path path;
dbus::utility::DBusInteracesMap interfaces;
m.read(path, interfaces);
if (std::find_if(
interfaces.begin(), interfaces.end(), [](const auto& i) {
return i.first == "xyz.openbmc_project.Software.Version";
}) != interfaces.end()) {
timeout.cancel();
std::string leaf = path.filename();
if (leaf.empty()) {
leaf = path.str;
}
asyncResp->res.jsonValue["data"] = leaf;
asyncResp->res.jsonValue["message"] = "200 OK";
asyncResp->res.jsonValue["status"] = "ok";
BMCWEB_LOG_DEBUG << "ending response";
fwUpdateMatcher = nullptr;
}
};
fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
*(managedStore::GetManagedObjectStore()
->GetDeprecatedThreadUnsafeSystemBus()),
"interface='org.freedesktop.DBus.ObjectManager',type='signal',"
"member='InterfacesAdded',path='/xyz/openbmc_project/software'",
callback);
std::string filepath(
"/tmp/images/" +
boost::uuids::to_string(boost::uuids::random_generator()()));
BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
std::ofstream::trunc);
out << req.body();
out.close();
timeout.async_wait(timeoutHandler);
}
inline void requestRoutes(App& app) {
BMCWEB_ROUTE(app, "/upload/image/<str>")
.privileges({{"ConfigureComponents", "ConfigureManager"}})
.methods(boost::beast::http::verb::post, boost::beast::http::verb::put)(
[](const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string&) { uploadImageHandler(req, asyncResp); });
BMCWEB_ROUTE(app, "/upload/image")
.privileges({{"ConfigureComponents", "ConfigureManager"}})
.methods(boost::beast::http::verb::post, boost::beast::http::verb::put)(
[](const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
uploadImageHandler(req, asyncResp);
});
}
} // namespace image_upload
} // namespace crow
#endif // THIRD_PARTY_GBMCWEB_INCLUDE_IMAGE_UPLOAD_H_