Make bmcweb image upload compatible with upstream.

This change moves the image upload logic out of the intel oem
namespace, and makes it 1:1 compatible with phosphor rest dbus.  This
is to allow a seamless transition in the future.

Change-Id: I243237357a672934c05bf072e7ff1a5955af0f5e
diff --git a/include/image_upload.hpp b/include/image_upload.hpp
new file mode 100644
index 0000000..2a95967
--- /dev/null
+++ b/include/image_upload.hpp
@@ -0,0 +1,103 @@
+#pragma once
+
+#include <dbus_singleton.hpp>
+#include <cstdio>
+#include <fstream>
+#include <memory>
+#include <crow/app.h>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+#include <boost/uuid/uuid_io.hpp>
+
+namespace crow {
+namespace image_upload {
+
+std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
+
+inline void uploadImageHandler(const crow::request& req, crow::response& res,
+                               const std::string& filename) {
+  // Only allow one FW update at a time
+  if (fwUpdateMatcher != nullptr) {
+    res.add_header("Retry-After", "30");
+    res.result(boost::beast::http::status::service_unavailable);
+    res.end();
+    return;
+  }
+  // Make this const static so it survives outside this method
+  static boost::asio::deadline_timer timeout(*req.io_service,
+                                             boost::posix_time::seconds(5));
+
+  timeout.expires_from_now(boost::posix_time::seconds(5));
+
+  timeout.async_wait([&res](const boost::system::error_code& ec) {
+    fwUpdateMatcher = nullptr;
+    if (ec == asio::error::operation_aborted) {
+      // expected, we were canceled before the timer completed.
+      return;
+    }
+    CROW_LOG_ERROR << "Timed out waiting for log event";
+
+    if (ec) {
+      CROW_LOG_ERROR << "Async_wait failed " << ec;
+      return;
+    }
+
+    res.result(boost::beast::http::status::internal_server_error);
+    res.end();
+  });
+
+  std::function<void(sdbusplus::message::message&)> callback =
+      [&res](sdbusplus::message::message& m) {
+        CROW_LOG_DEBUG << "Match fired";
+        boost::system::error_code ec;
+        timeout.cancel(ec);
+        if (ec) {
+          CROW_LOG_ERROR << "error canceling timer " << ec;
+        }
+        std::string versionInfo;
+        m.read(versionInfo);  // Read in the object path that was just created
+
+        std::size_t index = versionInfo.rfind('/');
+        if (index != std::string::npos) {
+          versionInfo.erase(0, index);
+        }
+        res.json_value = {{"data", std::move(versionInfo)},
+                          {"message", "200 OK"},
+                          {"status", "ok"}};
+        CROW_LOG_DEBUG << "ending response";
+        res.end();
+        fwUpdateMatcher = nullptr;
+      };
+  fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
+      *crow::connections::system_bus,
+      "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
+      "member='InterfacesAdded',path='/xyz/openbmc_project/logging'",
+      callback);
+
+  std::string filepath(
+      "/tmp/images/" +
+      boost::uuids::to_string(boost::uuids::random_generator()()));
+  CROW_LOG_DEBUG << "Writing file to " << filepath;
+  std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
+                                  std::ofstream::trunc);
+  out << req.body;
+  out.close();
+}
+
+template <typename... Middlewares>
+void requestRoutes(Crow<Middlewares...>& app) {
+  CROW_ROUTE(app, "/upload/image/<str>")
+      .methods("POST"_method,
+               "PUT"_method)([](const crow::request& req, crow::response& res,
+                                const std::string& filename) {
+        uploadImageHandler(req, res, filename);
+      });
+
+  CROW_ROUTE(app, "/upload/image")
+      .methods("POST"_method,
+               "PUT"_method)([](const crow::request& req, crow::response& res) {
+        uploadImageHandler(req, res, "");
+      });
+}
+}  // namespace image_upload
+}  // namespace crow
diff --git a/include/intel_oem.hpp b/include/intel_oem.hpp
deleted file mode 100644
index f2dc163..0000000
--- a/include/intel_oem.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include <dbus_singleton.hpp>
-#include <fstream>
-#include <crow/app.h>
-
-namespace crow {
-namespace intel_oem {
-
-template <typename... Middlewares>
-void request_routes(Crow<Middlewares...>& app) {
-  CROW_ROUTE(app, "/intel/firmwareupload")
-      .methods(
-          "POST"_method)([](const crow::request& req, crow::response& res) {
-        std::string filepath("/tmp/fw_update_image");
-        std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
-                                        std::ofstream::trunc);
-        out << req.body;
-        out.close();
-        crow::connections::system_bus->async_method_call(
-            [&](boost::system::error_code ec) {
-              std::cout << "async_method_call callback\n";
-              if (ec) {
-                std::cerr << "error with async_method_call \n";
-                res.json_value["status"] = "Upload failed";
-              } else {
-                res.json_value["status"] = "Upload Successful";
-              }
-              res.end();
-            },
-            "xyz.openbmc_project.fwupdate1.server",
-            "/xyz/openbmc_project/fwupdate1", "xyz.openbmc_project.fwupdate1",
-            "start", "file://" + filepath);
-
-      });
-}
-}  // namespace intel_oem
-}  // namespace crow
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index eaaca94..93b3aa6 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -1,7 +1,7 @@
 #include <systemd/sd-daemon.h>
 #include <dbus_monitor.hpp>
 #include <dbus_singleton.hpp>
-#include <intel_oem.hpp>
+#include <image_upload.hpp>
 #include <openbmc_dbus_rest.hpp>
 #include <persistent_data_middleware.hpp>
 #include <redfish_v1.hpp>
@@ -43,7 +43,7 @@
 }
 
 int main(int argc, char** argv) {
-    crow::logger::setLogLevel(crow::LogLevel::DEBUG);
+  crow::logger::setLogLevel(crow::LogLevel::DEBUG);
 
   auto io = std::make_shared<boost::asio::io_service>();
   crow::PersistentData::session_store =
@@ -67,7 +67,7 @@
   crow::kvm::request_routes(app);
   crow::redfish::request_routes(app);
   crow::dbus_monitor::request_routes(app);
-  crow::intel_oem::request_routes(app);
+  crow::image_upload::requestRoutes(app);
   crow::openbmc_mapper::request_routes(app);
 
   CROW_LOG_INFO << "bmcweb (" << __DATE__ << ": " << __TIME__ << ')';
@@ -80,4 +80,5 @@
   app.run();
   io->run();
 
+  crow::connections::system_bus.reset();
 }