Boost beast

This commit is the beginings of attempting to transition away from
crow, and toward boost::beast.  Unit tests are passing, and
implementation appears to be slightly faster than crow.

Change-Id: Ic8d946dc7a04f514c67b1098f181eee1ced69171
diff --git a/include/ast_video_puller.hpp b/include/ast_video_puller.hpp
index 759aaeb..6cd7f37 100644
--- a/include/ast_video_puller.hpp
+++ b/include/ast_video_puller.hpp
@@ -148,7 +148,7 @@
     boost::asio::async_read(
         dev_video, mutable_buffer, [this](const boost::system::error_code &ec,
                                           std::size_t bytes_transferred) {
-          if (ec != nullptr) {
+          if (ec) {
             std::cerr << "Read failed with status " << ec << "\n";
           } else {
             this->read_done();
diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp
index 4257127..e6052f1 100644
--- a/include/openbmc_dbus_rest.hpp
+++ b/include/openbmc_dbus_rest.hpp
@@ -2,6 +2,7 @@
 
 #include <tinyxml2.h>
 #include <dbus_singleton.hpp>
+#include <boost/algorithm/string.hpp>
 #include <boost/container/flat_set.hpp>
 
 namespace crow {
@@ -130,7 +131,7 @@
           const boost::system::error_code ec,
           const GetSubTreeType &object_names) {
         if (ec) {
-          res.code = 500;
+          res.result(boost::beast::http::status::internal_server_error);
           res.end();
           return;
         }
@@ -144,7 +145,7 @@
         }
 
         if (connections.size() <= 0) {
-          res.code = 404;
+          res.result(boost::beast::http::status::not_found);
           res.end();
           return;
         }
@@ -163,10 +164,10 @@
 
 template <typename... Middlewares>
 void request_routes(Crow<Middlewares...> &app) {
-  CROW_ROUTE(app, "/bus/").methods("GET"_method)([](const crow::request &req) {
-    return nlohmann::json{{"busses", {{{"name", "system"}}}}, {"status", "ok"}};
-
-  });
+  CROW_ROUTE(app, "/bus/")
+      .methods("GET"_method)([](const crow::request &req, crow::response &res) {
+        res.json_value = {{"busses", {{{"name", "system"}}}}, {"status", "ok"}};
+      });
 
   CROW_ROUTE(app, "/bus/system/")
       .methods("GET"_method)([](const crow::request &req, crow::response &res) {
@@ -174,7 +175,7 @@
         auto myCallback = [&res](const boost::system::error_code ec,
                                  std::vector<std::string> &names) {
           if (ec) {
-            res.code = 500;
+            res.result(boost::beast::http::status::internal_server_error);
           } else {
             std::sort(names.begin(), names.end());
             nlohmann::json j{{"status", "ok"}};
@@ -197,7 +198,7 @@
             [&res](const boost::system::error_code ec,
                    const std::vector<std::string> &object_paths) {
               if (ec) {
-                res.code = 500;
+                res.result(boost::beast::http::status::internal_server_error);
               } else {
                 res.json_value = {{"status", "ok"},
                                   {"message", "200 OK"},
@@ -232,21 +233,21 @@
           auto request_dbus_data =
               nlohmann::json::parse(req.body, nullptr, false);
           if (request_dbus_data.is_discarded()) {
-            res.code = 400;
+            res.result(boost::beast::http::status::unauthorized);
             res.end();
             return;
           }
 
           auto property_value_it = request_dbus_data.find("data");
           if (property_value_it == request_dbus_data.end()) {
-            res.code = 400;
+            res.result(boost::beast::http::status::unauthorized);
             res.end();
             return;
           }
 
           property_set_value = property_value_it->get<const std::string>();
           if (property_set_value.empty()) {
-            res.code = 400;
+            res.result(boost::beast::http::status::unauthorized);
             res.end();
             return;
           }
@@ -266,16 +267,16 @@
             ](const boost::system::error_code ec,
               const GetObjectType &object_names) {
               if (ec) {
-                res.code = 500;
+                res.result(boost::beast::http::status::internal_server_error);
                 res.end();
                 return;
               }
               if (object_names.size() != 1) {
-                res.code = 404;
+                res.result(boost::beast::http::status::not_found);
                 res.end();
                 return;
               }
-              if (req.method == "GET"_method) {
+              if (req.method() == "GET"_method) {
                 for (auto &interface : object_names[0].second) {
                   crow::connections::system_bus->async_method_call(
                       [&res, transaction](
@@ -303,7 +304,7 @@
                       object_names[0].first, object_path,
                       "org.freedesktop.DBus.Properties", "GetAll", interface);
                 }
-              } else if (req.method == "PUT"_method) {
+              } else if (req.method() == "PUT"_method) {
                 for (auto &interface : object_names[0].second) {
                   crow::connections::system_bus->async_method_call(
                       [
@@ -351,7 +352,7 @@
                           // if nobody filled in the property, all calls either
                           // errored, or failed
                           if (transaction == nullptr) {
-                            res.code = 403;
+                            res.result(boost::beast::http::status::forbidden);
                             res.json_value = {{"status", "error"},
                                               {"message", "403 Forbidden"},
                                               {"data",
@@ -426,7 +427,7 @@
         if (it != strs.end()) {
           // if there is more levels past the method name, something went
           // wrong, throw an error
-          res.code = 404;
+          res.result(boost::beast::http::status::not_found);
           res.end();
           return;
         }
@@ -452,8 +453,9 @@
                     CROW_LOG_ERROR << "XML document failed to parse "
                                    << process_name << " " << object_path
                                    << "\n";
-                    res.write(nlohmann::json{{"status", "XML parse error"}});
-                    res.code = 500;
+                    res.json_value = {{"status", "XML parse error"}};
+                    res.result(
+                        boost::beast::http::status::internal_server_error);
                   } else {
                     nlohmann::json interfaces_array = nlohmann::json::array();
                     tinyxml2::XMLElement *interface =
@@ -498,7 +500,8 @@
                     CROW_LOG_ERROR << "XML document failed to parse "
                                    << process_name << " " << object_path
                                    << "\n";
-                    res.code = 500;
+                    res.result(
+                        boost::beast::http::status::internal_server_error);
 
                   } else {
                     tinyxml2::XMLElement *node =
@@ -575,7 +578,7 @@
                     if (interface == nullptr) {
                       // if we got to the end of the list and never found a
                       // match, throw 404
-                      res.code = 404;
+                      res.result(boost::beast::http::status::not_found);
                     }
                   }
                 }
diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp
index 5b4b454..997c297 100644
--- a/include/pam_authenticate.hpp
+++ b/include/pam_authenticate.hpp
@@ -1,8 +1,9 @@
 #pragma once
 
 #include <security/pam_appl.h>
-#include <memory>
 #include <cstring>
+#include <memory>
+#include <boost/utility/string_view.hpp>
 
 // function used to get user input
 inline int pam_function_conversation(int num_msg,
@@ -32,13 +33,15 @@
   return PAM_SUCCESS;
 }
 
-inline bool pam_authenticate_user(const std::string& username,
-                                  const std::string& password) {
+inline bool pam_authenticate_user(const boost::string_view username,
+                                  const boost::string_view password) {
+  std::string user_str(username);
+  std::string pass_str(password);
   const struct pam_conv local_conversation = {
-      pam_function_conversation, const_cast<char*>(password.c_str())};
+      pam_function_conversation, const_cast<char*>(pass_str.c_str())};
   pam_handle_t* local_auth_handle = NULL;  // this gets set by pam_start
 
-  if (pam_start("dropbear", username.c_str(), &local_conversation,
+  if (pam_start("dropbear", user_str.c_str(), &local_conversation,
                 &local_auth_handle) != PAM_SUCCESS) {
     return false;
   }
diff --git a/include/persistent_data_middleware.hpp b/include/persistent_data_middleware.hpp
index fcab52f..77a5bbb 100644
--- a/include/persistent_data_middleware.hpp
+++ b/include/persistent_data_middleware.hpp
@@ -68,11 +68,11 @@
         if (jSessions != data.end()) {
           if (jSessions->is_object()) {
             for (const auto& elem : *jSessions) {
-              UserSession newSession;
+              std::shared_ptr<UserSession> newSession = std::make_shared<UserSession>();
 
-              if (newSession.fromJson(elem)) {
-                session_store->auth_tokens.emplace(newSession.unique_id,
-                                                   std::move(newSession));
+              if (newSession->fromJson(elem)) {
+                session_store->auth_tokens.emplace(newSession->unique_id,
+                                                   newSession);
               }
             }
           }
diff --git a/include/redfish_v1.hpp b/include/redfish_v1.hpp
index 49a5a15..e8f4d7f 100644
--- a/include/redfish_v1.hpp
+++ b/include/redfish_v1.hpp
@@ -11,36 +11,6 @@
 namespace crow {
 namespace redfish {
 
-template <typename... Middlewares>
-void get_redfish_sub_routes(Crow<Middlewares...>& app, const std::string& url,
-                            nlohmann::json& j) {
-  std::vector<const std::string*> routes = app.get_routes(url);
-  for (auto route : routes) {
-    auto redfish_sub_route =
-        route->substr(url.size(), route->size() - url.size() - 1);
-    // check if the route is at this level, and we didn't find and exact match
-    // also, filter out resources that start with $ to remove $metadata
-    if (!redfish_sub_route.empty() && redfish_sub_route[0] != '$' &&
-        redfish_sub_route.find('/') == std::string::npos) {
-      j[redfish_sub_route] = nlohmann::json{{"@odata.id", *route}};
-    }
-  }
-}
-
-std::string execute_process(const char* cmd) {
-  std::array<char, 128> buffer;
-  std::string result;
-  std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
-  if (!pipe) throw std::runtime_error("popen() failed!");
-  while (!feof(pipe.get())) {
-    if (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
-      result += buffer.data();
-  }
-  return result;
-}
-
-// GetManagedObjects unpack type.  Observe that variant has only one bool type,
-// because we don't actually use the values it provides
 using ManagedObjectType = std::vector<std::pair<
     sdbusplus::message::object_path,
     boost::container::flat_map<
@@ -62,7 +32,7 @@
             [&](const boost::system::error_code ec,
                 const ManagedObjectType& users) {
               if (ec) {
-                res.code = 500;
+                res.result(boost::beast::http::status::internal_server_error);
               } else {
                 res.json_value = {
                     {"@odata.context",
@@ -107,7 +77,7 @@
                 const boost::system::error_code ec,
                 const ManagedObjectType& users) {
               if (ec) {
-                res.code = 500;
+                res.result(boost::beast::http::status::internal_server_error);
               } else {
                 for (auto& user : users) {
                   const std::string& path =
@@ -141,7 +111,7 @@
                   }
                 }
                 if (res.json_value.is_null()) {
-                  res.code = 404;
+                  res.result(boost::beast::http::status::not_found);
                 }
               }
               res.end();
diff --git a/include/sessions.hpp b/include/sessions.hpp
index 15ff9ca..fdd1200 100644
--- a/include/sessions.hpp
+++ b/include/sessions.hpp
@@ -73,12 +73,12 @@
   }
 };
 
-void to_json(nlohmann::json& j, const UserSession& p) {
-  if (p.persistence != PersistenceType::SINGLE_REQUEST) {
-    j = nlohmann::json{{"unique_id", p.unique_id},
-                       {"session_token", p.session_token},
-                       {"username", p.username},
-                       {"csrf_token", p.csrf_token}};
+void to_json(nlohmann::json& j, const std::shared_ptr<UserSession> p) {
+  if (p->persistence != PersistenceType::SINGLE_REQUEST) {
+    j = {{"unique_id", p->unique_id},
+         {"session_token", p->session_token},
+         {"username", p->username},
+         {"csrf_token", p->csrf_token}};
   }
 }
 
@@ -87,8 +87,8 @@
 class SessionStore {
  public:
   SessionStore() : timeout_in_minutes(60) {}
-  const UserSession& generate_user_session(
-      const std::string& username,
+  std::shared_ptr<UserSession> generate_user_session(
+      const boost::string_view username,
       PersistenceType persistence = PersistenceType::TIMEOUT) {
     // TODO(ed) find a secure way to not generate session identifiers if
     // persistence is set to SINGLE_REQUEST
@@ -120,42 +120,42 @@
     for (int i = 0; i < unique_id.size(); ++i) {
       unique_id[i] = alphanum[dist(rd)];
     }
-
-    const auto session_it = auth_tokens.emplace(
-        session_token,
-        std::move(UserSession{unique_id, session_token, username, csrf_token,
-                              std::chrono::steady_clock::now(), persistence}));
-    const UserSession& user = (session_it).first->second;
+    auto session = std::make_shared<UserSession>(
+        UserSession{unique_id, session_token, std::string(username), csrf_token,
+                    std::chrono::steady_clock::now(), persistence});
+    auto it = auth_tokens.emplace(std::make_pair(session_token, session));
     // Only need to write to disk if session isn't about to be destroyed.
     need_write_ = persistence == PersistenceType::TIMEOUT;
-    return user;
+    return it.first->second;
   }
 
-  const UserSession* login_session_by_token(const std::string& token) {
+  std::shared_ptr<UserSession> login_session_by_token(
+      const boost::string_view token) {
     apply_session_timeouts();
-    auto session_it = auth_tokens.find(token);
+    auto session_it = auth_tokens.find(std::string(token));
     if (session_it == auth_tokens.end()) {
       return nullptr;
     }
-    UserSession& foo = session_it->second;
-    foo.last_updated = std::chrono::steady_clock::now();
-    return &foo;
+    std::shared_ptr<UserSession> user_session = session_it->second;
+    user_session->last_updated = std::chrono::steady_clock::now();
+    return user_session;
   }
 
-  const UserSession* get_session_by_uid(const std::string& uid) {
+  std::shared_ptr<UserSession> get_session_by_uid(
+      const boost::string_view uid) {
     apply_session_timeouts();
     // TODO(Ed) this is inefficient
     auto session_it = auth_tokens.begin();
     while (session_it != auth_tokens.end()) {
-      if (session_it->second.unique_id == uid) {
-        return &session_it->second;
+      if (session_it->second->unique_id == uid) {
+        return session_it->second;
       }
       session_it++;
     }
     return nullptr;
   }
 
-  void remove_session(const UserSession* session) {
+  void remove_session(std::shared_ptr<UserSession> session) {
     auth_tokens.erase(session->session_token);
     need_write_ = true;
   }
@@ -168,8 +168,8 @@
     std::vector<const std::string*> ret;
     ret.reserve(auth_tokens.size());
     for (auto& session : auth_tokens) {
-      if (getAll || type == session.second.persistence) {
-        ret.push_back(&session.second.unique_id);
+      if (getAll || type == session.second->persistence) {
+        ret.push_back(&session.second->unique_id);
       }
     }
     return ret;
@@ -191,7 +191,7 @@
       last_timeout_update = time_now;
       auto auth_tokens_it = auth_tokens.begin();
       while (auth_tokens_it != auth_tokens.end()) {
-        if (time_now - auth_tokens_it->second.last_updated >=
+        if (time_now - auth_tokens_it->second->last_updated >=
             timeout_in_minutes) {
           auth_tokens_it = auth_tokens.erase(auth_tokens_it);
           need_write_ = true;
@@ -202,11 +202,12 @@
     }
   }
   std::chrono::time_point<std::chrono::steady_clock> last_timeout_update;
-  boost::container::flat_map<std::string, UserSession> auth_tokens;
+  boost::container::flat_map<std::string, std::shared_ptr<UserSession>>
+      auth_tokens;
   std::random_device rd;
   bool need_write_{false};
   std::chrono::minutes timeout_in_minutes;
 };
 
-}  // namespaec PersistentData
+}  // namespace PersistentData
 }  // namespace crow
diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp
index 07540d4..49649dd 100644
--- a/include/token_authorization_middleware.hpp
+++ b/include/token_authorization_middleware.hpp
@@ -5,10 +5,9 @@
 #include <webassets.hpp>
 #include <random>
 #include <crow/app.h>
-#include <crow/http_codes.h>
+#include <crow/common.h>
 #include <crow/http_request.h>
 #include <crow/http_response.h>
-#include <boost/bimap.hpp>
 #include <boost/container/flat_set.hpp>
 
 namespace crow {
@@ -18,7 +17,7 @@
 class Middleware {
  public:
   struct context {
-    const crow::PersistentData::UserSession* session;
+    std::shared_ptr<crow::PersistentData::UserSession> session;
   };
 
   void before_handle(crow::request& req, response& res, context& ctx) {
@@ -27,25 +26,27 @@
     }
 
     ctx.session = perform_xtoken_auth(req);
-
     if (ctx.session == nullptr) {
       ctx.session = perform_cookie_auth(req);
     }
-
-    const std::string& auth_header = req.get_header_value("Authorization");
-    // Reject any kind of auth other than basic or token
-    if (ctx.session == nullptr && boost::starts_with(auth_header, "Token ")) {
-      ctx.session = perform_token_auth(auth_header);
-    }
-
-    if (ctx.session == nullptr && boost::starts_with(auth_header, "Basic ")) {
-      ctx.session = perform_basic_auth(auth_header);
+    if (ctx.session == nullptr) {
+      boost::string_view auth_header = req.get_header_value("Authorization");
+      if (!auth_header.empty()) {
+        // Reject any kind of auth other than basic or token
+        if (boost::starts_with(auth_header, "Token ")) {
+          ctx.session = perform_token_auth(auth_header);
+        } else if (boost::starts_with(auth_header, "Basic ")) {
+          ctx.session = perform_basic_auth(auth_header);
+        }
+      }
     }
 
     if (ctx.session == nullptr) {
       CROW_LOG_WARNING << "[AuthMiddleware] authorization failed";
-      res.code = static_cast<int>(HttpRespCode::UNAUTHORIZED);
+
+      res.result(boost::beast::http::status::unauthorized);
       res.add_header("WWW-Authenticate", "Basic");
+
       res.end();
       return;
     }
@@ -57,10 +58,10 @@
   template <typename AllContext>
   void after_handle(request& req, response& res, context& ctx,
                     AllContext& allctx) {
-    // TODO(ed) THis should really be handled by the persistent data middleware,
-    // but because it is upstream, it doesn't have access to the session
-    // information.  Should the data middleware persist the current user
-    // session?
+    // TODO(ed) THis should really be handled by the persistent data
+    // middleware, but because it is upstream, it doesn't have access to the
+    // session information.  Should the data middleware persist the current
+    // user session?
     if (ctx.session != nullptr &&
         ctx.session->persistence ==
             crow::PersistentData::PersistenceType::SINGLE_REQUEST) {
@@ -69,12 +70,12 @@
   }
 
  private:
-  const crow::PersistentData::UserSession* perform_basic_auth(
-      const std::string& auth_header) const {
+  const std::shared_ptr<crow::PersistentData::UserSession> perform_basic_auth(
+      boost::string_view auth_header) const {
     CROW_LOG_DEBUG << "[AuthMiddleware] Basic authentication";
 
     std::string auth_data;
-    std::string param = auth_header.substr(strlen("Basic "));
+    boost::string_view param = auth_header.substr(strlen("Basic "));
     if (!crow::utility::base64_decode(param, auth_data)) {
       return nullptr;
     }
@@ -102,24 +103,24 @@
     // needed.
     // This whole flow needs to be revisited anyway, as we can't be
     // calling directly into pam for every request
-    return &(PersistentData::session_store->generate_user_session(
-        user, crow::PersistentData::PersistenceType::SINGLE_REQUEST));
+    return PersistentData::session_store->generate_user_session(
+        user, crow::PersistentData::PersistenceType::SINGLE_REQUEST);
   }
 
-  const crow::PersistentData::UserSession* perform_token_auth(
-      const std::string& auth_header) const {
+  const std::shared_ptr<crow::PersistentData::UserSession> perform_token_auth(
+      boost::string_view auth_header) const {
     CROW_LOG_DEBUG << "[AuthMiddleware] Token authentication";
 
-    std::string token = auth_header.substr(strlen("Token "));
+    boost::string_view token = auth_header.substr(strlen("Token "));
     auto session = PersistentData::session_store->login_session_by_token(token);
     return session;
   }
 
-  const crow::PersistentData::UserSession* perform_xtoken_auth(
+  const std::shared_ptr<crow::PersistentData::UserSession> perform_xtoken_auth(
       const crow::request& req) const {
     CROW_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication";
 
-    const std::string& token = req.get_header_value("X-Auth-Token");
+    boost::string_view token = req.get_header_value("X-Auth-Token");
     if (token.empty()) {
       return nullptr;
     }
@@ -127,11 +128,11 @@
     return session;
   }
 
-  const crow::PersistentData::UserSession* perform_cookie_auth(
+  const std::shared_ptr<crow::PersistentData::UserSession> perform_cookie_auth(
       const crow::request& req) const {
     CROW_LOG_DEBUG << "[AuthMiddleware] Cookie authentication";
 
-    auto& cookie_value = req.get_header_value("Cookie");
+    boost::string_view cookie_value = req.get_header_value("Cookie");
     if (cookie_value.empty()) {
       return nullptr;
     }
@@ -145,18 +146,18 @@
     if (end_index == std::string::npos) {
       end_index = cookie_value.size();
     }
-    std::string auth_key =
+    boost::string_view auth_key =
         cookie_value.substr(start_index, end_index - start_index);
 
-    const crow::PersistentData::UserSession* session =
+    const std::shared_ptr<crow::PersistentData::UserSession> session =
         PersistentData::session_store->login_session_by_token(auth_key);
     if (session == nullptr) {
       return nullptr;
     }
 
     // RFC7231 defines methods that need csrf protection
-    if (req.method != "GET"_method) {
-      const std::string& csrf = req.get_header_value("X-XSRF-TOKEN");
+    if (req.method() != "GET"_method) {
+      boost::string_view csrf = req.get_header_value("X-XSRF-TOKEN");
       // Make sure both tokens are filled
       if (csrf.empty() || session->csrf_token.empty()) {
         return nullptr;
@@ -171,21 +172,21 @@
 
   // checks if request can be forwarded without authentication
   bool is_on_whitelist(const crow::request& req) const {
-    // it's allowed to GET root node without authentication
-    if ("GET"_method == req.method) {
-      CROW_LOG_DEBUG << "TESTING ROUTE " << req.url;
+    // it's allowed to GET root node without authentica tion
+    if ("GET"_method == req.method()) {
       if (req.url == "/redfish/v1" || req.url == "/redfish/v1/") {
         return true;
-      } else if (crow::webassets::routes.find(req.url) !=
+      } else if (crow::webassets::routes.find(std::string(req.url)) !=
                  crow::webassets::routes.end()) {
         return true;
       }
     }
 
-    // it's allowed to POST on session collection & login without authentication
-    if ("POST"_method == req.method) {
-      if ((req.url == "/redfish/v1/SessionService/Sessions" ||
-           req.url == "/redfish/v1/SessionService/Sessions/") ||
+    // it's allowed to POST on session collection & login without
+    // authentication
+    if ("POST"_method == req.method()) {
+      if ((req.url == "/redfish/v1/SessionService/Sessions") ||
+          (req.url == "/redfish/v1/SessionService/Sessions/") ||
           (req.url == "/login") || (req.url == "/logout")) {
         return true;
       }
@@ -207,35 +208,38 @@
   CROW_ROUTE(app, "/login")
       .methods(
           "POST"_method)([&](const crow::request& req, crow::response& res) {
-        std::string content_type;
-        auto content_type_it = req.headers.find("content-type");
-        if (content_type_it != req.headers.end()) {
-          content_type = content_type_it->second;
-          boost::algorithm::to_lower(content_type);
-        }
-        const std::string* username;
-        const std::string* password;
+        boost::string_view content_type = req.get_header_value("content-type");
+        boost::string_view username;
+        boost::string_view password;
+
         bool looks_like_ibm = false;
 
-        // This object needs to be declared at this scope so the strings within
-        // it are not destroyed before we can use them
+        // This object needs to be declared at this scope so the strings
+        // within it are not destroyed before we can use them
         nlohmann::json login_credentials;
         // Check if auth was provided by a payload
         if (content_type == "application/json") {
           login_credentials = nlohmann::json::parse(req.body, nullptr, false);
           if (login_credentials.is_discarded()) {
-            res.code = 400;
+            res.result(boost::beast::http::status::bad_request);
             res.end();
             return;
           }
+
           // check for username/password in the root object
           // THis method is how intel APIs authenticate
-          auto user_it = login_credentials.find("username");
-          auto pass_it = login_credentials.find("password");
+          nlohmann::json::iterator user_it = login_credentials.find("username");
+          nlohmann::json::iterator pass_it = login_credentials.find("password");
           if (user_it != login_credentials.end() &&
               pass_it != login_credentials.end()) {
-            username = user_it->get_ptr<const std::string*>();
-            password = pass_it->get_ptr<const std::string*>();
+            const std::string* user_str =
+                user_it->get_ptr<const std::string*>();
+            const std::string* pass_str =
+                pass_it->get_ptr<const std::string*>();
+            if (user_str != nullptr && pass_str != nullptr) {
+              username = *user_str;
+              password = *pass_str;
+            }
           } else {
             // Openbmc appears to push a data object that contains the same
             // keys (username and password), attempt to use that
@@ -245,56 +249,70 @@
               // "password"]
               if (data_it->is_array()) {
                 if (data_it->size() == 2) {
-                  username = (*data_it)[0].get_ptr<const std::string*>();
-                  password = (*data_it)[1].get_ptr<const std::string*>();
+                  nlohmann::json::iterator user_it2 = data_it->begin();
+                  nlohmann::json::iterator pass_it2 = data_it->begin() + 1;
                   looks_like_ibm = true;
+                  if (user_it2 != data_it->end() &&
+                      pass_it2 != data_it->end()) {
+                    const std::string* user_str =
+                        user_it2->get_ptr<const std::string*>();
+                    const std::string* pass_str =
+                        pass_it2->get_ptr<const std::string*>();
+                    if (user_str != nullptr && pass_str != nullptr) {
+                      username = *user_str;
+                      password = *pass_str;
+                    }
+                  }
                 }
+
               } else if (data_it->is_object()) {
-                auto user_it = data_it->find("username");
-                auto pass_it = data_it->find("password");
-                if (user_it != data_it->end() && pass_it != data_it->end()) {
-                  username = user_it->get_ptr<const std::string*>();
-                  password = pass_it->get_ptr<const std::string*>();
+                nlohmann::json::iterator user_it2 = data_it->find("username");
+                nlohmann::json::iterator pass_it2 = data_it->find("password");
+                if (user_it2 != data_it->end() && pass_it2 != data_it->end()) {
+                  const std::string* user_str =
+                      user_it2->get_ptr<const std::string*>();
+                  const std::string* pass_str =
+                      pass_it2->get_ptr<const std::string*>();
+                  if (user_str != nullptr && pass_str != nullptr) {
+                    username = *user_str;
+                    password = *pass_str;
+                  }
                 }
               }
             }
           }
         } else {
-          // check if auth was provided as a query string
-          auto user_it = req.headers.find("username");
-          auto pass_it = req.headers.find("password");
-          if (user_it != req.headers.end() && pass_it != req.headers.end()) {
-            username = &user_it->second;
-            password = &pass_it->second;
-          }
+          // check if auth was provided as a headers
+          username = req.get_header_value("username");
+          password = req.get_header_value("password");
         }
 
-        if (username != nullptr && !username->empty() && password != nullptr &&
-            !password->empty()) {
-          if (!pam_authenticate_user(*username, *password)) {
-            res.code = res.code = static_cast<int>(HttpRespCode::UNAUTHORIZED);
+        if (!username.empty() && !password.empty()) {
+          if (!pam_authenticate_user(username, password)) {
+            res.result(boost::beast::http::status::unauthorized);
           } else {
-            auto& session =
-                PersistentData::session_store->generate_user_session(*username);
+            auto session =
+                PersistentData::session_store->generate_user_session(username);
 
             if (looks_like_ibm) {
               // IBM requires a very specific login structure, and doesn't
               // actually look at the status code.  TODO(ed).... Fix that
               // upstream
-              res.json_value = {{"data", "User '" + *username + "' logged in"},
-                                {"message", "200 OK"},
-                                {"status", "ok"}};
-              res.add_header("Set-Cookie", "XSRF-TOKEN=" + session.csrf_token);
-              res.add_header("Set-Cookie", "SESSION=" + session.session_token +
+              res.json_value = {
+                  {"data", "User '" + std::string(username) + "' logged in"},
+                  {"message", "200 OK"},
+                  {"status", "ok"}};
+              res.add_header("Set-Cookie", "XSRF-TOKEN=" + session->csrf_token);
+              res.add_header("Set-Cookie", "SESSION=" + session->session_token +
                                                "; Secure; HttpOnly");
             } else {
               // if content type is json, assume json token
-              res.json_value = {{"token", session.session_token}};
+              res.json_value = {{"token", session->session_token}};
             }
           }
 
         } else {
-          res.code = static_cast<int>(HttpRespCode::BAD_REQUEST);
+          res.result(boost::beast::http::status::bad_request);
         }
         res.end();
       });
@@ -308,7 +326,6 @@
             if (session != nullptr) {
               PersistentData::session_store->remove_session(session);
             }
-            res.code = static_cast<int>(HttpRespCode::OK);
             res.end();
             return;
 
diff --git a/include/webassets.hpp b/include/webassets.hpp
index 6384f3a..85de3ad 100644
--- a/include/webassets.hpp
+++ b/include/webassets.hpp
@@ -4,7 +4,6 @@
 #include <fstream>
 #include <string>
 #include <crow/app.h>
-#include <crow/http_codes.h>
 #include <crow/http_request.h>
 #include <crow/http_response.h>
 #include <crow/routing.h>
@@ -88,7 +87,7 @@
 
       auto content_type_it = content_types.find(extension.c_str());
       if (content_type_it == content_types.end()) {
-        CROW_LOG_ERROR << "Cannot determine content-type for " << webpath
+        CROW_LOG_ERROR << "Cannot determine content-type for " << absolute_path
                        << " with extension " << extension;
       } else {
         content_type = content_type_it->second;
@@ -109,13 +108,12 @@
             std::ifstream inf(absolute_path);
             if (!inf) {
               CROW_LOG_DEBUG << "failed to read file";
-              res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
-              res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
+              res.result(boost::beast::http::status::internal_server_error);
               res.end();
               return;
             }
 
-            res.body = {std::istreambuf_iterator<char>(inf),
+            res.body() = {std::istreambuf_iterator<char>(inf),
                         std::istreambuf_iterator<char>()};
             res.end();
           });