Subversion Repositories ESP8266_P1_Meter

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 raymond 1
// SPDX-License-Identifier: LGPL-3.0-or-later
2
// Copyright 2016-2026 Hristo Gochkov, Mathieu Carbou, Emil Muratov, Will Miles
3
 
4
#include "AsyncJson.h"
5
#include "AsyncWebServerLogging.h"
6
 
7
#include <utility>
8
 
9
#if ASYNC_JSON_SUPPORT == 1
10
 
11
// Json content type response classes
12
 
13
#if ARDUINOJSON_VERSION_MAJOR == 5
14
AsyncJsonResponse::AsyncJsonResponse(bool isArray) : _isValid{false} {
15
  _code = 200;
16
  _contentType = asyncsrv::T_application_json;
17
  if (isArray) {
18
    _root = _jsonBuffer.createArray();
19
  } else {
20
    _root = _jsonBuffer.createObject();
21
  }
22
}
23
#elif ARDUINOJSON_VERSION_MAJOR == 6
24
AsyncJsonResponse::AsyncJsonResponse(bool isArray, size_t maxJsonBufferSize) : _jsonBuffer(maxJsonBufferSize), _isValid{false} {
25
  _code = 200;
26
  _contentType = asyncsrv::T_application_json;
27
  if (isArray) {
28
    _root = _jsonBuffer.createNestedArray();
29
  } else {
30
    _root = _jsonBuffer.createNestedObject();
31
  }
32
}
33
#else
34
AsyncJsonResponse::AsyncJsonResponse(bool isArray) : _isValid{false} {
35
  _code = 200;
36
  _contentType = asyncsrv::T_application_json;
37
  if (isArray) {
38
    _root = _jsonBuffer.add<JsonArray>();
39
  } else {
40
    _root = _jsonBuffer.add<JsonObject>();
41
  }
42
}
43
#endif
44
 
45
size_t AsyncJsonResponse::setLength() {
46
#if ARDUINOJSON_VERSION_MAJOR == 5
47
  _contentLength = _root.measureLength();
48
#else
49
  _contentLength = measureJson(_root);
50
#endif
51
  if (_contentLength) {
52
    _isValid = true;
53
  }
54
  return _contentLength;
55
}
56
 
57
size_t AsyncJsonResponse::_fillBuffer(uint8_t *data, size_t len) {
58
  ChunkPrint dest(data, _sentLength, len);
59
#if ARDUINOJSON_VERSION_MAJOR == 5
60
  _root.printTo(dest);
61
#else
62
  serializeJson(_root, dest);
63
#endif
64
  return dest.written();
65
}
66
 
67
#if ARDUINOJSON_VERSION_MAJOR == 6
68
PrettyAsyncJsonResponse::PrettyAsyncJsonResponse(bool isArray, size_t maxJsonBufferSize) : AsyncJsonResponse{isArray, maxJsonBufferSize} {}
69
#else
70
PrettyAsyncJsonResponse::PrettyAsyncJsonResponse(bool isArray) : AsyncJsonResponse{isArray} {}
71
#endif
72
 
73
size_t PrettyAsyncJsonResponse::setLength() {
74
#if ARDUINOJSON_VERSION_MAJOR == 5
75
  _contentLength = _root.measurePrettyLength();
76
#else
77
  _contentLength = measureJsonPretty(_root);
78
#endif
79
  if (_contentLength) {
80
    _isValid = true;
81
  }
82
  return _contentLength;
83
}
84
 
85
size_t PrettyAsyncJsonResponse::_fillBuffer(uint8_t *data, size_t len) {
86
  ChunkPrint dest(data, _sentLength, len);
87
#if ARDUINOJSON_VERSION_MAJOR == 5
88
  _root.prettyPrintTo(dest);
89
#else
90
  serializeJsonPretty(_root, dest);
91
#endif
92
  return dest.written();
93
}
94
 
95
// MessagePack content type response
96
#if ASYNC_MSG_PACK_SUPPORT == 1
97
 
98
size_t AsyncMessagePackResponse::setLength() {
99
  _contentLength = measureMsgPack(_root);
100
  if (_contentLength) {
101
    _isValid = true;
102
  }
103
  return _contentLength;
104
}
105
 
106
size_t AsyncMessagePackResponse::_fillBuffer(uint8_t *data, size_t len) {
107
  ChunkPrint dest(data, _sentLength, len);
108
  serializeMsgPack(_root, dest);
109
  return dest.written();
110
}
111
 
112
#endif
113
 
114
// Body handler supporting both content types: JSON and MessagePack
115
constexpr static WebRequestMethodComposite JsonHandlerMethods =
116
  AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST | AsyncWebRequestMethod::HTTP_PUT | AsyncWebRequestMethod::HTTP_PATCH;
117
 
