Browse Source

terminal: small workaround for _tempObject from API

Exchange sneaky memory leak with a squeaky wheel...
Web server will immediatly delete the request object, so not really much
point in tracking the pointer via some external means.
mcspr-patch-1
Maxim Prokhorov 4 years ago
parent
commit
e0e5377da7
3 changed files with 44 additions and 34 deletions
  1. +0
    -31
      code/espurna/api.cpp
  2. +31
    -0
      code/espurna/api_impl.h
  3. +13
    -3
      code/espurna/web_asyncwebprint_impl.h

+ 0
- 31
code/espurna/api.cpp View File

@ -268,37 +268,6 @@ bool _apiIsFormDataContent(AsyncWebServerRequest* request) {
return _apiMatchHeader(request, F("Content-Type"), F("application/x-www-form-urlencoded")); return _apiMatchHeader(request, F("Content-Type"), F("application/x-www-form-urlencoded"));
} }
struct ApiRequestHelper {
ApiRequestHelper(const ApiRequestHelper&) = delete;
ApiRequestHelper(ApiRequestHelper&&) noexcept = default;
// &path is expected to be request->url(), which is valid throughout the request's lifetime
explicit ApiRequestHelper(AsyncWebServerRequest& request, const PathParts& pattern) :
_request(request),
_pattern(pattern),
_path(request.url()),
_match(_pattern.match(_path))
{}
ApiRequest request() const {
return ApiRequest(_request, _pattern, _path);
}
const PathParts& parts() const {
return _path;
}
bool match() const {
return _match;
}
private:
AsyncWebServerRequest& _request;
const PathParts& _pattern;
PathParts _path;
bool _match;
};
// Because the webserver request is split between multiple separate function invocations, we need to preserve some state. // Because the webserver request is split between multiple separate function invocations, we need to preserve some state.
// TODO: in case we are dealing with multicore, perhaps enforcing static-size data structs instead of the vector would we better, // TODO: in case we are dealing with multicore, perhaps enforcing static-size data structs instead of the vector would we better,
// to avoid calling generic malloc when paths are parsed? // to avoid calling generic malloc when paths are parsed?


+ 31
- 0
code/espurna/api_impl.h View File

@ -180,3 +180,34 @@ private:
const PathParts& _pattern; const PathParts& _pattern;
const PathParts& _parts; const PathParts& _parts;
}; };
struct ApiRequestHelper {
ApiRequestHelper(const ApiRequestHelper&) = delete;
ApiRequestHelper(ApiRequestHelper&&) noexcept = default;
// &path is expected to be request->url(), which is valid throughout the request's lifetime
explicit ApiRequestHelper(AsyncWebServerRequest& request, const PathParts& pattern) :
_request(request),
_pattern(pattern),
_path(request.url()),
_match(_pattern.match(_path))
{}
ApiRequest request() const {
return ApiRequest(_request, _pattern, _path);
}
const PathParts& parts() const {
return _path;
}
bool match() const {
return _match;
}
private:
AsyncWebServerRequest& _request;
const PathParts& _pattern;
PathParts _path;
bool _match;
};

+ 13
- 3
code/espurna/web_asyncwebprint_impl.h View File

@ -15,7 +15,8 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if WEB_SUPPORT #if WEB_SUPPORT
namespace asyncwebprint_traits {
namespace asyncwebprint {
namespace traits {
template <typename T> template <typename T>
using print_callable_t = decltype(std::declval<T>()(std::declval<Print&>())); using print_callable_t = decltype(std::declval<T>()(std::declval<Print&>()));
@ -23,17 +24,26 @@ using print_callable_t = decltype(std::declval<T>()(std::declval<Print&>()));
template <typename T> template <typename T>
using is_print_callable = is_detected<print_callable_t, T>; using is_print_callable = is_detected<print_callable_t, T>;
}
} }
template<typename CallbackType> template<typename CallbackType>
void AsyncWebPrint::scheduleFromRequest(const AsyncWebPrintConfig& config, AsyncWebServerRequest* request, CallbackType callback) { void AsyncWebPrint::scheduleFromRequest(const AsyncWebPrintConfig& config, AsyncWebServerRequest* request, CallbackType callback) {
static_assert(asyncwebprint_traits::is_print_callable<CallbackType>::value, "CallbackType needs to be a callable with void(Print&)");
static_assert(asyncwebprint::traits::is_print_callable<CallbackType>::value, "CallbackType needs to be a callable with void(Print&)");
// because of async nature of the server, we need to make sure we outlive 'request' object // because of async nature of the server, we need to make sure we outlive 'request' object
auto print = std::shared_ptr<AsyncWebPrint>(new AsyncWebPrint(config, request)); auto print = std::shared_ptr<AsyncWebPrint>(new AsyncWebPrint(config, request));
// attach one ptr to onDisconnect capture, so we can detect disconnection before scheduled function runs // attach one ptr to onDisconnect capture, so we can detect disconnection before scheduled function runs
request->onDisconnect([print]() {
request->onDisconnect([print, request]() {
#if API_SUPPORT
// TODO: in case this comes from `apiRegister`'ed endpoint, there's still a lingering ApiRequestHelper that we must remove
if (request->_tempObject) {
auto* ptr = reinterpret_cast<ApiRequestHelper*>(request->_tempObject);
delete ptr;
request->_tempObject = nullptr;
}
#endif
print->setState(AsyncWebPrint::State::Done); print->setState(AsyncWebPrint::State::Done);
}); });


Loading…
Cancel
Save