Browse Source

api: streamable string view for json parser

pull/2552/head
Maxim Prokhorov 1 year ago
parent
commit
7b8955341a
2 changed files with 50 additions and 62 deletions
  1. +5
    -62
      code/espurna/api.cpp
  2. +45
    -0
      code/espurna/web_utils.h

+ 5
- 62
code/espurna/api.cpp View File

@ -372,65 +372,6 @@ class ApiJsonWebHandler final : public ApiBaseWebHandler {
public:
static constexpr size_t BufferSize { API_JSON_BUFFER_SIZE };
struct ReadOnlyStream : public Stream {
ReadOnlyStream() = delete;
explicit ReadOnlyStream(const uint8_t* buffer, size_t size) :
_buffer(buffer),
_size(size)
{}
int available() override {
return _size - _index;
}
int peek() override {
if (_index < _size) {
return static_cast<int>(_buffer[_index]);
}
return -1;
}
int read() override {
auto peeked = peek();
if (peeked >= 0) {
++_index;
}
return peeked;
}
// since we are fixed in size, no need for any timeouts and the only available option is to return full chunk of data
size_t readBytes(uint8_t* ptr, size_t size) override {
if ((_index < _size) && ((_size - _index) >= size)) {
std::copy(_buffer + _index, _buffer + _index + size, ptr);
_index += size;
return size;
}
return 0;
}
size_t readBytes(char* ptr, size_t size) override {
return readBytes(reinterpret_cast<uint8_t*>(ptr), size);
}
void flush() override {
}
size_t write(const uint8_t*, size_t) override {
return 0;
}
size_t write(uint8_t) override {
return 0;
}
const uint8_t* _buffer;
const size_t _size;
size_t _index { 0 };
};
ApiJsonWebHandler() = delete;
ApiJsonWebHandler(const ApiJsonWebHandler&) = delete;
ApiJsonWebHandler(ApiJsonWebHandler&&) = delete;
@ -500,10 +441,12 @@ public:
void _handlePut(AsyncWebServerRequest* request, uint8_t* data, size_t size) {
// XXX: arduinojson v5 de-serializer will happily read garbage from raw ptr, since there's no length limit
// this is fixed in v6 though. for now, use a wrapper, but be aware that this actually uses more mem for the jsonbuffer
DynamicJsonBuffer jsonBuffer(BufferSize);
ReadOnlyStream stream(data, size);
auto reader = espurna::StringView(
reinterpret_cast<const char*>(data),
reinterpret_cast<const char*>(data + size));
JsonObject& root = jsonBuffer.parseObject(stream);
DynamicJsonBuffer jsonBuffer(BufferSize);
JsonObject& root = jsonBuffer.parseObject(reader);
if (!root.success()) {
request->send(500);
return;


+ 45
- 0
code/espurna/web_utils.h View File

@ -23,6 +23,51 @@ namespace Internals {
template <>
struct StringTraits<::espurna::StringView, void> {
// c/p from std stream / Stream adapters
// allow to pass the view as-is to the parser
struct Reader {
Reader(espurna::StringView value) :
_value(value),
_it(_value.begin())
{}
void move() {
_current = _next;
_next = '\0';
}
char current() {
if (!_current) {
_current = read();
}
return _current;
}
char next() {
if (!_next) {
_next = read();
}
return _next;
}
private:
char read() {
if (_it != _value.end()) {
const auto c = (*_it);
++_it;
return c;
}
return '\0';
}
espurna::StringView _value;
const char* _it;
char _current = 0;
char _next = 0;
};
template <typename T>
static bool equals(::espurna::StringView lhs, T&& rhs) {
return lhs == rhs;


Loading…
Cancel
Save