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