mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 22:02:17 +01:00
fix: never write past a JSON buffer or send a broken socket event
When something didn't fit, the formatters skipped it silently, closing brackets included, and clients got malformed JSON. Two writes could also go past the buffer: - AsyncJsonResp flushed when full and then wrote the value without checking again, so a value bigger than the whole buffer overflowed. It is now streamed straight out instead. - JsonSockEvent::closeEvent added the closing ] when only one byte was left, putting the terminator one byte past the buffer. The formatters now set an overflowed() flag and log an error, and a socket event that overflowed is logged and not sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b2294ced34
commit
8881289b1d
4 changed files with 61 additions and 6 deletions
|
|
@ -8,18 +8,25 @@ void JsonSockEvent::beginEvent(AsyncWebSocket *server, const char *evt, char *bu
|
|||
this->buffSize = buffSize;
|
||||
this->_nocomma = true;
|
||||
this->_closed = false;
|
||||
this->_overflow = false;
|
||||
snprintf(this->buff, buffSize, "42[%s,", evt);
|
||||
}
|
||||
void JsonSockEvent::closeEvent() {
|
||||
if(!this->_closed) {
|
||||
if(strlen(this->buff) < buffSize) strcat(this->buff, "]");
|
||||
else this->buff[buffSize - 1] = ']';
|
||||
// The ] and the terminator both have to fit.
|
||||
if(strlen(this->buff) + 1 < buffSize) strcat(this->buff, "]");
|
||||
else this->_overflow = true;
|
||||
}
|
||||
this->_nocomma = true;
|
||||
this->_closed = true;
|
||||
}
|
||||
void JsonSockEvent::endEvent(uint32_t clientId) {
|
||||
this->closeEvent();
|
||||
// Part of it is missing so clients would only fail to parse it.
|
||||
if(this->_overflow) {
|
||||
ESP_LOGE(TAG, "Socket event too large for %u bytes, not sent: %.32s", (unsigned)this->buffSize, this->buff);
|
||||
return;
|
||||
}
|
||||
if(clientId == 0) this->server->textAll(this->buff);
|
||||
else this->server->text(clientId, this->buff);
|
||||
}
|
||||
|
|
@ -27,7 +34,7 @@ void JsonSockEvent::_safecat(const char *val, bool escape) {
|
|||
size_t len = (escape ? this->calcEscapedLength(val) : strlen(val)) + strlen(this->buff);
|
||||
if(escape) len += 2;
|
||||
if(len >= this->buffSize) {
|
||||
ESP_LOGE(TAG, "Socket exceeded buffer size %d - %d: %s", this->buffSize, len, this->buff);
|
||||
this->_overflow = true;
|
||||
return;
|
||||
}
|
||||
if(escape) strcat(this->buff, "\"");
|
||||
|
|
@ -42,6 +49,7 @@ void AsyncJsonResp::beginResponse(AsyncWebServerRequest *request, char *buff, si
|
|||
this->buff[0] = 0x00;
|
||||
this->_nocomma = true;
|
||||
this->_headersSent = false;
|
||||
this->_overflow = false;
|
||||
this->_stream = request->beginResponseStream("application/json");
|
||||
}
|
||||
void AsyncJsonResp::endResponse() {
|
||||
|
|
@ -57,10 +65,28 @@ void AsyncJsonResp::flush() {
|
|||
}
|
||||
}
|
||||
void AsyncJsonResp::_safecat(const char *val, bool escape) {
|
||||
size_t len = (escape ? this->calcEscapedLength(val) : strlen(val)) + strlen(this->buff);
|
||||
if(escape) len += 2;
|
||||
if(len >= this->buffSize) {
|
||||
const size_t vlen = escape ? this->calcEscapedLength(val) + 2 : strlen(val);
|
||||
if(vlen + strlen(this->buff) >= this->buffSize) {
|
||||
this->flush();
|
||||
if(vlen + strlen(this->buff) >= this->buffSize) {
|
||||
// Bigger than the whole buffer so stream it straight out.
|
||||
if(!this->_stream) {
|
||||
this->_overflow = true;
|
||||
return;
|
||||
}
|
||||
if(!escape) {
|
||||
this->_stream->print(val);
|
||||
return;
|
||||
}
|
||||
char esc[7];
|
||||
this->_stream->print("\"");
|
||||
for(size_t i = 0; val[i]; i++) {
|
||||
escapeChar(val[i], esc);
|
||||
this->_stream->print(esc);
|
||||
}
|
||||
this->_stream->print("\"");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(escape) strcat(this->buff, "\"");
|
||||
if(escape) this->escapeString(val, &this->buff[strlen(this->buff)]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue