From f5120a46371ff75f401c1cb724c3880811bfbae0 Mon Sep 17 00:00:00 2001 From: Sebastian Kemper Date: Sat, 3 Dec 2022 15:41:32 +0100 Subject: pjproject: bump to 2.12.1 This is a manual cherry-pick of a57228588602e5217b95f1e9ded0b76402cb6c72 and 472f1ac7ac867b8fbc2841c56e7d61935dba9d52. The only difference is that the uclibc-related patches were not dropped, because uclibc is used in OpenWrt 21.02. - add "--disable-android-mediacodec" to configure - add EXCLUDE_APP=1 to "make" calls so some apps aren't built (speeds up the build a bit) - drop "sed" call as no longer needed - update 0004-config_site.patch to sync up with Asterisk 18.14.0 - update 0006-fix-pkg_config-file.patch as there were some changes in this area upstream - add 0007-execinfo.patch to prevent errors due to missing - sync patches with Asterisk 18.14.0 - backports two security fixes (c4d3498 and 450baca) from pjproject 2.13, source: asterisk 20.0.1 Signed-off-by: Sebastian Kemper --- .../0160-Additional-multipart-improvements.patch | 635 --------------------- 1 file changed, 635 deletions(-) delete mode 100644 libs/pjproject/patches/0160-Additional-multipart-improvements.patch (limited to 'libs/pjproject/patches/0160-Additional-multipart-improvements.patch') diff --git a/libs/pjproject/patches/0160-Additional-multipart-improvements.patch b/libs/pjproject/patches/0160-Additional-multipart-improvements.patch deleted file mode 100644 index 3de67b5..0000000 --- a/libs/pjproject/patches/0160-Additional-multipart-improvements.patch +++ /dev/null @@ -1,635 +0,0 @@ -From b7ecff22e77887626fd8e8608c4dd73bc7b7366f Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Tue, 18 Jan 2022 06:14:31 -0700 -Subject: [PATCH] Additional multipart improvements - -Added the following APIs: -pjsip_multipart_find_part_by_header() -pjsip_multipart_find_part_by_header_str() -pjsip_multipart_find_part_by_cid_str() -pjsip_multipart_find_part_by_cid_uri() ---- - pjsip/include/pjsip/sip_multipart.h | 83 ++++++++++ - pjsip/src/pjsip/sip_multipart.c | 223 +++++++++++++++++++++++++++ - pjsip/src/test/multipart_test.c | 225 +++++++++++++++++++++++++++- - 3 files changed, 530 insertions(+), 1 deletion(-) - ---- a/pjsip/include/pjsip/sip_multipart.h -+++ b/pjsip/include/pjsip/sip_multipart.h -@@ -154,6 +154,89 @@ pjsip_multipart_find_part( const pjsip_m - const pjsip_multipart_part *start); - - /** -+ * Find a body inside multipart bodies which has a header matching the -+ * supplied one. Most useful for finding a part with a specific Content-ID. -+ * -+ * @param pool Memory pool to use for temp space. -+ * @param mp The multipart body. -+ * @param search_hdr Header to search for. -+ * @param start If specified, the search will begin at -+ * start->next part. Otherwise it will begin at -+ * the first part in the multipart bodies. -+ * -+ * @return The first part which has a header matching the -+ * specified one, or NULL if not found. -+ */ -+PJ_DECL(pjsip_multipart_part*) -+pjsip_multipart_find_part_by_header(pj_pool_t *pool, -+ const pjsip_msg_body *mp, -+ void *search_hdr, -+ const pjsip_multipart_part *start); -+ -+/** -+ * Find a body inside multipart bodies which has a header matching the -+ * supplied name and value. Most useful for finding a part with a specific -+ * Content-ID. -+ * -+ * @param pool Memory pool to use for temp space. -+ * @param mp The multipart body. -+ * @param hdr_name Header name to search for. -+ * @param hdr_value Header value search for. -+ * @param start If specified, the search will begin at -+ * start->next part. Otherwise it will begin at -+ * the first part in the multipart bodies. -+ * -+ * @return The first part which has a header matching the -+ * specified one, or NULL if not found. -+ */ -+PJ_DECL(pjsip_multipart_part*) -+pjsip_multipart_find_part_by_header_str(pj_pool_t *pool, -+ const pjsip_msg_body *mp, -+ const pj_str_t *hdr_name, -+ const pj_str_t *hdr_value, -+ const pjsip_multipart_part *start); -+ -+ -+ -+/** -+ * Find a body inside multipart bodies which has a Content-ID value matching the -+ * supplied "cid" URI in pj_str form. The "cid:" scheme will be assumed if the -+ * URL doesn't start with it. Enclosing angle brackets will also be handled -+ * correctly if they exist. -+ * -+ * @see RFC2392 Content-ID and Message-ID Uniform Resource Locators -+ * -+ * @param pool Memory pool to use for temp space. -+ * @param mp The multipart body. -+ * @param cid The "cid" URI to search for in pj_str form. -+ * -+ * @return The first part which has a Content-ID header matching the -+ * specified "cid" URI. or NULL if not found. -+ */ -+PJ_DECL(pjsip_multipart_part*) -+pjsip_multipart_find_part_by_cid_str(pj_pool_t *pool, -+ const pjsip_msg_body *mp, -+ pj_str_t *cid); -+ -+/** -+ * Find a body inside multipart bodies which has a Content-ID value matching the -+ * supplied "cid" URI. -+ * -+ * @see RFC2392 Content-ID and Message-ID Uniform Resource Locators -+ * -+ * @param pool Memory pool to use for temp space. -+ * @param mp The multipart body. -+ * @param cid The "cid" URI to search for. -+ * -+ * @return The first part which had a Content-ID header matching the -+ * specified "cid" URI. or NULL if not found. -+ */ -+PJ_DECL(pjsip_multipart_part*) -+pjsip_multipart_find_part_by_cid_uri(pj_pool_t *pool, -+ const pjsip_msg_body *mp, -+ pjsip_other_uri *cid_uri); -+ -+/** - * Parse multipart message. - * - * @param pool Memory pool. ---- a/pjsip/src/pjsip/sip_multipart.c -+++ b/pjsip/src/pjsip/sip_multipart.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -416,6 +417,220 @@ pjsip_multipart_find_part( const pjsip_m - return NULL; - } - -+/* -+ * Find a body inside multipart bodies which has the header and value. -+ */ -+PJ_DEF(pjsip_multipart_part*) -+pjsip_multipart_find_part_by_header_str(pj_pool_t *pool, -+ const pjsip_msg_body *mp, -+ const pj_str_t *hdr_name, -+ const pj_str_t *hdr_value, -+ const pjsip_multipart_part *start) -+{ -+ struct multipart_data *m_data; -+ pjsip_multipart_part *part; -+ pjsip_hdr *found_hdr; -+ pj_str_t found_hdr_str; -+ pj_str_t found_hdr_value; -+ pj_size_t expected_hdr_slen; -+ pj_size_t buf_size; -+ int hdr_name_len; -+#define REASONABLE_PADDING 32 -+#define SEPARATOR_LEN 2 -+ /* Must specify mandatory params */ -+ PJ_ASSERT_RETURN(mp && hdr_name && hdr_value, NULL); -+ -+ /* mp must really point to an actual multipart msg body */ -+ PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL); -+ -+ /* -+ * We'll need to "print" each header we find to test it but -+ * allocating a buffer of PJSIP_MAX_URL_SIZE is overkill. -+ * Instead, we'll allocate one large enough to hold the search -+ * header name, the ": " separator, the search hdr value, and -+ * the NULL terminator. If we can't print the found header -+ * into that buffer then it can't be a match. -+ * -+ * Some header print functions such as generic_int require enough -+ * space to print the maximum possible header length so we'll -+ * add a reasonable amount to the print buffer size. -+ */ -+ expected_hdr_slen = hdr_name->slen + SEPARATOR_LEN + hdr_value->slen; -+ buf_size = expected_hdr_slen + REASONABLE_PADDING; -+ found_hdr_str.ptr = pj_pool_alloc(pool, buf_size); -+ found_hdr_str.slen = 0; -+ hdr_name_len = hdr_name->slen + SEPARATOR_LEN; -+ -+ m_data = (struct multipart_data*)mp->data; -+ -+ if (start) -+ part = start->next; -+ else -+ part = m_data->part_head.next; -+ -+ while (part != &m_data->part_head) { -+ found_hdr = NULL; -+ while ((found_hdr = pjsip_hdr_find_by_name(&part->hdr, hdr_name, -+ (found_hdr ? found_hdr->next : NULL))) != NULL) { -+ -+ found_hdr_str.slen = pjsip_hdr_print_on((void*) found_hdr, found_hdr_str.ptr, buf_size); -+ /* -+ * If the buffer was too small (slen = -1) or the result wasn't -+ * the same length as the search header, it can't be a match. -+ */ -+ if (found_hdr_str.slen != expected_hdr_slen) { -+ continue; -+ } -+ /* -+ * Set the value overlay to start at the found header value... -+ */ -+ found_hdr_value.ptr = found_hdr_str.ptr + hdr_name_len; -+ found_hdr_value.slen = found_hdr_str.slen - hdr_name_len; -+ /* ...and compare it to the supplied header value. */ -+ if (pj_strcmp(hdr_value, &found_hdr_value) == 0) { -+ return part; -+ } -+ } -+ part = part->next; -+ } -+ return NULL; -+#undef SEPARATOR_LEN -+#undef REASONABLE_PADDING -+} -+ -+PJ_DEF(pjsip_multipart_part*) -+pjsip_multipart_find_part_by_header(pj_pool_t *pool, -+ const pjsip_msg_body *mp, -+ void *search_for, -+ const pjsip_multipart_part *start) -+{ -+ struct multipart_data *m_data; -+ pjsip_hdr *search_hdr = search_for; -+ pj_str_t search_buf; -+ -+ /* Must specify mandatory params */ -+ PJ_ASSERT_RETURN(mp && search_hdr, NULL); -+ -+ /* mp must really point to an actual multipart msg body */ -+ PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL); -+ -+ /* -+ * Unfortunately, there isn't enough information to determine -+ * the maximum printed size of search_hdr at this point so we -+ * have to allocate a reasonable max. -+ */ -+ search_buf.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); -+ search_buf.slen = pjsip_hdr_print_on(search_hdr, search_buf.ptr, PJSIP_MAX_URL_SIZE - 1); -+ if (search_buf.slen <= 0) { -+ return NULL; -+ } -+ /* -+ * Set the header value to start after the header name plus the ":", then -+ * strip leading and trailing whitespace. -+ */ -+ search_buf.ptr += (search_hdr->name.slen + 1); -+ search_buf.slen -= (search_hdr->name.slen + 1); -+ pj_strtrim(&search_buf); -+ -+ return pjsip_multipart_find_part_by_header_str(pool, mp, &search_hdr->name, &search_buf, start); -+} -+ -+/* -+ * Convert a Content-ID URI to it's corresponding header value. -+ * RFC2392 says... -+ * A "cid" URL is converted to the corresponding Content-ID message -+ * header by removing the "cid:" prefix, converting the % encoded -+ * character(s) to their equivalent US-ASCII characters, and enclosing -+ * the remaining parts with an angle bracket pair, "<" and ">". -+ * -+ * This implementation will accept URIs with or without the "cid:" -+ * scheme and optional angle brackets. -+ */ -+static pj_str_t cid_uri_to_hdr_value(pj_pool_t *pool, pj_str_t *cid_uri) -+{ -+ pj_size_t cid_len = pj_strlen(cid_uri); -+ pj_size_t alloc_len = cid_len + 2 /* for the leading and trailing angle brackets */; -+ pj_str_t uri_overlay; -+ pj_str_t cid_hdr; -+ pj_str_t hdr_overlay; -+ -+ pj_strassign(&uri_overlay, cid_uri); -+ /* If the URI is already enclosed in angle brackets, remove them. */ -+ if (uri_overlay.ptr[0] == '<') { -+ uri_overlay.ptr++; -+ uri_overlay.slen -= 2; -+ } -+ /* If the URI starts with the "cid:" scheme, skip over it. */ -+ if (pj_strncmp2(&uri_overlay, "cid:", 4) == 0) { -+ uri_overlay.ptr += 4; -+ uri_overlay.slen -= 4; -+ } -+ /* Start building */ -+ cid_hdr.ptr = pj_pool_alloc(pool, alloc_len); -+ cid_hdr.ptr[0] = '<'; -+ cid_hdr.slen = 1; -+ hdr_overlay.ptr = cid_hdr.ptr + 1; -+ hdr_overlay.slen = 0; -+ pj_strcpy_unescape(&hdr_overlay, &uri_overlay); -+ cid_hdr.slen += hdr_overlay.slen; -+ cid_hdr.ptr[cid_hdr.slen] = '>'; -+ cid_hdr.slen++; -+ -+ return cid_hdr; -+} -+ -+PJ_DEF(pjsip_multipart_part*) -+pjsip_multipart_find_part_by_cid_str(pj_pool_t *pool, -+ const pjsip_msg_body *mp, -+ pj_str_t *cid) -+{ -+ struct multipart_data *m_data; -+ pjsip_multipart_part *part; -+ pjsip_generic_string_hdr *found_hdr; -+ pj_str_t found_hdr_value; -+ static pj_str_t hdr_name = { "Content-ID", 10}; -+ pj_str_t hdr_value; -+ -+ PJ_ASSERT_RETURN(pool && mp && cid && (pj_strlen(cid) > 0), NULL); -+ -+ hdr_value = cid_uri_to_hdr_value(pool, cid); -+ if (pj_strlen(&hdr_value) == 0) { -+ return NULL; -+ } -+ -+ m_data = (struct multipart_data*)mp->data; -+ part = m_data->part_head.next; -+ -+ while (part != &m_data->part_head) { -+ found_hdr = NULL; -+ while ((found_hdr = pjsip_hdr_find_by_name(&part->hdr, &hdr_name, -+ (found_hdr ? found_hdr->next : NULL))) != NULL) { -+ if (pj_strcmp(&hdr_value, &found_hdr->hvalue) == 0) { -+ return part; -+ } -+ } -+ part = part->next; -+ } -+ return NULL; -+} -+ -+PJ_DEF(pjsip_multipart_part*) -+pjsip_multipart_find_part_by_cid_uri(pj_pool_t *pool, -+ const pjsip_msg_body *mp, -+ pjsip_other_uri *cid_uri) -+{ -+ PJ_ASSERT_RETURN(pool && mp && cid_uri, NULL); -+ -+ if (pj_strcmp2(&cid_uri->scheme, "cid") != 0) { -+ return NULL; -+ } -+ /* -+ * We only need to pass the URI content so we -+ * can do that directly. -+ */ -+ return pjsip_multipart_find_part_by_cid_str(pool, mp, &cid_uri->content); -+} -+ - /* Parse a multipart part. "pct" is parent content-type */ - static pjsip_multipart_part *parse_multipart_part(pj_pool_t *pool, - char *start, -@@ -584,6 +799,7 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_ - (int)boundary.slen, boundary.ptr)); - } - -+ - /* Build the delimiter: - * delimiter = "--" boundary - */ -@@ -630,6 +846,8 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_ - if (*curptr=='\r') ++curptr; - if (*curptr!='\n') { - /* Expecting a newline here */ -+ PJ_LOG(2, (THIS_FILE, "Failed to find newline")); -+ - return NULL; - } - ++curptr; -@@ -645,6 +863,7 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_ - curptr = pj_strstr(&subbody, &delim); - if (!curptr) { - /* We're really expecting end delimiter to be found. */ -+ PJ_LOG(2, (THIS_FILE, "Failed to find end-delimiter")); - return NULL; - } - } -@@ -670,9 +889,13 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_ - part = parse_multipart_part(pool, start_body, end_body - start_body, - ctype); - if (part) { -+ TRACE_((THIS_FILE, "Adding part")); - pjsip_multipart_add_part(pool, body, part); -+ } else { -+ PJ_LOG(2, (THIS_FILE, "Failed to add part")); - } - } -+ TRACE_((THIS_FILE, "pjsip_multipart_parse finished: %p", body)); - - return body; - } ---- a/pjsip/src/test/multipart_test.c -+++ b/pjsip/src/test/multipart_test.c -@@ -28,6 +28,7 @@ - typedef pj_status_t (*verify_ptr)(pj_pool_t*,pjsip_msg_body*); - - static pj_status_t verify1(pj_pool_t *pool, pjsip_msg_body *body); -+static pj_status_t verify2(pj_pool_t *pool, pjsip_msg_body *body); - - static struct test_t - { -@@ -68,7 +69,41 @@ static struct test_t - "This is epilogue, which should be ignored too", - - &verify1 -+ }, -+ { -+ /* Content-type */ -+ "multipart", "mixed", "12345", -+ -+ /* Body: */ -+ "This is the prolog, which should be ignored.\r\n" -+ "--12345\r\n" -+ "Content-Type: text/plain\r\n" -+ "Content-ID: \r\n" -+ "Content-ID: <\"header1\"@example.org>\r\n" -+ "Content-Length: 13\r\n" -+ "\r\n" -+ "has header1\r\n" -+ "--12345 \t\r\n" -+ "Content-Type: application/pidf+xml\r\n" -+ "Content-ID: \r\n" -+ "Content-ID: \r\n" -+ "Content-Length: 13\r\n" -+ "\r\n" -+ "has header2\r\n" -+ "--12345\r\n" -+ "Content-Type: text/plain\r\n" -+ "Content-ID: \r\n" -+ "Content-ID: \r\n" -+ "Content-ID: \r\n" -+ "Content-Length: 13\r\n" -+ "\r\n" -+ "has header4\r\n" -+ "--12345--\r\n" -+ "This is epilogue, which should be ignored too", -+ -+ &verify2 - } -+ - }; - - static void init_media_type(pjsip_media_type *mt, -@@ -87,6 +122,192 @@ static void init_media_type(pjsip_media_ - } - } - -+static int verify_hdr(pj_pool_t *pool, pjsip_msg_body *multipart_body, -+ void *hdr, char *part_body) -+{ -+ pjsip_media_type mt; -+ pjsip_multipart_part *part; -+ pj_str_t the_body; -+ -+ -+ part = pjsip_multipart_find_part_by_header(pool, multipart_body, hdr, NULL); -+ if (!part) { -+ return -1; -+ } -+ -+ the_body.ptr = (char*)part->body->data; -+ the_body.slen = part->body->len; -+ -+ if (pj_strcmp2(&the_body, part_body) != 0) { -+ return -2; -+ } -+ -+ return 0; -+} -+ -+static int verify_cid_str(pj_pool_t *pool, pjsip_msg_body *multipart_body, -+ pj_str_t cid_url, char *part_body) -+{ -+ pjsip_media_type mt; -+ pjsip_multipart_part *part; -+ pj_str_t the_body; -+ -+ part = pjsip_multipart_find_part_by_cid_str(pool, multipart_body, &cid_url); -+ if (!part) { -+ return -3; -+ } -+ -+ the_body.ptr = (char*)part->body->data; -+ the_body.slen = part->body->len; -+ -+ if (pj_strcmp2(&the_body, part_body) != 0) { -+ return -4; -+ } -+ -+ return 0; -+} -+ -+static int verify_cid_uri(pj_pool_t *pool, pjsip_msg_body *multipart_body, -+ pjsip_other_uri *cid_uri, char *part_body) -+{ -+ pjsip_media_type mt; -+ pjsip_multipart_part *part; -+ pj_str_t the_body; -+ -+ part = pjsip_multipart_find_part_by_cid_uri(pool, multipart_body, cid_uri); -+ if (!part) { -+ return -5; -+ } -+ -+ the_body.ptr = (char*)part->body->data; -+ the_body.slen = part->body->len; -+ -+ if (pj_strcmp2(&the_body, part_body) != 0) { -+ return -6; -+ } -+ -+ return 0; -+} -+ -+static pj_status_t verify2(pj_pool_t *pool, pjsip_msg_body *body) -+{ -+ int rc = 0; -+ int rcbase = 300; -+ pjsip_other_uri *cid_uri; -+ pjsip_ctype_hdr *ctype_hdr = pjsip_ctype_hdr_create(pool); -+ -+ ctype_hdr->media.type = pj_str("application"); -+ ctype_hdr->media.subtype = pj_str("pidf+xml"); -+ -+ rc = verify_hdr(pool, body, ctype_hdr, "has header2"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str("cid:header1@example.org"), "has header1"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str("%22header1%22@example.org"), "has header1"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "", -+ strlen(""), 0)); -+ rcbase += 10; -+ rc = verify_cid_uri(pool, body, cid_uri, "has header1"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str(""), "has header2"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str("cid:my%ffheader2@example.org"), "has header2"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "", -+ strlen(""), 0)); -+ rcbase += 10; -+ rc = verify_cid_uri(pool, body, cid_uri, "has header2"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str("cid:my%20header3@example.org"), "has header4"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str(""), "has header4"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "", -+ strlen(""), 0)); -+ rcbase += 10; -+ rc = verify_cid_uri(pool, body, cid_uri, "has header4"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str(""), "has header4"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ /* These should all fail for malformed or missing URI */ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str("cid:"), "has header4"); -+ if (!rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str(""), "has header4"); -+ if (!rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str("<>"), "has header4"); -+ if (!rc) { -+ return (rc - rcbase); -+ } -+ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str(""), "has header4"); -+ if (!rc) { -+ return (rc - rcbase); -+ } -+ -+ /* -+ * This is going to pass but the ' ' in the uri is un-encoded which is invalid -+ * so we should never see it. -+ */ -+ rcbase += 10; -+ rc = verify_cid_str(pool, body, pj_str("cid:my header3@example.org"), "has header4"); -+ if (rc) { -+ return (rc - rcbase); -+ } -+ -+ return 0; -+} -+ - static int verify_part(pjsip_multipart_part *part, - char *h_content_type, - char *h_content_subtype, -@@ -236,8 +457,10 @@ static int parse_test(void) - - pj_strdup2_with_null(pool, &str, p_tests[i].msg); - body = pjsip_multipart_parse(pool, str.ptr, str.slen, &ctype, 0); -- if (!body) -+ if (!body) { -+ pj_pool_release(pool); - return -100; -+ } - - if (p_tests[i].verify) { - rc = p_tests[i].verify(pool, body); -- cgit