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.

115 lines
3.4 KiB

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