Fork of the excellent esp8266-react - https://github.com/rjwats/esp8266-react
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
3.6 KiB

  1. #ifndef Async_Json_Request_Web_Handler_H_
  2. #define Async_Json_Request_Web_Handler_H_
  3. #include <ArduinoJson.h>
  4. #include <ESPAsyncWebServer.h>
  5. #define ASYNC_JSON_REQUEST_DEFAULT_MAX_SIZE 1024
  6. #define ASYNC_JSON_REQUEST_MIMETYPE "application/json"
  7. /*
  8. * Handy little utility for dealing with small JSON request body payloads.
  9. *
  10. * Need to be careful using this as we are somewhat limited by RAM.
  11. *
  12. * Really only of use where there is a determinate payload size.
  13. */
  14. typedef std::function<void(AsyncWebServerRequest* request, JsonDocument& jsonDocument)> JsonRequestCallback;
  15. class AsyncJsonWebHandler : public AsyncWebHandler {
  16. private:
  17. WebRequestMethodComposite _method;
  18. JsonRequestCallback _onRequest;
  19. size_t _maxContentLength;
  20. protected:
  21. String _uri;
  22. public:
  23. AsyncJsonWebHandler() :
  24. _method(HTTP_POST | HTTP_PUT | HTTP_PATCH),
  25. _onRequest(nullptr),
  26. _maxContentLength(ASYNC_JSON_REQUEST_DEFAULT_MAX_SIZE),
  27. _uri() {
  28. }
  29. ~AsyncJsonWebHandler() {
  30. }
  31. void setUri(const String& uri) {
  32. _uri = uri;
  33. }
  34. void setMethod(WebRequestMethodComposite method) {
  35. _method = method;
  36. }
  37. void setMaxContentLength(size_t maxContentLength) {
  38. _maxContentLength = maxContentLength;
  39. }
  40. void onRequest(JsonRequestCallback fn) {
  41. _onRequest = fn;
  42. }
  43. virtual bool canHandle(AsyncWebServerRequest* request) override final {
  44. if (!_onRequest)
  45. return false;
  46. if (!(_method & request->method()))
  47. return false;
  48. if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
  49. return false;
  50. if (!request->contentType().equalsIgnoreCase(ASYNC_JSON_REQUEST_MIMETYPE))
  51. return false;
  52. request->addInterestingHeader("ANY");
  53. return true;
  54. }
  55. virtual void handleRequest(AsyncWebServerRequest* request) override final {
  56. // no request configured
  57. if (!_onRequest) {
  58. Serial.print("No request callback was configured for endpoint: ");
  59. Serial.println(_uri);
  60. request->send(500);
  61. return;
  62. }
  63. // we have been handed too much data, return a 413 (payload too large)
  64. if (request->contentLength() > _maxContentLength) {
  65. request->send(413);
  66. return;
  67. }
  68. // parse JSON and if possible handle the request
  69. if (request->_tempObject) {
  70. DynamicJsonDocument jsonDocument(_maxContentLength);
  71. DeserializationError error = deserializeJson(jsonDocument, (uint8_t*)request->_tempObject);
  72. if (error == DeserializationError::Ok) {
  73. _onRequest(request, jsonDocument);
  74. } else {
  75. request->send(400);
  76. }
  77. return;
  78. }
  79. // fallthrough, we have a null pointer, return 500.
  80. // this can be due to running out of memory or never receiving body data.
  81. request->send(500);
  82. }
  83. virtual void handleBody(AsyncWebServerRequest* request,
  84. uint8_t* data,
  85. size_t len,
  86. size_t index,
  87. size_t total) override final {
  88. if (_onRequest) {
  89. // don't allocate if data is too large
  90. if (total > _maxContentLength) {
  91. return;
  92. }
  93. // try to allocate memory on first call
  94. // NB: the memory allocated here is freed by ~AsyncWebServerRequest
  95. if (index == 0 && !request->_tempObject) {
  96. request->_tempObject = malloc(total);
  97. }
  98. // copy the data into the buffer, if we have a buffer!
  99. if (request->_tempObject) {
  100. memcpy((uint8_t*)request->_tempObject + index, data, len);
  101. }
  102. }
  103. }
  104. virtual bool isRequestHandlerTrivial() override final {
  105. return _onRequest ? false : true;
  106. }
  107. };
  108. #endif // end Async_Json_Request_Web_Handler_H_