Skip to content

Commit

Permalink
Feature: Check for out of memory situations when sending json responses
Browse files Browse the repository at this point in the history
Also shows a nice message in the frontend if an internal error occours
  • Loading branch information
tbnobody committed Apr 5, 2024
1 parent 2e3125f commit 980e847
Show file tree
Hide file tree
Showing 26 changed files with 171 additions and 229 deletions.
1 change: 1 addition & 0 deletions include/WebApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class WebApiClass {
static void writeConfig(JsonVariant& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!");

static bool parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, JsonDocument& json_document);
static bool sendJsonResponse(AsyncWebServerRequest* request, AsyncJsonResponse* response, const char* function, const uint16_t line);

private:
AsyncWebServer _server;
Expand Down
1 change: 1 addition & 0 deletions include/WebApi_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ enum WebApiError {
GenericParseError,
GenericValueMissing,
GenericWriteFailed,
GenericInternalServerError,

DtuBase = 2000,
DtuSerialZero,
Expand Down
27 changes: 23 additions & 4 deletions src/WebApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
#include "WebApi.h"
#include "Configuration.h"
#include "MessageOutput.h"
#include "defaults.h"
#include <AsyncJson.h>

Expand Down Expand Up @@ -93,8 +94,7 @@ bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResp
if (!request->hasParam("data", true)) {
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return false;
}

Expand All @@ -103,12 +103,31 @@ bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResp
if (error) {
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return false;
}

return true;
}

bool WebApiClass::sendJsonResponse(AsyncWebServerRequest* request, AsyncJsonResponse* response, const char* function, const uint16_t line)
{
bool ret_val = true;
if (response->overflowed()) {
auto& root = response->getRoot();

root.clear();
root["message"] = String("500 Internal Server Error: ") + function + ", " + line;
root["code"] = WebApiError::GenericInternalServerError;
root["type"] = "danger";
response->setCode(500);
MessageOutput.printf("WebResponse failed: %s, %d\r\n", function, line);
ret_val = false;
}

response->setLength();
request->send(response);
return ret_val;
}

WebApiClass WebApi;
12 changes: 4 additions & 8 deletions src/WebApi_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,22 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
if (!(root.containsKey("delete"))) {
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

if (root["delete"].as<bool>() == false) {
retMsg["message"] = "Not deleted anything!";
retMsg["code"] = WebApiError::ConfigNotDeleted;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

retMsg["type"] = "success";
retMsg["message"] = "Configuration resettet. Rebooting now...";
retMsg["code"] = WebApiError::ConfigSuccess;

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);

Utils::removeAllFiles();
Utils::restartDtu();
Expand Down Expand Up @@ -110,8 +107,7 @@ void WebApiConfigClass::onConfigListGet(AsyncWebServerRequest* request)
}
file.close();

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}

void WebApiConfigClass::onConfigUploadFinish(AsyncWebServerRequest* request)
Expand Down
12 changes: 4 additions & 8 deletions src/WebApi_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
led["brightness"] = config.Led_Single[i].Brightness;
}

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}

void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
Expand All @@ -108,17 +107,15 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|| root.containsKey("display"))) {
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

if (root["curPin"]["name"].as<String>().length() == 0 || root["curPin"]["name"].as<String>().length() > DEV_MAX_MAPPING_NAME_STRLEN) {
retMsg["message"] = "Pin mapping must between 1 and " STR(DEV_MAX_MAPPING_NAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::HardwarePinMappingLength;
retMsg["param"]["max"] = DEV_MAX_MAPPING_NAME_STRLEN;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

Expand Down Expand Up @@ -149,8 +146,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)

WebApi.writeConfig(retMsg);

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);

if (performRestart) {
Utils::restartDtu();
Expand Down
3 changes: 1 addition & 2 deletions src/WebApi_devinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,5 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
root["fw_build_datetime"] = inv->DevInfo()->getFwBuildDateTimeStr();
}

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}
27 changes: 9 additions & 18 deletions src/WebApi_dtu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request)
obj["freq_legal_max"] = definition.definition.Freq_Legal_Max;
}

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}

void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
Expand All @@ -99,8 +98,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
&& root.containsKey("cmt_country"))) {
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

Expand All @@ -110,40 +108,35 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
if (serial == 0) {
retMsg["message"] = "Serial cannot be zero!";
retMsg["code"] = WebApiError::DtuSerialZero;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

if (root["pollinterval"].as<uint32_t>() == 0) {
retMsg["message"] = "Poll interval must be greater zero!";
retMsg["code"] = WebApiError::DtuPollZero;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

if (root["nrf_palevel"].as<uint8_t>() > 3) {
retMsg["message"] = "Invalid power level setting!";
retMsg["code"] = WebApiError::DtuInvalidPowerLevel;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

if (root["cmt_palevel"].as<int8_t>() < -10 || root["cmt_palevel"].as<int8_t>() > 20) {
retMsg["message"] = "Invalid power level setting!";
retMsg["code"] = WebApiError::DtuInvalidPowerLevel;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

if (root["cmt_country"].as<uint8_t>() >= CountryModeId_t::CountryModeId_Max) {
retMsg["message"] = "Invalid country setting!";
retMsg["code"] = WebApiError::DtuInvalidCmtCountry;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

Expand All @@ -156,8 +149,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::DtuInvalidCmtFrequency;
retMsg["param"]["min"] = FrequencyDefinition.Freq_Min;
retMsg["param"]["max"] = FrequencyDefinition.Freq_Max;
response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}

Expand All @@ -172,8 +164,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)

WebApi.writeConfig(retMsg);

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);

_applyDataTask.enable();
_applyDataTask.restart();
Expand Down
3 changes: 1 addition & 2 deletions src/WebApi_eventlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,5 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
}
}

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}
6 changes: 2 additions & 4 deletions src/WebApi_gridprofile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ void WebApiGridProfileClass::onGridProfileStatus(AsyncWebServerRequest* request)
}
}

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}

void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request)
Expand All @@ -83,6 +82,5 @@ void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request
copyArray(&data[0], data.size(), raw);
}

response->setLength();
request->send(response);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}
Loading

0 comments on commit 980e847

Please sign in to comment.