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.

120 lines
3.6 KiB

  1. #ifndef Async_Json_Request_Web_Handler_H_
  2. #define Async_Json_Request_Web_Handler_H_
  3. #include <ESPAsyncWebServer.h>
  4. #include <ArduinoJson.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. ~AsyncJsonWebHandler() {}
  29. void setUri(const String& uri) { _uri = uri; }
  30. void setMethod(WebRequestMethodComposite method) { _method = method; }
  31. void setMaxContentLength(size_t maxContentLength) { _maxContentLength = maxContentLength; }
  32. void onRequest(JsonRequestCallback fn) { _onRequest = fn; }
  33. virtual bool canHandle(AsyncWebServerRequest *request) override final {
  34. if(!_onRequest)
  35. return false;
  36. if(!(_method & request->method()))
  37. return false;
  38. if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
  39. return false;
  40. if (!request->contentType().equalsIgnoreCase(ASYNC_JSON_REQUEST_MIMETYPE))
  41. return false;
  42. request->addInterestingHeader("ANY");
  43. return true;
  44. }
  45. virtual void handleRequest(AsyncWebServerRequest *request) override final {
  46. // no request configured
  47. if(!_onRequest) {
  48. Serial.print("No request callback was configured for endpoint: ");
  49. Serial.println(_uri);
  50. request->send(500);
  51. return;
  52. }
  53. // we have been handed too much data, return a 413 (payload too large)
  54. if (request->contentLength() > _maxContentLength) {
  55. request->send(413);
  56. return;
  57. }
  58. // parse JSON and if possible handle the request
  59. if (request->_tempObject) {
  60. DynamicJsonDocument jsonDocument(_maxContentLength);
  61. DeserializationError error = deserializeJson(jsonDocument, (uint8_t *) request->_tempObject);
  62. if (error == DeserializationError::Ok) {
  63. _onRequest(request, jsonDocument);
  64. }else{
  65. request->send(400);
  66. }
  67. return;
  68. }
  69. // fallthrough, we have a null pointer, return 500.
  70. // this can be due to running out of memory or never receiving body data.
  71. request->send(500);
  72. }
  73. virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
  74. if (_onRequest) {
  75. // don't allocate if data is too large
  76. if (total > _maxContentLength){
  77. return;
  78. }
  79. // try to allocate memory on first call
  80. // NB: the memory allocated here is freed by ~AsyncWebServerRequest
  81. if(index == 0 && !request->_tempObject){
  82. request->_tempObject = malloc(total);
  83. }
  84. // copy the data into the buffer, if we have a buffer!
  85. if (request->_tempObject) {
  86. memcpy((uint8_t *) request->_tempObject+index, data, len);
  87. }
  88. }
  89. }
  90. virtual bool isRequestHandlerTrivial() override final {
  91. return _onRequest ? false : true;
  92. }
  93. };
  94. #endif // end Async_Json_Request_Web_Handler_H_