118
#if ARDUINOJSON_VERSION_MAJOR == 6
119
AsyncCallbackJsonWebHandler::AsyncCallbackJsonWebHandler(AsyncURIMatcher uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize)
120
  : _uri(std::move(uri)),
121
    _method(AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST | AsyncWebRequestMethod::HTTP_PUT | AsyncWebRequestMethod::HTTP_PATCH),
122
    _onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize), _maxContentLength(16384) {}
123
#else
124
AsyncCallbackJsonWebHandler::AsyncCallbackJsonWebHandler(AsyncURIMatcher uri, ArJsonRequestHandlerFunction onRequest)
125
  : _uri(std::move(uri)),
126
    _method(AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST | AsyncWebRequestMethod::HTTP_PUT | AsyncWebRequestMethod::HTTP_PATCH),
127
    _onRequest(onRequest), _maxContentLength(16384) {}
128
#endif
129
 
130
bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest *request) const {
131
  if (!_onRequest || !request->isHTTP() || !_method.matches(request->method())) {
132
    return false;
133
  }
134
 
135
  if (!_uri.matches(request)) {
136
    return false;
137
  }
138
 
139
#if ASYNC_MSG_PACK_SUPPORT == 1
140
  return request->method() == AsyncWebRequestMethod::HTTP_GET || request->contentType().equalsIgnoreCase(asyncsrv::T_application_json)
141
         || request->contentType().equalsIgnoreCase(asyncsrv::T_application_msgpack);
142
#else
143
  return request->method() == AsyncWebRequestMethod::HTTP_GET || request->contentType().equalsIgnoreCase(asyncsrv::T_application_json);
144
#endif
145
}
146
 
147
void AsyncCallbackJsonWebHandler::handleRequest(AsyncWebServerRequest *request) {
148
  if (_onRequest) {
149
    // GET request:
150
    if (request->method() == AsyncWebRequestMethod::HTTP_GET) {
151
      JsonVariant json;
152
      _onRequest(request, json);
153
      return;
154
    }
155
 
156
    // POST / PUT / ... requests:
157
    // check if JSON body is too large, if it is, don't deserialize
158
    if (request->contentLength() > _maxContentLength) {
159
      async_ws_log_w("Content length exceeds maximum allowed");
160
      request->send(413);
161
      return;
162
    }
163
 
164
    if (request->_tempObject == NULL) {
165
      // there is no body
166
      request->send(400);
167
      return;
168
    }
169
 
170
#if ARDUINOJSON_VERSION_MAJOR == 5
171
    DynamicJsonBuffer doc;
172
#elif ARDUINOJSON_VERSION_MAJOR == 6
173
    DynamicJsonDocument doc(this->maxJsonBufferSize);
174
#else
175
    JsonDocument doc;
176
#endif
177
 
178
#if ARDUINOJSON_VERSION_MAJOR == 5
179
    JsonVariant json = doc.parse((const char *)request->_tempObject);
180
    if (json.success()) {
181
      _onRequest(request, json);
182
      return;
183
    }
184
#else
185
    DeserializationError error = request->contentType().equalsIgnoreCase(asyncsrv::T_application_msgpack)
186
                                   ? deserializeMsgPack(doc, (uint8_t *)(request->_tempObject))
187
                                   : deserializeJson(doc, (const char *)request->_tempObject);
188
    if (!error) {
189
      JsonVariant json = doc.as<JsonVariant>();
190
      _onRequest(request, json);
191
      return;
192
    }
193
#endif
194
 
195
    // error parsing the body
196
    request->send(400);
197
  }
198
}
199
 
200
void AsyncCallbackJsonWebHandler::handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
201
  if (_onRequest) {
202
    // ignore callback if size is larger than maxContentLength
203
    if (total > _maxContentLength) {
204
      return;
205
    }
206
 
207
    if (index == 0) {
208
      if (total == 0) {
209
        // If total is 0, it is probably a chunked request without an
210
        // X-Expected-Entity-Length header.  In that case there is
211
        // no way to know the actual length in advance.  The best
212
        // way to handle this would be to use a String instead of
213
        // a fixed-length buffer, but for now we just reject.
214
        async_ws_log_w("AsyncJson cannot handle chunked requests without X-Expected-Entity-Length");
215
        request->abort();
216
        return;
217
      }
218
 
219
      // this check allows request->_tempObject to be initialized from a middleware
220
      if (request->_tempObject == NULL) {
221
        request->_tempObject = calloc(total + 1, sizeof(uint8_t));  // null-terminated string
222
        if (request->_tempObject == NULL) {
223
          async_ws_log_e("Failed to allocate");
224
          request->abort();
225
          return;
226
        }
227
      }
228
    }
229
 
230
    if (request->_tempObject != NULL) {
231
      uint8_t *buffer = (uint8_t *)request->_tempObject;
232
      memcpy(buffer + index, data, len);
233
    }
234
  }
235
}
236
 
237
#endif  // ASYNC_JSON_SUPPORT