You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kg...@apache.org on 2019/09/06 12:32:50 UTC
[qpid-dispatch] 01/02: DISPATCH-1394: Fix qd_message_check() to
detect truncated message headers
This is an automated email from the ASF dual-hosted git repository.
kgiusti pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git
commit 2876ccd736da700d8d03739cd85e5c8d495f2391
Author: Kenneth Giusti <kg...@apache.org>
AuthorDate: Wed Aug 21 14:11:50 2019 -0400
DISPATCH-1394: Fix qd_message_check() to detect truncated message headers
This closes #557
---
include/qpid/dispatch/message.h | 11 +-
src/message.c | 421 ++++++++++++++---------
src/python_embedded.c | 2 +-
src/router_core/exchange_bindings.c | 2 +-
src/router_core/modules/edge_router/addr_proxy.c | 2 +-
src/router_node.c | 13 +-
tests/message_test.c | 337 ++++++++++++++++--
tests/run_unit_tests_size.c | 5 +
8 files changed, 579 insertions(+), 214 deletions(-)
diff --git a/include/qpid/dispatch/message.h b/include/qpid/dispatch/message.h
index 26ddb4b..0d669c4 100644
--- a/include/qpid/dispatch/message.h
+++ b/include/qpid/dispatch/message.h
@@ -232,8 +232,17 @@ void qd_message_send(qd_message_t *msg, qd_link_t *link, bool strip_outbound_ann
/**
* Check that the message is well-formed up to a certain depth. Any part of the message that is
* beyond the specified depth is not checked for validity.
+ *
+ * Note: some message sections are optional - QD_MESSAGE_OK is returned if the
+ * optional section is not present, as that is valid.
*/
-int qd_message_check(qd_message_t *msg, qd_message_depth_t depth);
+typedef enum {
+ QD_MESSAGE_DEPTH_INVALID, // corrupt or malformed message detected
+ QD_MESSAGE_DEPTH_OK, // valid up to depth, including 'depth' if not optional
+ QD_MESSAGE_DEPTH_INCOMPLETE // have not received up to 'depth', or partial depth
+} qd_message_depth_status_t;
+
+qd_message_depth_status_t qd_message_check_depth(const qd_message_t *msg, qd_message_depth_t depth);
/**
* Return an iterator for the requested message field. If the field is not in the message,
diff --git a/src/message.c b/src/message.c
index ddc49bb..0325c14 100644
--- a/src/message.c
+++ b/src/message.c
@@ -69,6 +69,18 @@ static const unsigned char * const TAGS_ANY = (unsigned char
"\xa1\xb1\xa3\xb3\xe0\xf0"
"\x40\x56\x41\x42\x50\x60\x70\x52\x43\x80\x53\x44\x51\x61\x71\x54\x81\x55\x72\x82\x74\x84\x94\x73\x83\x98";
+
+static const char * const section_names[QD_DEPTH_ALL + 1] = {
+ [QD_DEPTH_NONE] = "none",
+ [QD_DEPTH_HEADER] = "header",
+ [QD_DEPTH_DELIVERY_ANNOTATIONS] = "delivery annotations",
+ [QD_DEPTH_MESSAGE_ANNOTATIONS] = "message annotations",
+ [QD_DEPTH_PROPERTIES] = "properties",
+ [QD_DEPTH_APPLICATION_PROPERTIES] = "application properties",
+ [QD_DEPTH_BODY] = "body",
+ [QD_DEPTH_ALL] = "footer"
+};
+
PN_HANDLE(PN_DELIVERY_CTX)
ALLOC_DEFINE_CONFIG(qd_message_t, sizeof(qd_message_pvt_t), 0, 0);
@@ -328,7 +340,9 @@ static void print_field(
static const char REPR_END[] = "}\0";
char* qd_message_repr(qd_message_t *msg, char* buffer, size_t len, qd_log_bits flags) {
- if (flags == 0 || !qd_message_check(msg, QD_DEPTH_APPLICATION_PROPERTIES)) {
+ if (flags == 0
+ || qd_message_check_depth(msg, QD_DEPTH_APPLICATION_PROPERTIES) != QD_MESSAGE_DEPTH_OK
+ || !((qd_message_pvt_t *)msg)->content->section_application_properties.parsed) {
return NULL;
}
char *begin = buffer;
@@ -357,20 +371,22 @@ char* qd_message_repr(qd_message_t *msg, char* buffer, size_t len, qd_log_bits f
/**
* Advance cursor through buffer chain by 'consume' bytes.
* Cursor and buffer args are advanced to point to new position in buffer chain.
- * - if the number of bytes in the buffer chain is less than or equal to
- * the consume number then return a null buffer and cursor.
+ * - if the number of bytes in the buffer chain is less than or equal to
+ * the consume number then set *cursor and *buffer to NULL and
+ * return the number of missing bytes
* - the original buffer chain is not changed or freed.
*
* @param cursor Pointer into current buffer content
* @param buffer pointer to current buffer
* @param consume number of bytes to advance
+ * @return 0 if all bytes consumed, != 0 if not enough bytes available
*/
-static void advance(unsigned char **cursor, qd_buffer_t **buffer, int consume)
+static int advance(unsigned char **cursor, qd_buffer_t **buffer, int consume)
{
unsigned char *local_cursor = *cursor;
qd_buffer_t *local_buffer = *buffer;
- int remaining = qd_buffer_size(local_buffer) - (local_cursor - qd_buffer_base(local_buffer));
+ int remaining = qd_buffer_cursor(local_buffer) - local_cursor;
while (consume > 0) {
if (consume < remaining) {
local_cursor += consume;
@@ -383,12 +399,14 @@ static void advance(unsigned char **cursor, qd_buffer_t **buffer, int consume)
break;
}
local_cursor = qd_buffer_base(local_buffer);
- remaining = qd_buffer_size(local_buffer) - (local_cursor - qd_buffer_base(local_buffer));
+ remaining = qd_buffer_size(local_buffer);
}
}
*cursor = local_cursor;
*buffer = local_buffer;
+
+ return consume;
}
@@ -556,33 +574,47 @@ static int start_list(unsigned char **cursor, qd_buffer_t **buffer)
}
+// Validate a message section (header, body, etc). This determines whether or
+// not a given section is present and complete at the start of the buffer chain.
+//
+// The section is identified by a 'pattern' (a descriptor identifier, such as
+// "MESSAGE_ANNOTATION_LONG" above). The descriptor also provides a type
+// 'tag', which MUST match else the section is invalid.
//
-// Check the buffer chain, starting at cursor to see if it matches the pattern.
-// If the pattern matches, check the next tag to see if it's in the set of expected
-// tags. If not, return zero. If so, set the location descriptor to the good
-// tag and advance the cursor (and buffer, if needed) to the end of the matched section.
+// Non-Body message sections are optional. So if the pattern does NOT match
+// then the section that the pattern represents is not present. Whether or not
+// this is acceptable is left to the caller.
//
-// If there is no match, don't advance the cursor.
+// If the pattern and tag match, extract the length and verify that the entire
+// section is present in the buffer chain. If this is the case then store the
+// start of the section in 'location' and advance '*buffer' and '*cursor' to
+// the next section.
//
-// Return 0 if the pattern matches but the following tag is unexpected
-// Return 0 if the pattern matches and the location already has a pointer (duplicate section)
-// Return 1 if the pattern matches and we've advanced the cursor/buffer
-// Return 1 if the pattern does not match
+// if there is not enough of the section present in the buffer chain we need to
+// wait until more data arrives and try again.
//
-static int qd_check_and_advance(qd_buffer_t **buffer,
- unsigned char **cursor,
- const unsigned char *pattern,
- int pattern_length,
- const unsigned char *expected_tags,
- qd_field_location_t *location)
+//
+typedef enum {
+ QD_SECTION_INVALID, // invalid section (tag mismatch, duplicate section, etc).
+ QD_SECTION_MATCH,
+ QD_SECTION_NO_MATCH,
+ QD_SECTION_NEED_MORE // not enough data in the buffer chain - try again
+} qd_section_status_t;
+
+static qd_section_status_t message_section_check(qd_buffer_t **buffer,
+ unsigned char **cursor,
+ const unsigned char *pattern,
+ int pattern_length,
+ const unsigned char *expected_tags,
+ qd_field_location_t *location)
{
qd_buffer_t *test_buffer = *buffer;
unsigned char *test_cursor = *cursor;
if (!test_cursor)
- return 1; // no match
+ return QD_SECTION_NEED_MORE;
- unsigned char *end_of_buffer = qd_buffer_base(test_buffer) + qd_buffer_size(test_buffer);
+ unsigned char *end_of_buffer = qd_buffer_cursor(test_buffer);
int idx = 0;
while (idx < pattern_length && *test_cursor == pattern[idx]) {
@@ -591,14 +623,14 @@ static int qd_check_and_advance(qd_buffer_t **buffer,
if (test_cursor == end_of_buffer) {
test_buffer = test_buffer->next;
if (test_buffer == 0)
- return 1; // Pattern didn't match
+ return QD_SECTION_NEED_MORE;
test_cursor = qd_buffer_base(test_buffer);
end_of_buffer = test_cursor + qd_buffer_size(test_buffer);
}
}
if (idx < pattern_length)
- return 1; // Pattern didn't match
+ return QD_SECTION_NO_MATCH;
//
// Pattern matched, check the tag
@@ -606,10 +638,10 @@ static int qd_check_and_advance(qd_buffer_t **buffer,
while (*expected_tags && *test_cursor != *expected_tags)
expected_tags++;
if (*expected_tags == 0)
- return 0; // Unexpected tag
+ return QD_SECTION_INVALID; // Error: Unexpected tag
if (location->parsed)
- return 0; // Duplicate section
+ return QD_SECTION_INVALID; // Error: Duplicate section
//
// Pattern matched and tag is expected. Mark the beginning of the section.
@@ -620,18 +652,22 @@ static int qd_check_and_advance(qd_buffer_t **buffer,
location->hdr_length = pattern_length;
//
- // Advance the pointers to consume the whole section.
+ // Check that the full section is present, if so advance the pointers to
+ // consume the whole section.
//
int pre_consume = 1; // Count the already extracted tag
- int consume = 0;
+ uint32_t consume = 0;
unsigned char tag = next_octet(&test_cursor, &test_buffer);
-
unsigned char tag_subcat = tag & 0xF0;
+
+ // if there is no more data the only valid data type is a null type (0x40),
+ // size is implied as 0
if (!test_cursor && tag_subcat != 0x40)
- return 0;
+ return QD_SECTION_NEED_MORE;
switch (tag_subcat) {
- case 0x40: break;
+ // fixed sizes:
+ case 0x40: /* null */ break;
case 0x50: consume = 1; break;
case 0x60: consume = 2; break;
case 0x70: consume = 4; break;
@@ -641,37 +677,43 @@ static int qd_check_and_advance(qd_buffer_t **buffer,
case 0xB0:
case 0xD0:
case 0xF0:
+ // uint32_t size field:
pre_consume += 3;
- consume |= ((int) next_octet(&test_cursor, &test_buffer)) << 24;
- if (!test_cursor) return 0;
- consume |= ((int) next_octet(&test_cursor, &test_buffer)) << 16;
- if (!test_cursor) return 0;
- consume |= ((int) next_octet(&test_cursor, &test_buffer)) << 8;
- if (!test_cursor) return 0;
+ consume |= ((uint32_t) next_octet(&test_cursor, &test_buffer)) << 24;
+ if (!test_cursor) return QD_SECTION_NEED_MORE;
+ consume |= ((uint32_t) next_octet(&test_cursor, &test_buffer)) << 16;
+ if (!test_cursor) return QD_SECTION_NEED_MORE;
+ consume |= ((uint32_t) next_octet(&test_cursor, &test_buffer)) << 8;
+ if (!test_cursor) return QD_SECTION_NEED_MORE;
// Fall through to the next case...
case 0xA0:
case 0xC0:
case 0xE0:
+ // uint8_t size field
pre_consume += 1;
- consume |= (int) next_octet(&test_cursor, &test_buffer);
- if (!test_cursor) return 0;
+ consume |= (uint32_t) next_octet(&test_cursor, &test_buffer);
+ if (!test_cursor) return QD_SECTION_NEED_MORE;
break;
}
location->length = pre_consume + consume;
- if (consume)
- advance(&test_cursor, &test_buffer, consume);
+ if (consume) {
+ if (advance(&test_cursor, &test_buffer, consume) != 0) {
+ return QD_SECTION_NEED_MORE; // whole section not fully received
+ }
+ }
//
// increment the reference count of the parsed section as location now
- // references it. Note that the cursor has advanced to the octet after the
- // parsed section, so be careful not to include an extra buffer past the
- // end
+ // references it. Note that the cursor may have advanced to the octet after
+ // the parsed section, so be careful not to include an extra buffer past
+ // the end. And cursor + buffer will be null if the parsed section ends at
+ // the end of the buffer chain, so be careful of that, too!
//
qd_buffer_t *start = *buffer;
qd_buffer_t *last = test_buffer;
- if (last != start && last != 0) {
+ if (last && last != start) {
if (test_cursor == qd_buffer_base(last)) {
// last does not include octets for the current section
last = DEQ_PREV(last);
@@ -689,7 +731,7 @@ static int qd_check_and_advance(qd_buffer_t **buffer,
*cursor = test_cursor;
*buffer = test_buffer;
- return 1;
+ return QD_SECTION_MATCH;
}
@@ -762,7 +804,7 @@ static qd_field_location_t *qd_message_properties_field(qd_message_t *msg, qd_me
qd_message_content_t *content = MSG_CONTENT(msg);
if (!content->section_message_properties.parsed) {
- if (!qd_message_check(msg, QD_DEPTH_PROPERTIES) || !content->section_message_properties.parsed)
+ if (qd_message_check_depth(msg, QD_DEPTH_PROPERTIES) != QD_MESSAGE_DEPTH_OK || !content->section_message_properties.parsed)
return 0;
}
@@ -834,7 +876,7 @@ static qd_field_location_t *qd_message_field_location(qd_message_t *msg, qd_mess
switch (section) {
case QD_FIELD_HEADER:
if (content->section_message_header.parsed ||
- (qd_message_check(msg, QD_DEPTH_HEADER) && content->section_message_header.parsed))
+ (qd_message_check_depth(msg, QD_DEPTH_HEADER) == QD_MESSAGE_DEPTH_OK && content->section_message_header.parsed))
return &content->section_message_header;
break;
@@ -843,31 +885,31 @@ static qd_field_location_t *qd_message_field_location(qd_message_t *msg, qd_mess
case QD_FIELD_DELIVERY_ANNOTATION:
if (content->section_delivery_annotation.parsed ||
- (qd_message_check(msg, QD_DEPTH_DELIVERY_ANNOTATIONS) && content->section_delivery_annotation.parsed))
+ (qd_message_check_depth(msg, QD_DEPTH_DELIVERY_ANNOTATIONS) == QD_MESSAGE_DEPTH_OK && content->section_delivery_annotation.parsed))
return &content->section_delivery_annotation;
break;
case QD_FIELD_MESSAGE_ANNOTATION:
if (content->section_message_annotation.parsed ||
- (qd_message_check(msg, QD_DEPTH_MESSAGE_ANNOTATIONS) && content->section_message_annotation.parsed))
+ (qd_message_check_depth(msg, QD_DEPTH_MESSAGE_ANNOTATIONS) == QD_MESSAGE_DEPTH_OK && content->section_message_annotation.parsed))
return &content->section_message_annotation;
break;
case QD_FIELD_APPLICATION_PROPERTIES:
if (content->section_application_properties.parsed ||
- (qd_message_check(msg, QD_DEPTH_APPLICATION_PROPERTIES) && content->section_application_properties.parsed))
+ (qd_message_check_depth(msg, QD_DEPTH_APPLICATION_PROPERTIES) == QD_MESSAGE_DEPTH_OK && content->section_application_properties.parsed))
return &content->section_application_properties;
break;
case QD_FIELD_BODY:
if (content->section_body.parsed ||
- (qd_message_check(msg, QD_DEPTH_BODY) && content->section_body.parsed))
+ (qd_message_check_depth(msg, QD_DEPTH_BODY) == QD_MESSAGE_DEPTH_OK && content->section_body.parsed))
return &content->section_body;
break;
case QD_FIELD_FOOTER:
if (content->section_footer.parsed ||
- (qd_message_check(msg, QD_DEPTH_ALL) && content->section_footer.parsed))
+ (qd_message_check_depth(msg, QD_DEPTH_ALL) == QD_MESSAGE_DEPTH_OK && content->section_footer.parsed))
return &content->section_footer;
break;
@@ -1754,154 +1796,201 @@ void qd_message_send(qd_message_t *in_msg,
}
-static int qd_check_field_LH(qd_message_content_t *content,
- qd_message_depth_t depth,
- const unsigned char *long_pattern,
- const unsigned char *short_pattern,
- const unsigned char *expected_tags,
- qd_field_location_t *location,
- int more)
+static qd_message_depth_status_t message_check_depth_LH(qd_message_content_t *content,
+ qd_message_depth_t depth,
+ const unsigned char *long_pattern,
+ const unsigned char *short_pattern,
+ const unsigned char *expected_tags,
+ qd_field_location_t *location,
+ bool optional)
{
#define LONG 10
#define SHORT 3
- if (depth > content->parse_depth) {
- if (0 == qd_check_and_advance(&content->parse_buffer, &content->parse_cursor, long_pattern, LONG, expected_tags, location))
- return 0;
- if (0 == qd_check_and_advance(&content->parse_buffer, &content->parse_cursor, short_pattern, SHORT, expected_tags, location))
- return 0;
- if (!more)
- content->parse_depth = depth;
+ if (depth <= content->parse_depth)
+ return QD_MESSAGE_DEPTH_OK;
+
+ qd_section_status_t rc;
+ rc = message_section_check(&content->parse_buffer, &content->parse_cursor, short_pattern, SHORT, expected_tags, location);
+ if (rc == QD_SECTION_NO_MATCH) // try the alternative
+ rc = message_section_check(&content->parse_buffer, &content->parse_cursor, long_pattern, LONG, expected_tags, location);
+
+ if (rc == QD_SECTION_MATCH || (optional && rc == QD_SECTION_NO_MATCH)) {
+ content->parse_depth = depth;
+ return QD_MESSAGE_DEPTH_OK;
}
- return 1;
+
+ if (rc == QD_SECTION_NEED_MORE) {
+ if (!content->receive_complete)
+ return QD_MESSAGE_DEPTH_INCOMPLETE;
+
+ // no more data is going to come. OK if at the end and optional:
+ if (!content->parse_cursor && optional)
+ return QD_MESSAGE_DEPTH_OK;
+
+ // otherwise we've got an invalid (truncated) header
+ }
+
+ // if QD_SECTION_NO_MATCH && !optional => INVALID;
+ // QD_SECTION_INVALID => INVALID;
+
+ return QD_MESSAGE_DEPTH_INVALID;
}
-static bool qd_message_check_LH(qd_message_content_t *content, qd_message_depth_t depth)
+static qd_message_depth_status_t qd_message_check_LH(qd_message_content_t *content, qd_message_depth_t depth)
{
qd_error_clear();
- //
- // In the case of a streaming or multi buffer message, there is a chance that some buffers might be freed before the entire
- // message has arrived in which case we cannot reliably check the message using the depth.
- //
- if (content->buffers_freed)
- return true;
+ if (depth <= content->parse_depth || depth == QD_DEPTH_NONE)
+ return QD_MESSAGE_DEPTH_OK; // We've already parsed at least this deep
qd_buffer_t *buffer = DEQ_HEAD(content->buffers);
-
if (!buffer) {
- return false;
+ return content->receive_complete ? QD_MESSAGE_DEPTH_INVALID : QD_MESSAGE_DEPTH_INCOMPLETE;
}
- if (depth <= content->parse_depth)
- return true; // We've already parsed at least this deep
-
if (content->parse_buffer == 0) {
content->parse_buffer = buffer;
content->parse_cursor = qd_buffer_base(content->parse_buffer);
}
- if (depth == QD_DEPTH_NONE)
- return true;
+ qd_message_depth_status_t rc = QD_MESSAGE_DEPTH_OK;
+ int last_section = QD_DEPTH_NONE;
- //
- // MESSAGE HEADER
- //
- if (0 == qd_check_field_LH(content, QD_DEPTH_HEADER,
- MSG_HDR_LONG, MSG_HDR_SHORT, TAGS_LIST, &content->section_message_header, 0)) {
- qd_error(QD_ERROR_MESSAGE, "Invalid header");
- return false;
- }
- if (depth == QD_DEPTH_HEADER)
- return true;
+ switch (content->parse_depth + 1) { // start checking at the next unparsed section
+ case QD_DEPTH_HEADER:
+ //
+ // MESSAGE HEADER (optional)
+ //
+ last_section = QD_DEPTH_HEADER;
+ rc = message_check_depth_LH(content, QD_DEPTH_HEADER,
+ MSG_HDR_LONG, MSG_HDR_SHORT, TAGS_LIST,
+ &content->section_message_header, true);
+ if (rc != QD_MESSAGE_DEPTH_OK || depth == QD_DEPTH_HEADER)
+ break;
- //
- // DELIVERY ANNOTATION
- //
- if (0 == qd_check_field_LH(content, QD_DEPTH_DELIVERY_ANNOTATIONS,
- DELIVERY_ANNOTATION_LONG, DELIVERY_ANNOTATION_SHORT, TAGS_MAP, &content->section_delivery_annotation, 0)) {
- qd_error(QD_ERROR_MESSAGE, "Invalid delivery-annotations");
- return false;
- }
- if (depth == QD_DEPTH_DELIVERY_ANNOTATIONS)
- return true;
+ // fallthrough
- //
- // MESSAGE ANNOTATION
- //
- if (0 == qd_check_field_LH(content, QD_DEPTH_MESSAGE_ANNOTATIONS,
- MESSAGE_ANNOTATION_LONG, MESSAGE_ANNOTATION_SHORT, TAGS_MAP, &content->section_message_annotation, 0)) {
- qd_error(QD_ERROR_MESSAGE, "Invalid annotations");
- return false;
- }
- if (depth == QD_DEPTH_MESSAGE_ANNOTATIONS)
- return true;
+ case QD_DEPTH_DELIVERY_ANNOTATIONS:
+ //
+ // DELIVERY ANNOTATIONS (optional)
+ //
+ last_section = QD_DEPTH_DELIVERY_ANNOTATIONS;
+ rc = message_check_depth_LH(content, QD_DEPTH_DELIVERY_ANNOTATIONS,
+ DELIVERY_ANNOTATION_LONG, DELIVERY_ANNOTATION_SHORT, TAGS_MAP,
+ &content->section_delivery_annotation, true);
+ if (rc != QD_MESSAGE_DEPTH_OK || depth == QD_DEPTH_DELIVERY_ANNOTATIONS)
+ break;
- //
- // PROPERTIES
- //
- if (0 == qd_check_field_LH(content, QD_DEPTH_PROPERTIES,
- PROPERTIES_LONG, PROPERTIES_SHORT, TAGS_LIST, &content->section_message_properties, 0)) {
- qd_error(QD_ERROR_MESSAGE, "Invalid message properties");
- return false;
- }
- if (depth == QD_DEPTH_PROPERTIES)
- return true;
+ // fallthrough
- //
- // APPLICATION PROPERTIES
- //
- if (0 == qd_check_field_LH(content, QD_DEPTH_APPLICATION_PROPERTIES,
- APPLICATION_PROPERTIES_LONG, APPLICATION_PROPERTIES_SHORT, TAGS_MAP, &content->section_application_properties, 0)) {
- qd_error(QD_ERROR_MESSAGE, "Invalid application-properties");
- return false;
- }
- if (depth == QD_DEPTH_APPLICATION_PROPERTIES)
- return true;
+ case QD_DEPTH_MESSAGE_ANNOTATIONS:
+ //
+ // MESSAGE ANNOTATION (optional)
+ //
+ last_section = QD_DEPTH_MESSAGE_ANNOTATIONS;
+ rc = message_check_depth_LH(content, QD_DEPTH_MESSAGE_ANNOTATIONS,
+ MESSAGE_ANNOTATION_LONG, MESSAGE_ANNOTATION_SHORT, TAGS_MAP,
+ &content->section_message_annotation, true);
+ if (rc != QD_MESSAGE_DEPTH_OK || depth == QD_DEPTH_MESSAGE_ANNOTATIONS)
+ break;
- //
- // BODY
- // Note that this function expects a limited set of types in a VALUE section. This is
- // not a problem for messages passing through Dispatch because through-only messages won't
- // be parsed to BODY-depth.
- //
- if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
- BODY_DATA_LONG, BODY_DATA_SHORT, TAGS_BINARY, &content->section_body, 1)) {
- qd_error(QD_ERROR_MESSAGE, "Invalid body data");
- return false;
- }
- if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
- BODY_SEQUENCE_LONG, BODY_SEQUENCE_SHORT, TAGS_LIST, &content->section_body, 1)) {
- qd_error(QD_ERROR_MESSAGE, "Invalid body sequence");
- return false;
- }
- if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
- BODY_VALUE_LONG, BODY_VALUE_SHORT, TAGS_ANY, &content->section_body, 0)) {
- qd_error(QD_ERROR_MESSAGE, "Invalid body value");
- return false;
- }
- if (depth == QD_DEPTH_BODY)
- return true;
+ // fallthough
- //
- // FOOTER
- //
- if (0 == qd_check_field_LH(content, QD_DEPTH_ALL,
- FOOTER_LONG, FOOTER_SHORT, TAGS_MAP, &content->section_footer, 0)) {
+ case QD_DEPTH_PROPERTIES:
+ //
+ // PROPERTIES (optional)
+ //
+ last_section = QD_DEPTH_PROPERTIES;
+ rc = message_check_depth_LH(content, QD_DEPTH_PROPERTIES,
+ PROPERTIES_LONG, PROPERTIES_SHORT, TAGS_LIST,
+ &content->section_message_properties, true);
+ if (rc != QD_MESSAGE_DEPTH_OK || depth == QD_DEPTH_PROPERTIES)
+ break;
- qd_error(QD_ERROR_MESSAGE, "Invalid footer");
- return false;
+ // fallthrough
+
+ case QD_DEPTH_APPLICATION_PROPERTIES:
+ //
+ // APPLICATION PROPERTIES (optional)
+ //
+ last_section = QD_DEPTH_APPLICATION_PROPERTIES;
+ rc = message_check_depth_LH(content, QD_DEPTH_APPLICATION_PROPERTIES,
+ APPLICATION_PROPERTIES_LONG, APPLICATION_PROPERTIES_SHORT, TAGS_MAP,
+ &content->section_application_properties, true);
+ if (rc != QD_MESSAGE_DEPTH_OK || depth == QD_DEPTH_APPLICATION_PROPERTIES)
+ break;
+
+ // fallthrough
+
+ case QD_DEPTH_BODY:
+ // In the case of multi-buffer streaming we may discard buffers that
+ // contain only the Body or Footer section for those messages that are
+ // through-only. We really cannot validate those sections if that should happen
+ //
+ if (content->buffers_freed)
+ return QD_MESSAGE_DEPTH_OK;
+
+ //
+ // BODY (not optional, but proton allows it - see PROTON-2085)
+ //
+ // AMQP 1.0 defines 3 valid Body types: Binary, Sequence (list), or Value (any type)
+ // Since the body is mandatory, we need to match one of these. Setting
+ // the optional flag to false will force us to check each one until a match is found.
+ //
+ last_section = QD_DEPTH_BODY;
+ rc = message_check_depth_LH(content, QD_DEPTH_BODY,
+ BODY_VALUE_LONG, BODY_VALUE_SHORT, TAGS_ANY,
+ &content->section_body, false);
+ if (rc == QD_MESSAGE_DEPTH_INVALID) { // may be a different body type, need to check:
+ rc = message_check_depth_LH(content, QD_DEPTH_BODY,
+ BODY_DATA_LONG, BODY_DATA_SHORT, TAGS_BINARY,
+ &content->section_body, false);
+ if (rc == QD_MESSAGE_DEPTH_INVALID) {
+ rc = message_check_depth_LH(content, QD_DEPTH_BODY,
+ BODY_SEQUENCE_LONG, BODY_SEQUENCE_SHORT, TAGS_LIST,
+ &content->section_body, true); // PROTON-2085
+ }
+ }
+
+ if (rc != QD_MESSAGE_DEPTH_OK || depth == QD_DEPTH_BODY)
+ break;
+
+ // fallthrough
+
+ case QD_DEPTH_ALL:
+ //
+ // FOOTER (optional)
+ //
+ if (content->buffers_freed) // see above
+ return QD_MESSAGE_DEPTH_OK;
+
+ last_section = QD_DEPTH_ALL;
+ rc = message_check_depth_LH(content, QD_DEPTH_ALL,
+ FOOTER_LONG, FOOTER_SHORT, TAGS_MAP,
+ &content->section_footer, true);
+ break;
+
+ default:
+ assert(false); // should not happen!
+ qd_error(QD_ERROR_MESSAGE, "BUG! Invalid message depth specified: %d",
+ content->parse_depth + 1);
+ return QD_MESSAGE_DEPTH_INVALID;
}
- return true;
+ if (rc == QD_MESSAGE_DEPTH_INVALID)
+ qd_error(QD_ERROR_MESSAGE, "Invalid message: %s section invalid",
+ section_names[last_section]);
+
+ return rc;
}
-int qd_message_check(qd_message_t *in_msg, qd_message_depth_t depth)
+qd_message_depth_status_t qd_message_check_depth(const qd_message_t *in_msg, qd_message_depth_t depth)
{
qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg;
qd_message_content_t *content = msg->content;
- int result;
+ qd_message_depth_status_t result;
LOCK(content->lock);
result = qd_message_check_LH(content, depth);
diff --git a/src/python_embedded.c b/src/python_embedded.c
index 243ab0a..c822925 100644
--- a/src/python_embedded.c
+++ b/src/python_embedded.c
@@ -520,7 +520,7 @@ static void qd_io_rx_handler(void *context, qd_message_t *msg, int link_id, int
//
// Parse the message through the body and exit if the message is not well formed.
//
- if (!qd_message_check(msg, QD_DEPTH_BODY))
+ if (qd_message_check_depth(msg, QD_DEPTH_BODY) != QD_MESSAGE_DEPTH_OK)
return;
// This is called from non-python threads so we need to acquire the GIL to use python APIS.
diff --git a/src/router_core/exchange_bindings.c b/src/router_core/exchange_bindings.c
index 0f5908c..dc3b495 100644
--- a/src/router_core/exchange_bindings.c
+++ b/src/router_core/exchange_bindings.c
@@ -192,7 +192,7 @@ int qdr_forward_exchange_CT(qdr_core_t *core,
if (!presettled)
in_delivery->settled = true;
- qd_iterator_t *subject = qd_message_check(msg, QD_DEPTH_PROPERTIES)
+ qd_iterator_t *subject = qd_message_check_depth(msg, QD_DEPTH_PROPERTIES) == QD_MESSAGE_DEPTH_OK
? qd_message_field_iterator(msg, QD_FIELD_SUBJECT)
: NULL;
next_hop_list_t transmit_list;
diff --git a/src/router_core/modules/edge_router/addr_proxy.c b/src/router_core/modules/edge_router/addr_proxy.c
index 31f9fdc..61fbf59 100644
--- a/src/router_core/modules/edge_router/addr_proxy.c
+++ b/src/router_core/modules/edge_router/addr_proxy.c
@@ -428,7 +428,7 @@ static void on_transfer(void *link_context,
//
// Validate the message
//
- if (qd_message_check(msg, QD_DEPTH_BODY)) {
+ if (qd_message_check_depth(msg, QD_DEPTH_BODY) == QD_MESSAGE_DEPTH_OK) {
//
// Get the message body. It must be a list with two elements. The first is an address
// and the second is a boolean indicating whether that address has upstream destinations.
diff --git a/src/router_node.c b/src/router_node.c
index 1e5ee6a..ef1ce17 100644
--- a/src/router_node.c
+++ b/src/router_node.c
@@ -465,20 +465,19 @@ static bool AMQP_rx_handler(void* context, qd_link_t *link)
// using the address from the link target.
//
qd_message_depth_t validation_depth = (anonymous_link || check_user) ? QD_DEPTH_PROPERTIES : QD_DEPTH_MESSAGE_ANNOTATIONS;
- bool valid_message = qd_message_check(msg, validation_depth);
+ qd_message_depth_status_t depth_valid = qd_message_check_depth(msg, validation_depth);
- if (!valid_message) {
- if (receive_complete) {
- //
- // The entire message has been received and the message is still invalid. Reject the message.
- //
+ if (depth_valid != QD_MESSAGE_DEPTH_OK) {
+ if (depth_valid == QD_MESSAGE_DEPTH_INVALID) {
qd_message_set_discard(msg, true);
pn_link_flow(pn_link, 1);
pn_delivery_update(pnd, PN_REJECTED);
pn_delivery_settle(pnd);
qd_message_free(msg);
+ } else {
+ // otherwise wait until more data arrives and re-try the validation
+ assert(depth_valid == QD_MESSAGE_DEPTH_INCOMPLETE);
}
- // otherwise wait until more data arrives and re-try the validation
return next_delivery;
}
diff --git a/tests/message_test.c b/tests/message_test.c
index fa30d94..bc786a1 100644
--- a/tests/message_test.c
+++ b/tests/message_test.c
@@ -25,12 +25,12 @@
#include <qpid/dispatch/amqp.h>
#include <proton/message.h>
-static char buffer[10000];
+static unsigned char buffer[10000];
static size_t flatten_bufs(qd_message_content_t *content)
{
- char *cursor = buffer;
- qd_buffer_t *buf = DEQ_HEAD(content->buffers);
+ unsigned char *cursor = buffer;
+ qd_buffer_t *buf = DEQ_HEAD(content->buffers);
while (buf) {
memcpy(cursor, qd_buffer_base(buf), qd_buffer_size(buf));
@@ -42,9 +42,9 @@ static size_t flatten_bufs(qd_message_content_t *content)
}
-static void set_content(qd_message_content_t *content, size_t len)
+static void set_content(qd_message_content_t *content, unsigned char *buffer, size_t len)
{
- char *cursor = buffer;
+ unsigned char *cursor = buffer;
qd_buffer_t *buf;
while (len > (size_t) (cursor - buffer)) {
@@ -58,6 +58,7 @@ static void set_content(qd_message_content_t *content, size_t len)
qd_buffer_insert(buf, segment);
DEQ_INSERT_TAIL(content->buffers, buf);
}
+ content->receive_complete = true;
}
@@ -85,7 +86,7 @@ static char* test_send_to_messenger(void *context)
pn_message_t *pn_msg = pn_message();
size_t len = flatten_bufs(content);
- int result = pn_message_decode(pn_msg, buffer, len);
+ int result = pn_message_decode(pn_msg, (char *)buffer, len);
if (result != 0) {
pn_message_free(pn_msg);
qd_message_free(msg);
@@ -111,7 +112,7 @@ static char* test_receive_from_messenger(void *context)
pn_message_set_address(pn_msg, "test_addr_1");
size_t size = 10000;
- int result = pn_message_encode(pn_msg, buffer, &size);
+ int result = pn_message_encode(pn_msg, (char *)buffer, &size);
if (result != 0) {
pn_message_free(pn_msg);
return "Error in pn_message_encode";
@@ -120,13 +121,12 @@ static char* test_receive_from_messenger(void *context)
qd_message_t *msg = qd_message();
qd_message_content_t *content = MSG_CONTENT(msg);
- set_content(content, size);
+ set_content(content, buffer, size);
- int valid = qd_message_check(msg, QD_DEPTH_ALL);
- if (!valid) {
+ if (qd_message_check_depth(msg, QD_DEPTH_ALL) != QD_MESSAGE_DEPTH_OK) {
pn_message_free(pn_msg);
qd_message_free(msg);
- return "qd_message_check returns 'invalid'";
+ return "qd_message_check_depth returns 'invalid'";
}
qd_iterator_t *iter = qd_message_field_iterator(msg, QD_FIELD_TO);
@@ -195,7 +195,7 @@ static char* test_message_properties(void *context)
pn_message_set_correlation_id(pn_msg, cid);
size_t size = 10000;
- int result = pn_message_encode(pn_msg, buffer, &size);
+ int result = pn_message_encode(pn_msg, (char *)buffer, &size);
pn_message_free(pn_msg);
if (result != 0) return "Error in pn_message_encode";
@@ -203,7 +203,7 @@ static char* test_message_properties(void *context)
qd_message_t *msg = qd_message();
qd_message_content_t *content = MSG_CONTENT(msg);
- set_content(content, size);
+ set_content(content, buffer, size);
qd_iterator_t *iter = qd_message_field_iterator(msg, QD_FIELD_CORRELATION_ID);
if (!iter) {
@@ -266,42 +266,93 @@ static char* test_message_properties(void *context)
}
+// run qd_message_check_depth against different legal AMQP message
+//
+static char* _check_all_depths(qd_message_t *msg)
+{
+ static const qd_message_depth_t depths[] = {
+ // yep: purposely out of order
+ QD_DEPTH_MESSAGE_ANNOTATIONS,
+ QD_DEPTH_DELIVERY_ANNOTATIONS,
+ QD_DEPTH_PROPERTIES,
+ QD_DEPTH_HEADER,
+ QD_DEPTH_APPLICATION_PROPERTIES,
+ QD_DEPTH_BODY
+ };
+ static const int n_depths = 6;
+
+ static char err[1024];
+
+ for (int i = 0; i < n_depths; ++i) {
+ if (qd_message_check_depth(msg, depths[i]) != QD_MESSAGE_DEPTH_OK) {
+ snprintf(err, 1023,
+ "qd_message_check_depth returned 'invalid' for section 0x%X", (unsigned int)depths[i]);
+ err[1023] = 0;
+ return err;
+ }
+ }
+ return 0;
+}
+
+
static char* test_check_multiple(void *context)
{
+ // case 1: a minimal encoded message
+ //
pn_message_t *pn_msg = pn_message();
- pn_message_set_address(pn_msg, "test_addr_2");
size_t size = 10000;
- int result = pn_message_encode(pn_msg, buffer, &size);
+ int result = pn_message_encode(pn_msg, (char *)buffer, &size);
pn_message_free(pn_msg);
if (result != 0) return "Error in pn_message_encode";
qd_message_t *msg = qd_message();
qd_message_content_t *content = MSG_CONTENT(msg);
- set_content(content, size);
-
- int valid = qd_message_check(msg, QD_DEPTH_DELIVERY_ANNOTATIONS);
- if (!valid) {
- qd_message_free(msg);
- return "qd_message_check returns 'invalid' for DELIVERY_ANNOTATIONS";
- }
-
- valid = qd_message_check(msg, QD_DEPTH_BODY);
- if (!valid) {
- qd_message_free(msg);
- return "qd_message_check returns 'invalid' for BODY";
- }
-
- valid = qd_message_check(msg, QD_DEPTH_PROPERTIES);
- if (!valid) {
- qd_message_free(msg);
- return "qd_message_check returns 'invalid' for PROPERTIES";
- }
-
+ set_content(content, buffer, size);
+ char *rc = _check_all_depths(msg);
qd_message_free(msg);
+ if (rc) return rc;
- return 0;
+ // case 2: minimal, with address field in header
+ //
+ pn_msg = pn_message();
+ pn_message_set_address(pn_msg, "test_addr_2");
+ size = 10000;
+ result = pn_message_encode(pn_msg, (char *)buffer, &size);
+ pn_message_free(pn_msg);
+ if (result != 0) return "Error in pn_message_encode";
+ msg = qd_message();
+ set_content(MSG_CONTENT(msg), buffer, size);
+ rc = _check_all_depths(msg);
+ qd_message_free(msg);
+ if (rc) return rc;
+
+ // case 3: null body
+ //
+ pn_msg = pn_message();
+ pn_data_t *body = pn_message_body(pn_msg);
+ pn_data_put_null(body);
+ size = 10000;
+ result = pn_message_encode(pn_msg, (char *)buffer, &size);
+ pn_message_free(pn_msg);
+ if (result != 0) return "Error in pn_message_encode";
+ msg = qd_message();
+ set_content(MSG_CONTENT(msg), buffer, size);
+ rc = _check_all_depths(msg);
+ qd_message_free(msg);
+ if (rc) return rc;
+
+ // case 4: minimal legal AMQP 1.0 message (as defined by the standard)
+ // A single body field with a null value
+ const unsigned char null_body[] = {0x00, 0x53, 0x77, 0x40};
+ size = sizeof(null_body);
+ memcpy(buffer, null_body, size);
+ msg = qd_message();
+ set_content(MSG_CONTENT(msg), buffer, size);
+ rc = _check_all_depths(msg);
+ qd_message_free(msg);
+ return rc;
}
@@ -334,7 +385,7 @@ static char* test_send_message_annotations(void *context)
pn_message_t *pn_msg = pn_message();
size_t len = flatten_bufs(content);
- int result = pn_message_decode(pn_msg, buffer, len);
+ int result = pn_message_decode(pn_msg, (char *)buffer, len);
if (result != 0) {
qd_message_free(msg);
return "Error in pn_message_decode";
@@ -415,6 +466,216 @@ static char* test_q2_input_holdoff_sensing(void *context)
}
+// verify that message check does not incorrectly validate a message section
+// that has not been completely received.
+//
+static char *test_incomplete_annotations(void *context)
+{
+ const char big_string[] =
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
+
+ char *result = 0;
+ qd_message_t *msg = 0;
+ pn_message_t *out_message = pn_message();
+
+ pn_data_t *body = pn_message_body(out_message);
+ pn_data_clear(body);
+ pn_data_put_list(body);
+ pn_data_enter(body);
+ pn_data_put_long(body, 1);
+ pn_data_put_long(body, 2);
+ pn_data_put_long(body, 3);
+ pn_data_exit(body);
+
+ // Add a bunch 'o user message annotations
+ pn_data_t *annos = pn_message_annotations(out_message);
+ pn_data_clear(annos);
+ pn_data_put_map(annos);
+ pn_data_enter(annos);
+
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-key"), "my-key"));
+ pn_data_put_string(annos, pn_bytes(strlen("my-data"), "my-data"));
+
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-other-key"), "my-other-key"));
+ pn_data_put_string(annos, pn_bytes(strlen("my-other-data"), "my-other-data"));
+
+ // embedded map
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-map"), "my-map"));
+ pn_data_put_map(annos);
+ pn_data_enter(annos);
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-map-key1"), "my-map-key1"));
+ pn_data_put_char(annos, 'X');
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-map-key2"), "my-map-key2"));
+ pn_data_put_byte(annos, 0x12);
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-map-key3"), "my-map-key3"));
+ pn_data_put_string(annos, pn_bytes(strlen("Are We Not Men?"), "Are We Not Men?"));
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-last-key"), "my-last-key"));
+ pn_data_put_binary(annos, pn_bytes(sizeof(big_string), big_string));
+ pn_data_exit(annos);
+
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-ulong"), "my-ulong"));
+ pn_data_put_ulong(annos, 0xDEADBEEFCAFEBEEF);
+
+ // embedded list
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-list"), "my-list"));
+ pn_data_put_list(annos);
+ pn_data_enter(annos);
+ pn_data_put_string(annos, pn_bytes(sizeof(big_string), big_string));
+ pn_data_put_double(annos, 3.1415);
+ pn_data_put_short(annos, 1966);
+ pn_data_exit(annos);
+
+ pn_data_put_symbol(annos, pn_bytes(strlen("my-bool"), "my-bool"));
+ pn_data_put_bool(annos, false);
+
+ pn_data_exit(annos);
+
+ // now encode it
+
+ size_t encode_len = sizeof(buffer);
+ int rc = pn_message_encode(out_message, (char *)buffer, &encode_len);
+ if (rc) {
+ if (rc == PN_OVERFLOW)
+ result = "Error: sizeof(buffer) in message_test.c too small - update it!";
+ else
+ result = "Error encoding message";
+ goto exit;
+ }
+
+ assert(encode_len > 100); // you broke the test!
+
+ // Verify that the message check fails unless the entire annotations are
+ // present. First copy in only the first 100 bytes: enough for the MA
+ // section header but not the whole section
+
+ msg = qd_message();
+ qd_message_content_t *content = MSG_CONTENT(msg);
+ set_content(content, buffer, 100);
+ content->receive_complete = false; // more data coming!
+ if (qd_message_check_depth(msg, QD_DEPTH_MESSAGE_ANNOTATIONS) != QD_MESSAGE_DEPTH_INCOMPLETE) {
+ result = "Error: incomplete message was not detected!";
+ goto exit;
+ }
+
+ // now complete the message
+ set_content(content, &buffer[100], encode_len - 100);
+ if (qd_message_check_depth(msg, QD_DEPTH_MESSAGE_ANNOTATIONS) != QD_MESSAGE_DEPTH_OK) {
+ result = "Error: expected message to be valid!";
+ }
+
+exit:
+
+ if (out_message) pn_message_free(out_message);
+ if (msg) qd_message_free(msg);
+
+ return result;
+}
+
+
+static char *test_check_weird_messages(void *context)
+{
+ char *result = 0;
+ qd_message_t *msg = qd_message();
+
+ // case 1:
+ // delivery annotations with empty map
+ unsigned char da_map[] = {0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71,
+ 0xc1, 0x01, 0x00};
+ // first test an incomplete pattern:
+ set_content(MSG_CONTENT(msg), da_map, 4);
+ MSG_CONTENT(msg)->receive_complete = false;
+ qd_message_depth_status_t mc = qd_message_check_depth(msg, QD_DEPTH_DELIVERY_ANNOTATIONS);
+ if (mc != QD_MESSAGE_DEPTH_INCOMPLETE) {
+ result = "Expected INCOMPLETE status";
+ goto exit;
+ }
+
+ // full pattern, but no tag
+ set_content(MSG_CONTENT(msg), &da_map[4], 6);
+ MSG_CONTENT(msg)->receive_complete = false;
+ mc = qd_message_check_depth(msg, QD_DEPTH_DELIVERY_ANNOTATIONS);
+ if (mc != QD_MESSAGE_DEPTH_INCOMPLETE) {
+ result = "Expected INCOMPLETE status";
+ goto exit;
+ }
+
+ // add tag, but incomplete field:
+ set_content(MSG_CONTENT(msg), &da_map[10], 1);
+ MSG_CONTENT(msg)->receive_complete = false;
+ mc = qd_message_check_depth(msg, QD_DEPTH_DELIVERY_ANNOTATIONS);
+ if (mc != QD_MESSAGE_DEPTH_INCOMPLETE) {
+ result = "Expected INCOMPLETE status";
+ goto exit;
+ }
+
+ // and finish up
+ set_content(MSG_CONTENT(msg), &da_map[11], 2);
+ mc = qd_message_check_depth(msg, QD_DEPTH_DELIVERY_ANNOTATIONS);
+ if (mc != QD_MESSAGE_DEPTH_OK) {
+ result = "Expected OK status";
+ goto exit;
+ }
+
+ // case 2: negative test - detect invalid tag
+ unsigned char bad_hdr[] = {0x00, 0x53, 0x70, 0xC1}; // 0xc1 == map, not list!
+ qd_message_free(msg);
+ msg = qd_message();
+ set_content(MSG_CONTENT(msg), bad_hdr, sizeof(bad_hdr));
+ MSG_CONTENT(msg)->receive_complete = false;
+ mc = qd_message_check_depth(msg, QD_DEPTH_DELIVERY_ANNOTATIONS); // looking _past_ header!
+ if (mc != QD_MESSAGE_DEPTH_INVALID) {
+ result = "Bad tag not detected!";
+ goto exit;
+ }
+
+ // case 3: check the valid body types
+ unsigned char body_bin[] = {0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75,
+ 0xA0, 0x03, 0x00, 0x01, 0x02};
+ qd_message_free(msg);
+ msg = qd_message();
+ set_content(MSG_CONTENT(msg), body_bin, sizeof(body_bin));
+ mc = qd_message_check_depth(msg, QD_DEPTH_ALL); // looking _past_ header!
+ if (mc != QD_MESSAGE_DEPTH_OK) {
+ result = "Expected OK bin body";
+ goto exit;
+ }
+
+ unsigned char body_seq[] = {0x00, 0x53, 0x76, 0x45};
+ qd_message_free(msg);
+ msg = qd_message();
+ set_content(MSG_CONTENT(msg), body_seq, sizeof(body_seq));
+ mc = qd_message_check_depth(msg, QD_DEPTH_BODY);
+ if (mc != QD_MESSAGE_DEPTH_OK) {
+ result = "Expected OK seq body";
+ goto exit;
+ }
+
+ unsigned char body_value[] = {0x00, 0x53, 0x77, 0x51, 0x99};
+ qd_message_free(msg);
+ msg = qd_message();
+ set_content(MSG_CONTENT(msg), body_value, sizeof(body_value));
+ mc = qd_message_check_depth(msg, QD_DEPTH_BODY);
+ if (mc != QD_MESSAGE_DEPTH_OK) {
+ result = "Expected OK value body";
+ goto exit;
+ }
+
+exit:
+ if (msg) qd_message_free(msg);
+ return result;
+}
+
+
int message_tests(void)
{
int result = 0;
@@ -426,6 +687,8 @@ int message_tests(void)
TEST_CASE(test_check_multiple, 0);
TEST_CASE(test_send_message_annotations, 0);
TEST_CASE(test_q2_input_holdoff_sensing, 0);
+ TEST_CASE(test_incomplete_annotations, 0);
+ TEST_CASE(test_check_weird_messages, 0);
return result;
}
diff --git a/tests/run_unit_tests_size.c b/tests/run_unit_tests_size.c
index 25c467f..ec4f88f 100644
--- a/tests/run_unit_tests_size.c
+++ b/tests/run_unit_tests_size.c
@@ -20,6 +20,9 @@
#include <qpid/dispatch/buffer.h>
#include <qpid/dispatch/alloc.h>
+void qd_log_initialize(void);
+void qd_error_initialize();
+
int message_tests();
int field_tests();
int parse_tests();
@@ -36,6 +39,8 @@ int main(int argc, char** argv)
}
qd_alloc_initialize();
+ qd_log_initialize();
+ qd_error_initialize();
qd_buffer_set_size(buffer_size);
int result = 0;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org