xref: /openbmc/bmcweb/include/image_upload.hpp (revision 683f7276)
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