Skip to content

Commit 70a15fe

Browse files
Merge pull request #184 from ayavilevich/main
fix Invalid JSON desearilaztion beyond buffer end
2 parents 40083c9 + 426aea1 commit 70a15fe

File tree

3 files changed

+62
-26
lines changed

3 files changed

+62
-26
lines changed

examples/Json/Json.ino

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,27 @@ void setup() {
6363
JsonObject root = doc.to<JsonObject>();
6464
root["foo"] = "bar";
6565
serializeJson(root, *response);
66+
Serial.println();
6667
request->send(response);
6768
});
6869

6970
// curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/json2
7071
// curl -v -X PUT -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/json2
72+
//
73+
// edge cases:
74+
//
75+
// curl -v -X POST -H "Content-Type: application/json" -d "1234" -H "Content-Length: 5" http://192.168.4.1/json2 => rx timeout
76+
// curl -v -X POST -H "Content-Type: application/json" -d "1234" -H "Content-Length: 2" http://192.168.4.1/json2 => 12
77+
// curl -v -X POST -H "Content-Type: application/json" -d "1234" -H "Content-Length: 4" http://192.168.4.1/json2 => 1234
78+
// curl -v -X POST -H "Content-Type: application/json" -d "1234" -H "Content-Length: 10" http://192.168.4.1/json2 => rx timeout
79+
// curl -v -X POST -H "Content-Type: application/json" -d "12345678" -H "Content-Length: 8" http://192.168.4.1/json2 => 12345678
80+
// curl -v -X POST -H "Content-Type: application/json" -d "123456789" -H "Content-Length: 8" http://192.168.4.1/json2 => 12345678
81+
// curl -v -X POST -H "Content-Type: application/json" -d "123456789" -H "Content-Length: 9" http://192.168.4.1/json2 => 413: Content length exceeds maximum allowed
82+
handler->setMaxContentLength(8);
7183
handler->setMethod(HTTP_POST | HTTP_PUT);
7284
handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) {
7385
serializeJson(json, Serial);
86+
Serial.println();
7487
AsyncJsonResponse *response = new AsyncJsonResponse();
7588
JsonObject root = response->getRoot().to<JsonObject>();
7689
root["hello"] = json.as<JsonObject>()["name"];

src/AsyncJson.cpp

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -113,53 +113,77 @@ bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest *request) cons
113113

114114
void AsyncCallbackJsonWebHandler::handleRequest(AsyncWebServerRequest *request) {
115115
if (_onRequest) {
116+
// GET request:
116117
if (request->method() == HTTP_GET) {
117118
JsonVariant json;
118119
_onRequest(request, json);
119120
return;
120-
} else if (request->_tempObject != NULL) {
121+
}
122+
123+
// POST / PUT / ... requests:
124+
// check if JSON body is too large, if it is, don't deserialize
125+
if (request->contentLength() > _maxContentLength) {
126+
#ifdef ESP32
127+
log_e("Content length exceeds maximum allowed");
128+
#endif
129+
request->send(413);
130+
return;
131+
}
132+
133+
if (request->_tempObject == NULL) {
134+
// there is no body
135+
request->send(400);
136+
return;
137+
}
121138

122139
#if ARDUINOJSON_VERSION_MAJOR == 5
123-
DynamicJsonBuffer jsonBuffer;
124-
JsonVariant json = jsonBuffer.parse((uint8_t *)(request->_tempObject));
125-
if (json.success()) {
140+
DynamicJsonBuffer jsonBuffer;
141+
JsonVariant json = jsonBuffer.parse((const char *)request->_tempObject);
142+
if (json.success()) {
126143
#elif ARDUINOJSON_VERSION_MAJOR == 6
127-
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
128-
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
129-
if (!error) {
130-
JsonVariant json = jsonBuffer.as<JsonVariant>();
144+
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
145+
DeserializationError error = deserializeJson(jsonBuffer, (const char *)request->_tempObject);
146+
if (!error) {
147+
JsonVariant json = jsonBuffer.as<JsonVariant>();
131148
#else
132-
JsonDocument jsonBuffer;
133-
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
134-
if (!error) {
135-
JsonVariant json = jsonBuffer.as<JsonVariant>();
149+
JsonDocument jsonBuffer;
150+
DeserializationError error = deserializeJson(jsonBuffer, (const char *)request->_tempObject);
151+
if (!error) {
152+
JsonVariant json = jsonBuffer.as<JsonVariant>();
136153
#endif
137154

138-
_onRequest(request, json);
139-
return;
140-
}
155+
_onRequest(request, json);
156+
} else {
157+
// error parsing the body
158+
request->send(400);
141159
}
142-
request->send(_contentLength > _maxContentLength ? 413 : 400);
143-
} else {
144-
request->send(500);
145160
}
146161
}
147162

148163
void AsyncCallbackJsonWebHandler::handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
149164
if (_onRequest) {
150-
_contentLength = total;
151-
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) {
152-
request->_tempObject = malloc(total);
165+
// ignore callback if size is larger than maxContentLength
166+
if (total > _maxContentLength) {
167+
return;
168+
}
169+
170+
if (index == 0) {
171+
// this check allows request->_tempObject to be initialized from a middleware
153172
if (request->_tempObject == NULL) {
173+
request->_tempObject = calloc(total + 1, sizeof(uint8_t)); // null-terminated string
174+
if (request->_tempObject == NULL) {
154175
#ifdef ESP32
155-
log_e("Failed to allocate");
176+
log_e("Failed to allocate");
156177
#endif
157-
request->abort();
158-
return;
178+
request->abort();
179+
return;
180+
}
159181
}
160182
}
183+
161184
if (request->_tempObject != NULL) {
162-
memcpy((uint8_t *)(request->_tempObject) + index, data, len);
185+
uint8_t *buffer = (uint8_t *)request->_tempObject;
186+
memcpy(buffer + index, data, len);
163187
}
164188
}
165189
}

src/AsyncJson.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
7979
String _uri;
8080
WebRequestMethodComposite _method;
8181
ArJsonRequestHandlerFunction _onRequest;
82-
size_t _contentLength;
8382
#if ARDUINOJSON_VERSION_MAJOR == 6
8483
size_t maxJsonBufferSize;
8584
#endif

0 commit comments

Comments
 (0)