Allow logged in users to upload incrementally
There are use cases where logged in users might want to upload a large
file over a slow connection, and would exceed the 60 second timeout that
bmcweb has. This commit would theoretically allow the user timer to be
per-segment, allowing very long timeouts in the case of slow
connections, so long as some progress was made within the 15 second
window, which seems reasonable.
If user authentication is disabled then there is no user session active
in this case timer will be refreshed as long as progress was made.
This seems like a better alternative compared to setting a very long
(5-20 minute) timeout.
Testing:
- Loaded image on the system
$ curl -k -H 'X-Auth-Token: <token>' -H 'Content-Type: application/octet-stream' -X POST -T ./obmc-phosphor-image-p10bmc.ext4.mmc.tar https://${bmc}:443/redfish/v1/UpdateService/update
{
"@odata.id": "/redfish/v1/TaskService/Tasks/0",
"@odata.type": "#Task.v1_4_3.Task",
"Id": "0",
"TaskState": "Running",
"TaskStatus": "OK"
}
- Tested image load using disable authentication and insecure http
connections.
- Ran few querries and those are fine.
* curl -s -k https://${bmc}:443/redfish/v1/Managers
* curl -s -k https://${bmc}:443/redfish/v1/Managers/bmc
* curl -s -k https://${bmc}:443/redfish/v1/AccountService/Accounts
* curl -s -k https://${bmc}:443/redfish/v1/Systems/system
* curl -s -k https://${bmc}:443/redfish/v1/Chassis/chassis
* curl -s -k https://${bmc}:443/redfish/v1/AccountService/LDAP/Certificates
* curl -k -X POST https://${bmc}:443/redfish/v1/AccountService/Accounts -d '{"UserName": "user99", "Password": "pass123", "RoleId": "Administrator"}'
* curl -k https://${bmc}:443/redfish/v1/AccountService/Accounts/user99
* curl -k -X DELETE https://${bmc}:443/redfish/v1/AccountService/Accounts/user99
* curl -k -H 'Content-Type: application/json' -X POST https://${bmc}:443/login -d '{"username" : "admin", "password" : "newpas1"}'
* curl -k -H 'X-Auth-Token: ' -X PATCH https://${bmc}:443/redfish/v1/AccountService/Accounts/admin -d '{"Password":"newpas2"}'
* curl -k -H 'X-Auth-Token: ' -X POST https://${bmc}:443/logout
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I579c86defdd199c140891a986d70ae2eca63b2aa
Signed-off-by: Ninad Palsule <ninadpalsule@us.ibm.com>
diff --git a/http/http_connection.hpp b/http/http_connection.hpp
index 2c921b5..0daf665 100644
--- a/http/http_connection.hpp
+++ b/http/http_connection.hpp
@@ -490,6 +490,12 @@
}
#endif // BMCWEB_INSECURE_DISABLE_AUTHX
+ if (parser->is_done())
+ {
+ handle();
+ return;
+ }
+
doRead();
});
}
@@ -498,13 +504,14 @@
{
BMCWEB_LOG_DEBUG << this << " doRead";
startDeadline();
- boost::beast::http::async_read(adaptor, buffer, *parser,
- [this, self(shared_from_this())](
- const boost::system::error_code& ec,
- std::size_t bytesTransferred) {
- BMCWEB_LOG_DEBUG << this << " async_read " << bytesTransferred
+ boost::beast::http::async_read_some(
+ adaptor, buffer, *parser,
+ [this,
+ self(shared_from_this())](const boost::system::error_code& ec,
+ std::size_t bytesTransferred) {
+ BMCWEB_LOG_DEBUG << this << " async_read_some " << bytesTransferred
<< " Bytes";
- cancelDeadlineTimer();
+
if (ec)
{
BMCWEB_LOG_ERROR << this
@@ -513,8 +520,23 @@
BMCWEB_LOG_DEBUG << this << " from read(1)";
return;
}
+
+ // If the user is logged in, allow them to send files incrementally
+ // one piece at a time. If authentication is disabled then there is
+ // no user session hence always allow to send one piece at a time.
+ if (userSession != nullptr)
+ {
+ cancelDeadlineTimer();
+ }
+ if (!parser->is_done())
+ {
+ doRead();
+ return;
+ }
+
+ cancelDeadlineTimer();
handle();
- });
+ });
}
void doWrite(crow::Response& thisRes)
@@ -567,22 +589,19 @@
void startDeadline()
{
- cancelDeadlineTimer();
+ // Timer is already started so no further action is required.
+ if (timerStarted)
+ {
+ return;
+ }
std::chrono::seconds timeout(15);
- // allow slow uploads for logged in users
- bool loggedIn = userSession != nullptr;
- if (loggedIn)
- {
- timeout = std::chrono::seconds(60);
- }
std::weak_ptr<Connection<Adaptor, Handler>> weakSelf = weak_from_this();
timer.expires_after(timeout);
timer.async_wait([weakSelf](const boost::system::error_code ec) {
// Note, we are ignoring other types of errors here; If the timer
// failed for any reason, we should still close the connection
-
std::shared_ptr<Connection<Adaptor, Handler>> self =
weakSelf.lock();
if (!self)
@@ -590,6 +609,9 @@
BMCWEB_LOG_CRITICAL << self << " Failed to capture connection";
return;
}
+
+ self->timerStarted = false;
+
if (ec == boost::asio::error::operation_aborted)
{
// Canceled wait means the path succeeeded.
@@ -605,6 +627,7 @@
self->close();
});
+ timerStarted = true;
BMCWEB_LOG_DEBUG << this << " timer started";
}
@@ -632,6 +655,8 @@
bool keepAlive = true;
+ bool timerStarted = false;
+
std::function<std::string()>& getCachedDateStr;
using std::enable_shared_from_this<