mirror of
git://git.psyc.eu/libpsyc
synced 2024-08-15 03:19:02 +00:00
fixes for parsing partial packets
This commit is contained in:
parent
d18187229a
commit
2d8eb96f0d
2 changed files with 89 additions and 36 deletions
|
@ -30,11 +30,13 @@ typedef enum
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
PSYC_PARSE_ERROR_END = -7,
|
PSYC_PARSE_ERROR_END = -9,
|
||||||
PSYC_PARSE_ERROR_METHOD = -6,
|
PSYC_PARSE_ERROR_BODY = -8,
|
||||||
PSYC_PARSE_ERROR_VAR_LEN = -5,
|
PSYC_PARSE_ERROR_METHOD = -7,
|
||||||
PSYC_PARSE_ERROR_VAR_TAB = -4,
|
PSYC_PARSE_ERROR_MOD_NL = -6,
|
||||||
PSYC_PARSE_ERROR_VAR_NAME = -3,
|
PSYC_PARSE_ERROR_MOD_LEN = -5,
|
||||||
|
PSYC_PARSE_ERROR_MOD_TAB = -4,
|
||||||
|
PSYC_PARSE_ERROR_MOD_NAME = -3,
|
||||||
PSYC_PARSE_ERROR_LENGTH = -2,
|
PSYC_PARSE_ERROR_LENGTH = -2,
|
||||||
PSYC_PARSE_ERROR = -1,
|
PSYC_PARSE_ERROR = -1,
|
||||||
PSYC_PARSE_SUCCESS = 0,
|
PSYC_PARSE_SUCCESS = 0,
|
||||||
|
@ -42,13 +44,13 @@ typedef enum
|
||||||
/// Fill another buffer and concatenate it with the end of the current buffer,
|
/// Fill another buffer and concatenate it with the end of the current buffer,
|
||||||
/// from the cursor position to the end.
|
/// from the cursor position to the end.
|
||||||
PSYC_PARSE_INSUFFICIENT = 1,
|
PSYC_PARSE_INSUFFICIENT = 1,
|
||||||
/// Routing variable parsing done.
|
/// Routing modifier parsing done.
|
||||||
/// Operator, name & value contains the respective parts.
|
/// Operator, name & value contains the respective parts.
|
||||||
PSYC_PARSE_ROUTING = 2,
|
PSYC_PARSE_ROUTING = 2,
|
||||||
/// Entity variable parsing done.
|
/// Entity modifier parsing done.
|
||||||
/// Operator, name & value contains the respective parts.
|
/// Operator, name & value contains the respective parts.
|
||||||
PSYC_PARSE_ENTITY = 3,
|
PSYC_PARSE_ENTITY = 3,
|
||||||
/// Entity variable parsing is incomplete.
|
/// Entity modifier parsing is incomplete.
|
||||||
/// Operator & name are complete, value is incomplete.
|
/// Operator & name are complete, value is incomplete.
|
||||||
PSYC_PARSE_ENTITY_INCOMPLETE = 4,
|
PSYC_PARSE_ENTITY_INCOMPLETE = 4,
|
||||||
/// Body parsing done, name contains method, value contains body.
|
/// Body parsing done, name contains method, value contains body.
|
||||||
|
@ -91,6 +93,7 @@ typedef struct
|
||||||
uint8_t flags; ///< flags for the parser, see psycParseFlag
|
uint8_t flags; ///< flags for the parser, see psycParseFlag
|
||||||
psycPart part; ///< part of the packet being parsed currently
|
psycPart part; ///< part of the packet being parsed currently
|
||||||
|
|
||||||
|
size_t routingLength; ///< length of routing part parsed so far
|
||||||
size_t contentParsed; ///< number of bytes parsed from the content so far
|
size_t contentParsed; ///< number of bytes parsed from the content so far
|
||||||
size_t contentLength; ///< expected length of the content
|
size_t contentLength; ///< expected length of the content
|
||||||
psycBool contentLengthFound; ///< is there a length given for this packet?
|
psycBool contentLengthFound; ///< is there a length given for this packet?
|
||||||
|
|
106
src/parser.c
106
src/parser.c
|
@ -133,13 +133,15 @@ inline psycParseRC psyc_parseBinaryValue(psycParseState* state, psycString* valu
|
||||||
if (state->cursor + remaining > state->buffer.length) // is the length larger than this buffer?
|
if (state->cursor + remaining > state->buffer.length) // is the length larger than this buffer?
|
||||||
{
|
{
|
||||||
value->length = state->buffer.length - state->cursor;
|
value->length = state->buffer.length - state->cursor;
|
||||||
|
state->cursor += value->length;
|
||||||
*parsed += value->length;
|
*parsed += value->length;
|
||||||
return PSYC_PARSE_INCOMPLETE;
|
return PSYC_PARSE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
value->length += remaining;
|
value->length = remaining;
|
||||||
state->cursor += remaining;
|
state->cursor += remaining;
|
||||||
*parsed += value->length;
|
*parsed += remaining;
|
||||||
|
assert(*parsed == *length);
|
||||||
|
|
||||||
return PSYC_PARSE_COMPLETE;
|
return PSYC_PARSE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
@ -153,9 +155,13 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
||||||
*oper = *(state->buffer.ptr + state->cursor);
|
*oper = *(state->buffer.ptr + state->cursor);
|
||||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||||
|
|
||||||
if (psyc_parseName(state, name) != PSYC_PARSE_SUCCESS)
|
psycParseRC ret = psyc_parseName(state, name);
|
||||||
return PSYC_PARSE_ERROR_VAR_NAME;
|
if (ret == PSYC_PARSE_ERROR)
|
||||||
|
return PSYC_PARSE_ERROR_MOD_NAME;
|
||||||
|
else if (ret != PSYC_PARSE_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
size_t length = 0;
|
||||||
value->length = 0;
|
value->length = 0;
|
||||||
state->valueLength = 0;
|
state->valueLength = 0;
|
||||||
state->valueParsed = 0;
|
state->valueParsed = 0;
|
||||||
|
@ -170,25 +176,25 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
state->valueLength = 10 * state->valueLength + state->buffer.ptr[state->cursor] - '0';
|
length = 10 * length + state->buffer.ptr[state->cursor] - '0';
|
||||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||||
}
|
}
|
||||||
while (isNumeric(state->buffer.ptr[state->cursor]));
|
while (isNumeric(state->buffer.ptr[state->cursor]));
|
||||||
|
state->valueLength = length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return PSYC_PARSE_ERROR_VAR_LEN;
|
return PSYC_PARSE_ERROR_MOD_LEN;
|
||||||
|
|
||||||
// After the length a TAB follows.
|
// After the length a TAB follows.
|
||||||
if (state->buffer.ptr[state->cursor] != '\t')
|
if (state->buffer.ptr[state->cursor] != '\t')
|
||||||
return PSYC_PARSE_ERROR_VAR_TAB;
|
return PSYC_PARSE_ERROR_MOD_TAB;
|
||||||
|
|
||||||
if (state->buffer.length <= ++(state->cursor)) // Incremented cursor inside length?
|
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INCOMPLETE);
|
||||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
|
||||||
|
|
||||||
if (psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed)) == PSYC_PARSE_INCOMPLETE)
|
ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
|
||||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||||
|
return ret;
|
||||||
|
|
||||||
state->cursor++;
|
|
||||||
return PSYC_PARSE_SUCCESS;
|
return PSYC_PARSE_SUCCESS;
|
||||||
}
|
}
|
||||||
else if (state->buffer.ptr[state->cursor] == '\t') // simple arg
|
else if (state->buffer.ptr[state->cursor] == '\t') // simple arg
|
||||||
|
@ -201,11 +207,11 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
||||||
value->length++;
|
value->length++;
|
||||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||||
}
|
}
|
||||||
state->cursor++;
|
|
||||||
return PSYC_PARSE_SUCCESS;
|
return PSYC_PARSE_SUCCESS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return PSYC_PARSE_ERROR_VAR_TAB;
|
return PSYC_PARSE_ERROR_MOD_TAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -214,7 +220,7 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
||||||
*/
|
*/
|
||||||
psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psycString* value)
|
psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psycString* value)
|
||||||
{
|
{
|
||||||
int ret; // a return value
|
psycParseRC ret; // a return value
|
||||||
size_t pos; // a cursor position
|
size_t pos; // a cursor position
|
||||||
|
|
||||||
// Start position of the current line in the buffer
|
// Start position of the current line in the buffer
|
||||||
|
@ -230,6 +236,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
||||||
case PSYC_PART_RESET: // New packet starts here, reset state.
|
case PSYC_PART_RESET: // New packet starts here, reset state.
|
||||||
state->valueParsed = 0;
|
state->valueParsed = 0;
|
||||||
state->valueLength = 0;
|
state->valueLength = 0;
|
||||||
|
state->routingLength = 0;
|
||||||
state->contentParsed = 0;
|
state->contentParsed = 0;
|
||||||
state->contentLength = 0;
|
state->contentLength = 0;
|
||||||
state->contentLengthFound = 0;
|
state->contentLengthFound = 0;
|
||||||
|
@ -237,12 +244,21 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
||||||
// fall thru
|
// fall thru
|
||||||
|
|
||||||
case PSYC_PART_ROUTING:
|
case PSYC_PART_ROUTING:
|
||||||
|
pos = state->cursor;
|
||||||
|
if (state->routingLength > 0)
|
||||||
|
{
|
||||||
|
if (state->buffer.ptr[state->cursor] != '\n')
|
||||||
|
return PSYC_PARSE_ERROR_MOD_NL;
|
||||||
|
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||||
|
}
|
||||||
|
|
||||||
// Each line of the header starts with a glyph,
|
// Each line of the header starts with a glyph,
|
||||||
// i.e. :_name, -_name +_name etc,
|
// i.e. :_name, -_name +_name etc,
|
||||||
// so just test if the first char is a glyph.
|
// so just test if the first char is a glyph.
|
||||||
if (isGlyph(state->buffer.ptr[state->cursor])) // is the first char a glyph?
|
if (isGlyph(state->buffer.ptr[state->cursor])) // is the first char a glyph?
|
||||||
{ // it is a glyph, so a variable starts here
|
{ // it is a glyph, so a variable starts here
|
||||||
ret = psyc_parseModifier(state, oper, name, value);
|
ret = psyc_parseModifier(state, oper, name, value);
|
||||||
|
state->routingLength += state->cursor - pos;
|
||||||
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ROUTING : ret;
|
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ROUTING : ret;
|
||||||
}
|
}
|
||||||
else // not a glyph
|
else // not a glyph
|
||||||
|
@ -293,7 +309,20 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
||||||
if (state->valueParsed < state->valueLength) {
|
if (state->valueParsed < state->valueLength) {
|
||||||
ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
|
ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
|
||||||
state->contentParsed += value->length;
|
state->contentParsed += value->length;
|
||||||
return ret == PSYC_PARSE_COMPLETE ? PSYC_PARSE_ENTITY : PSYC_PARSE_ENTITY_INCOMPLETE;
|
|
||||||
|
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||||
|
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||||
|
|
||||||
|
return PSYC_PARSE_ENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = state->cursor;
|
||||||
|
|
||||||
|
if (state->contentParsed > 0)
|
||||||
|
{
|
||||||
|
if (state->buffer.ptr[state->cursor] != '\n')
|
||||||
|
return PSYC_PARSE_ERROR_MOD_NL;
|
||||||
|
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each line of the header starts with a glyph,
|
// Each line of the header starts with a glyph,
|
||||||
|
@ -303,31 +332,45 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
||||||
// method does not start with a glyph.
|
// method does not start with a glyph.
|
||||||
if (isGlyph(state->buffer.ptr[state->cursor]))
|
if (isGlyph(state->buffer.ptr[state->cursor]))
|
||||||
{
|
{
|
||||||
pos = state->cursor;
|
|
||||||
ret = psyc_parseModifier(state, oper, name, value);
|
ret = psyc_parseModifier(state, oper, name, value);
|
||||||
state->contentParsed += state->cursor - pos;
|
state->contentParsed += state->cursor - pos;
|
||||||
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ENTITY : ret;
|
|
||||||
|
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||||
|
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||||
|
else if (ret == PSYC_PARSE_SUCCESS)
|
||||||
|
return PSYC_PARSE_ENTITY;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state->part = PSYC_PART_METHOD;
|
state->contentParsed += state->cursor - pos;
|
||||||
state->startc = state->cursor;
|
state->startc = state->cursor;
|
||||||
|
state->part = PSYC_PART_METHOD;
|
||||||
// fall thru
|
// fall thru
|
||||||
}
|
}
|
||||||
|
|
||||||
case PSYC_PART_METHOD:
|
case PSYC_PART_METHOD:
|
||||||
pos = state->cursor;
|
pos = state->cursor;
|
||||||
if (psyc_parseName(state, name) == PSYC_PARSE_SUCCESS)
|
ret = psyc_parseName(state, name);
|
||||||
|
|
||||||
|
if (ret == PSYC_PARSE_INSUFFICIENT)
|
||||||
|
return ret;
|
||||||
|
else if (ret == PSYC_PARSE_SUCCESS)
|
||||||
{ // the method ends with a \n then the data follows
|
{ // the method ends with a \n then the data follows
|
||||||
if (state->buffer.ptr[state->cursor] != '\n')
|
if (state->buffer.ptr[state->cursor] != '\n')
|
||||||
return PSYC_PARSE_ERROR_METHOD;
|
return PSYC_PARSE_ERROR_METHOD;
|
||||||
|
|
||||||
state->cursor++;
|
if (state->contentLengthFound)
|
||||||
state->startc = state->cursor;
|
{ // if length was found set start position to the beginning of data
|
||||||
|
state->cursor++;
|
||||||
|
state->startc = state->cursor;
|
||||||
|
state->part = PSYC_PART_DATA;
|
||||||
|
}
|
||||||
|
else // otherwise keep it at the beginning of method
|
||||||
|
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||||
|
|
||||||
state->contentParsed += state->cursor - pos;
|
state->contentParsed += state->cursor - pos;
|
||||||
state->part = PSYC_PART_DATA;
|
|
||||||
if (state->cursor >= state->buffer.length)
|
|
||||||
return PSYC_PARSE_INSUFFICIENT;
|
|
||||||
// fall thru
|
// fall thru
|
||||||
}
|
}
|
||||||
else // No method, which means the packet should end now.
|
else // No method, which means the packet should end now.
|
||||||
|
@ -343,9 +386,16 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
||||||
|
|
||||||
if (state->contentLengthFound) // We know the length of the packet.
|
if (state->contentLengthFound) // We know the length of the packet.
|
||||||
{
|
{
|
||||||
if (psyc_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_PARSE_INCOMPLETE)
|
if (state->contentParsed < state->contentLength &&
|
||||||
|
psyc_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_PARSE_INCOMPLETE)
|
||||||
return PSYC_PARSE_BODY_INCOMPLETE;
|
return PSYC_PARSE_BODY_INCOMPLETE;
|
||||||
|
|
||||||
|
if (state->cursor >= state->buffer.length)
|
||||||
|
return PSYC_PARSE_BODY;
|
||||||
|
|
||||||
|
if (state->buffer.ptr[state->cursor] != '\n')
|
||||||
|
return PSYC_PARSE_ERROR_BODY;
|
||||||
|
|
||||||
state->cursor++;
|
state->cursor++;
|
||||||
state->part = PSYC_PART_END;
|
state->part = PSYC_PART_END;
|
||||||
return PSYC_PARSE_BODY;
|
return PSYC_PARSE_BODY;
|
||||||
|
@ -385,7 +435,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
||||||
return PSYC_PARSE_INSUFFICIENT;
|
return PSYC_PARSE_INSUFFICIENT;
|
||||||
|
|
||||||
if (state->buffer.ptr[state->cursor] == '|' &&
|
if (state->buffer.ptr[state->cursor] == '|' &&
|
||||||
state->buffer.ptr[state->cursor+1] == '\n') // packet ends here
|
state->buffer.ptr[state->cursor+1] == '\n') // packet ends here
|
||||||
{
|
{
|
||||||
state->cursor += 2;
|
state->cursor += 2;
|
||||||
state->part = PSYC_PART_RESET;
|
state->part = PSYC_PART_RESET;
|
||||||
|
@ -414,7 +464,7 @@ psycParseListRC psyc_parseList(psycParseListState* state, psycString *name, psyc
|
||||||
if (!state->type) // If type is not set we're at the start
|
if (!state->type) // If type is not set we're at the start
|
||||||
{
|
{
|
||||||
if (name->length < 5 || memcmp(name->ptr, "_list", 5) != 0 ||
|
if (name->length < 5 || memcmp(name->ptr, "_list", 5) != 0 ||
|
||||||
(name->length > 5 && name->ptr[5] != '_')) // name should be _list or should start with _list_
|
(name->length > 5 && name->ptr[5] != '_')) // name should be _list or should start with _list_
|
||||||
return PSYC_PARSE_LIST_ERROR_NAME;
|
return PSYC_PARSE_LIST_ERROR_NAME;
|
||||||
|
|
||||||
// First character is either | for text lists, or a number for binary lists
|
// First character is either | for text lists, or a number for binary lists
|
||||||
|
|
Loading…
Reference in a new issue