1 #pragma once 2 3 #include <dbus_singleton.hpp> 4 #include <cstdio> 5 #include <fstream> 6 #include <memory> 7 #include <crow/app.h> 8 #include <boost/uuid/uuid.hpp> 9 #include <boost/uuid/uuid_generators.hpp> 10 #include <boost/uuid/uuid_io.hpp> 11 12 namespace crow { 13 namespace image_upload { 14 15 std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher; 16 17 inline void uploadImageHandler(const crow::Request& req, crow::Response& res, 18 const std::string& filename) { 19 // Only allow one FW update at a time 20 if (fwUpdateMatcher != nullptr) { 21 res.addHeader("Retry-After", "30"); 22 res.result(boost::beast::http::status::service_unavailable); 23 res.end(); 24 return; 25 } 26 // Make this const static so it survives outside this method 27 static boost::asio::deadline_timer timeout(*req.ioService, 28 boost::posix_time::seconds(5)); 29 30 timeout.expires_from_now(boost::posix_time::seconds(5)); 31 32 timeout.async_wait([&res](const boost::system::error_code& ec) { 33 fwUpdateMatcher = nullptr; 34 if (ec == asio::error::operation_aborted) { 35 // expected, we were canceled before the timer completed. 36 return; 37 } 38 BMCWEB_LOG_ERROR << "Timed out waiting for log event"; 39 40 if (ec) { 41 BMCWEB_LOG_ERROR << "Async_wait failed " << ec; 42 return; 43 } 44 45 res.result(boost::beast::http::status::internal_server_error); 46 res.end(); 47 }); 48 49 std::function<void(sdbusplus::message::message&)> callback = 50 [&res](sdbusplus::message::message& m) { 51 BMCWEB_LOG_DEBUG << "Match fired"; 52 boost::system::error_code ec; 53 timeout.cancel(ec); 54 if (ec) { 55 BMCWEB_LOG_ERROR << "error canceling timer " << ec; 56 } 57 std::string versionInfo; 58 m.read(versionInfo); // Read in the object path that was just created 59 60 std::size_t index = versionInfo.rfind('/'); 61 if (index != std::string::npos) { 62 versionInfo.erase(0, index); 63 } 64 res.jsonValue = {{"data", std::move(versionInfo)}, 65 {"message", "200 OK"}, 66 {"status", "ok"}}; 67 BMCWEB_LOG_DEBUG << "ending response"; 68 res.end(); 69 fwUpdateMatcher = nullptr; 70 }; 71 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 72 *crow::connections::systemBus, 73 "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 74 "member='InterfacesAdded',path='/xyz/openbmc_project/logging'", 75 callback); 76 77 std::string filepath( 78 "/tmp/images/" + 79 boost::uuids::to_string(boost::uuids::random_generator()())); 80 BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 81 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 82 std::ofstream::trunc); 83 out << req.body; 84 out.close(); 85 } 86 87 template <typename... Middlewares> 88 void requestRoutes(Crow<Middlewares...>& app) { 89 BMCWEB_ROUTE(app, "/upload/image/<str>") 90 .methods("POST"_method, 91 "PUT"_method)([](const crow::Request& req, crow::Response& res, 92 const std::string& filename) { 93 uploadImageHandler(req, res, filename); 94 }); 95 96 BMCWEB_ROUTE(app, "/upload/image") 97 .methods("POST"_method, 98 "PUT"_method)([](const crow::Request& req, crow::Response& res) { 99 uploadImageHandler(req, res, ""); 100 }); 101 } 102 } // namespace image_upload 103 } // namespace crow 104