Add StreamReader and rebuild Parser/LineParser/IMFHeader/IMFBoundary on it
Introduces StreamReader to accumulate socket data delivered in arbitrary chunks into one buffer, so a Parser can build an object (a line, a header block, a MIME boundary) that spans any number of packets without losing its place. Parser is redesigned around this: no longer inherits MString (was redundant with its own buffer member), takes a StreamReader&, and drives a resumable COMPLETE/INCOMPLETE/DATA_AVAIL state-machine protocol via doParse(). LineParser, IMFHeader, and IMFBoundary are rewritten as real, working resumable parsers against the shared buffer instead of the previous non-compiling stubs (mismatched constructors/return types, a syntax error, checkParse() never implemented). IMFFormData is left as the stub it already was, just restored to compiling against the new IMFHeader signature - fully wiring it up needs IMFMultipart/IMFText migrated to StreamReader too, out of scope here. Verified with real runtime tests (not just compilation) covering data split mid-line, mid-CRLF, mid-header-fold, and mid-boundary-marker across separate feed() calls, plus StreamReader::compact(). Along the way fixed a header-value bug (space after ':' wasn't skipped) and a double cursor-offset subtraction bug in two places caused by forgetting that ZString::getLength() is already cursor-relative, not the raw buffer size. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
94d4a30e88
commit
a033cc6718
13 files changed
+443
-136
No files matched your search
@@ -0,0 +1,66 @@
|
||||
#ifndef __StreamReader_h__
|
||||
#define __StreamReader_h__
|
||||
|
||||
#include "MString.h"
|
||||
|
||||
namespace coreutils {
|
||||
|
||||
///
|
||||
/// StreamReader accumulates data delivered in arbitrary-sized chunks (e.g. from
|
||||
/// core::Socket::onDataReceived) into one continuous, growable buffer, and exposes
|
||||
/// it to a chain of Parser objects so they can build higher-level protocol objects
|
||||
/// (a header, a line, a MIME part, etc.) without needing to worry about where one
|
||||
/// network packet ended and the next began - a "complete" unit may span any number
|
||||
/// of feed() calls.
|
||||
///
|
||||
/// Parsers consume data through the ZString-style cursor on getBuffer(). Once a
|
||||
/// Parser has fully consumed a unit (advanced the cursor past it), call compact()
|
||||
/// to drop the already-parsed prefix so the buffer doesn't grow unboundedly for the
|
||||
/// life of a long-running connection.
|
||||
///
|
||||
|
||||
class StreamReader {
|
||||
|
||||
public:
|
||||
|
||||
StreamReader();
|
||||
|
||||
///
|
||||
/// Append newly-arrived data to the end of the buffer. Does not affect the
|
||||
/// cursor - existing parse position is preserved across a feed().
|
||||
///
|
||||
|
||||
void feed(ZString &data);
|
||||
|
||||
///
|
||||
/// The accumulated buffer Parsers read from and advance the cursor over.
|
||||
///
|
||||
|
||||
MString &getBuffer();
|
||||
|
||||
///
|
||||
/// Drop the already-parsed prefix (everything before the cursor) and reset
|
||||
/// the cursor to the new start of the buffer. Call this once a Parser has
|
||||
/// completed a unit and before waiting for more data, so the buffer only
|
||||
/// ever grows by the amount of not-yet-parsed data.
|
||||
///
|
||||
|
||||
void compact();
|
||||
|
||||
///
|
||||
/// True if there is unparsed data currently sitting in the buffer that a
|
||||
/// Parser hasn't consumed yet (i.e. more progress may be possible without
|
||||
/// waiting for the next feed()).
|
||||
///
|
||||
|
||||
bool hasUnparsedData();
|
||||
|
||||
private:
|
||||
|
||||
MString buffer;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user