Fix content reader for partial input
When there is partial message in reader, popping out the characters lead to parse errors on the subsequent attempt to parse. To avoid this, the last matched characters' index is stored during parsing and reset on error.
This commit is contained in:
parent
e53575d272
commit
77209caf04
@ -44,13 +44,17 @@ void ContentReader::close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string ContentReader::read() {
|
std::string ContentReader::read() {
|
||||||
|
matched_idx = 0;
|
||||||
|
|
||||||
// Find Content-Length header prefix
|
// Find Content-Length header prefix
|
||||||
if (!scan("Content-Length:")) {
|
if (!scan("Content-Length:")) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip whitespace and tabs
|
// Skip whitespace and tabs
|
||||||
while (matchAny(" \t")) {
|
while (matchAny(" \t")) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse length
|
// Parse length
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -68,10 +72,16 @@ std::string ContentReader::read() {
|
|||||||
if (!match("\r\n\r\n")) {
|
if (!match("\r\n\r\n")) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read message
|
// Read message
|
||||||
if (!buffer(len)) {
|
if (!buffer(len + matched_idx)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < matched_idx; i++) {
|
||||||
|
buf.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
std::string out;
|
std::string out;
|
||||||
out.reserve(len);
|
out.reserve(len);
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
@ -97,18 +107,17 @@ bool ContentReader::scan(const char* str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ContentReader::match(const uint8_t* seq, size_t len) {
|
bool ContentReader::match(const uint8_t* seq, size_t len) {
|
||||||
if (!buffer(len)) {
|
if (!buffer(len + matched_idx)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto it = buf.begin();
|
auto it = matched_idx;
|
||||||
for (size_t i = 0; i < len; i++, it++) {
|
for (size_t i = 0; i < len; i++, it++) {
|
||||||
if (*it != seq[i]) {
|
if (buf[it] != seq[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
buf.pop_front();
|
matched_idx += len;
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,12 +127,12 @@ bool ContentReader::match(const char* str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char ContentReader::matchAny(const char* chars) {
|
char ContentReader::matchAny(const char* chars) {
|
||||||
if (!buffer(1)) {
|
if (!buffer(1 + matched_idx)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int c = buf.front();
|
int c = buf[matched_idx];
|
||||||
if (auto p = strchr(chars, c)) {
|
if (auto p = strchr(chars, c)) {
|
||||||
buf.pop_front();
|
matched_idx++;
|
||||||
return *p;
|
return *p;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -47,6 +47,7 @@ class ContentReader {
|
|||||||
|
|
||||||
std::shared_ptr<Reader> reader;
|
std::shared_ptr<Reader> reader;
|
||||||
std::deque<uint8_t> buf;
|
std::deque<uint8_t> buf;
|
||||||
|
uint32_t matched_idx = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContentWriter {
|
class ContentWriter {
|
||||||
|
@ -81,3 +81,19 @@ TEST(ContentStreamTest, ShortRead) {
|
|||||||
ASSERT_EQ(cs.read(), "Content payload number three");
|
ASSERT_EQ(cs.read(), "Content payload number three");
|
||||||
ASSERT_EQ(cs.read(), "");
|
ASSERT_EQ(cs.read(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ContentStreamTest, PartialReadAndParse) {
|
||||||
|
auto sb = std::make_shared<dap::StringBuffer>();
|
||||||
|
dap::ContentReader cs(sb);
|
||||||
|
sb->write("Content");
|
||||||
|
ASSERT_EQ(cs.read(), "");
|
||||||
|
sb->write("-Length: ");
|
||||||
|
ASSERT_EQ(cs.read(), "");
|
||||||
|
sb->write("26");
|
||||||
|
ASSERT_EQ(cs.read(), "");
|
||||||
|
sb->write("\r\n\r\n");
|
||||||
|
ASSERT_EQ(cs.read(), "");
|
||||||
|
sb->write("Content payload number one");
|
||||||
|
ASSERT_EQ(cs.read(), "Content payload number one");
|
||||||
|
ASSERT_EQ(cs.read(), "");
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user