From fb36b3e9e06ba2b50163c34c99adf0257d5c0d12 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 23 Nov 2022 22:05:29 +0000 Subject: clone: support sha256 --- ci/test.sh | 19 ++++++ src/libgit2/oid.h | 41 ++++++++++++ src/libgit2/transports/smart.h | 7 +- src/libgit2/transports/smart_pkt.c | 111 +++++++++++++++++++++++++++----- src/libgit2/transports/smart_protocol.c | 13 ++-- tests/libgit2/CMakeLists.txt | 1 + tests/libgit2/online/clone.c | 17 +++++ tests/libgit2/transports/smart/packet.c | 37 +++++++---- 8 files changed, 212 insertions(+), 34 deletions(-) diff --git a/ci/test.sh b/ci/test.sh index 0e1d39e8d..4b15ea936 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -32,6 +32,11 @@ cleanup() { kill $GIT_NAMESPACE_PID fi + if [ ! -z "$GIT_SHA256_PID" ]; then + echo "Stopping git daemon (sha256)..." + kill $GIT_SHA256_PID + fi + if [ ! -z "$PROXY_BASIC_PID" ]; then echo "Stopping proxy (Basic)..." kill $PROXY_BASIC_PID @@ -114,6 +119,12 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then cp -R "${SOURCE_DIR}/tests/resources/namespace.git" "${GIT_NAMESPACE_DIR}/namespace.git" GIT_NAMESPACE="name1" git daemon --listen=localhost --port=9419 --export-all --enable=receive-pack --base-path="${GIT_NAMESPACE_DIR}" "${GIT_NAMESPACE_DIR}" & GIT_NAMESPACE_PID=$! + + echo "Starting git daemon (sha256)..." + GIT_SHA256_DIR=`mktemp -d ${TMPDIR}/git_sha256.XXXXXXXX` + cp -R "${SOURCE_DIR}/tests/resources/testrepo_256.git" "${GIT_SHA256_DIR}/testrepo_256.git" + git daemon --listen=localhost --port=9420 --export-all --enable=receive-pack --base-path="${GIT_SHA256_DIR}" "${GIT_SHA256_DIR}" & + GIT_SHA256_PID=$! fi if [ -z "$SKIP_PROXY_TESTS" ]; then @@ -256,6 +267,14 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then run_test gitdaemon_namespace unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_BRANCH + + echo "" + echo "Running gitdaemon (sha256) tests" + echo "" + + export GITTEST_REMOTE_URL="git://localhost:9419/testrepo_sha256.git" + run_test gitdaemon_sha256 + unset GITTEST_REMOTE_URL fi if [ -z "$SKIP_PROXY_TESTS" ]; then diff --git a/src/libgit2/oid.h b/src/libgit2/oid.h index d775e180b..7b6b09d8b 100644 --- a/src/libgit2/oid.h +++ b/src/libgit2/oid.h @@ -66,6 +66,47 @@ GIT_INLINE(size_t) git_oid_hexsize(git_oid_t type) return 0; } +GIT_INLINE(const char *) git_oid_type_name(git_oid_t type) +{ + switch (type) { + case GIT_OID_SHA1: + return "sha1"; + +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + return "sha256"; +#endif + } + + return "unknown"; +} + +GIT_INLINE(git_oid_t) git_oid_type_fromstr(const char *name) +{ + if (strcmp(name, "sha1") == 0) + return GIT_OID_SHA1; + +#ifdef GIT_EXPERIMENTAL_SHA256 + if (strcmp(name, "sha256") == 0) + return GIT_OID_SHA256; +#endif + + return 0; +} + +GIT_INLINE(git_oid_t) git_oid_type_fromstrn(const char *name, size_t len) +{ + if (len == CONST_STRLEN("sha1") && strncmp(name, "sha1", len) == 0) + return GIT_OID_SHA1; + +#ifdef GIT_EXPERIMENTAL_SHA256 + if (len == CONST_STRLEN("sha256") && strncmp(name, "sha256", len) == 0) + return GIT_OID_SHA256; +#endif + + return 0; +} + GIT_INLINE(git_hash_algorithm_t) git_oid_algorithm(git_oid_t type) { switch (type) { diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index 9323d6c44..ca6496163 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -182,7 +182,12 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream int git_smart__update_heads(transport_smart *t, git_vector *symrefs); /* smart_pkt.c */ -int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen); +typedef struct { + git_oid_t oid_type; + int seen_capabilities: 1; +} git_pkt_parse_data; + +int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen, git_pkt_parse_data *data); int git_pkt_buffer_flush(git_str *buf); int git_pkt_send_flush(GIT_SOCKET s); int git_pkt_buffer_done(git_str *buf); diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index e679819fa..b6428d845 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -212,26 +212,87 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) return 0; } +static int set_data( + git_pkt_parse_data *data, + const char *line, + size_t len) +{ + const char *caps, *format_str = NULL, *eos; + size_t format_len; + git_oid_t remote_oid_type; + + GIT_ASSERT_ARG(data); + + if ((caps = memchr(line, '\0', len)) != NULL) { + caps++; + + if (strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0) + format_str = caps + CONST_STRLEN("object-format="); + else if ((format_str = strstr(caps, " object-format=")) != NULL) + format_str += CONST_STRLEN(" object-format="); + } + + if (format_str) { + if ((eos = strchr(format_str, ' ')) == NULL) + eos = strchr(format_str, '\0'); + + GIT_ASSERT(eos); + + format_len = eos - format_str; + + if ((remote_oid_type = git_oid_type_fromstrn(format_str, format_len)) == 0) { + git_error_set(GIT_ERROR_INVALID, "unknown remote object format '%.*s'", (int)format_len, format_str); + return -1; + } + } else { + remote_oid_type = GIT_OID_SHA1; + } + + if (!data->oid_type) { + data->oid_type = remote_oid_type; + } else if (data->oid_type != remote_oid_type) { + git_error_set(GIT_ERROR_INVALID, + "the local object format '%s' does not match the remote object format '%s'", + git_oid_type_name(data->oid_type), + git_oid_type_name(remote_oid_type)); + return -1; + } + + return 0; +} + /* * Parse an other-ref line. */ -static int ref_pkt(git_pkt **out, const char *line, size_t len) +static int ref_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) { git_pkt_ref *pkt; - size_t alloclen; + size_t alloclen, oid_hexsize; pkt = git__calloc(1, sizeof(git_pkt_ref)); GIT_ERROR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_REF; - if (len < GIT_OID_SHA1_HEXSIZE || - git_oid__fromstr(&pkt->head.oid, line, GIT_OID_SHA1) < 0) + /* Determine OID type from capabilities */ + if (!data->seen_capabilities && set_data(data, line, len) < 0) + return -1; + + GIT_ASSERT(data->oid_type); + oid_hexsize = git_oid_hexsize(data->oid_type); + + if (len < oid_hexsize || + git_oid__fromstr(&pkt->head.oid, line, data->oid_type) < 0) goto out_err; - line += GIT_OID_SHA1_HEXSIZE; - len -= GIT_OID_SHA1_HEXSIZE; + line += oid_hexsize; + len -= oid_hexsize; if (git__prefixncmp(line, len, " ")) goto out_err; + line++; len--; @@ -248,8 +309,14 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len) memcpy(pkt->head.name, line, len); pkt->head.name[len] = '\0'; - if (strlen(pkt->head.name) < len) - pkt->capabilities = strchr(pkt->head.name, '\0') + 1; + if (strlen(pkt->head.name) < len) { + if (!data->seen_capabilities) + pkt->capabilities = strchr(pkt->head.name, '\0') + 1; + else + goto out_err; + } + + data->seen_capabilities = 1; *out = (git_pkt *)pkt; return 0; @@ -418,7 +485,11 @@ static int parse_len(size_t *out, const char *line, size_t linelen) */ int git_pkt_parse_line( - git_pkt **pkt, const char **endptr, const char *line, size_t linelen) + git_pkt **pkt, + const char **endptr, + const char *line, + size_t linelen, + git_pkt_parse_data *data) { int error; size_t len; @@ -493,7 +564,7 @@ int git_pkt_parse_line( else if (!git__prefixncmp(line, len, "unpack")) error = unpack_pkt(pkt, line, len); else - error = ref_pkt(pkt, line, len); + error = ref_pkt(pkt, line, len, data); *endptr = line + len; @@ -533,8 +604,11 @@ int git_pkt_buffer_flush(git_str *buf) static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_str *buf) { git_str str = GIT_STR_INIT; - char oid[GIT_OID_SHA1_HEXSIZE +1] = {0}; - size_t len; + char oid[GIT_OID_MAX_HEXSIZE + 1] = {0}; + size_t oid_hexsize, len; + + oid_hexsize = git_oid_hexsize(head->oid.type); + git_oid_fmt(oid, &head->oid); /* Prefer multi_ack_detailed */ if (caps->multi_ack_detailed) @@ -560,7 +634,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca if (git_str_oom(&str)) return -1; - len = strlen("XXXXwant ") + GIT_OID_SHA1_HEXSIZE + 1 /* NUL */ + + len = strlen("XXXXwant ") + oid_hexsize + 1 /* NUL */ + git_str_len(&str) + 1 /* LF */; if (len > 0xffff) { @@ -570,9 +644,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca } git_str_grow_by(buf, len); - git_oid_fmt(oid, &head->oid); git_str_printf(buf, - "%04xwant %s %s\n", (unsigned int)len, oid, git_str_cstr(&str)); + "%04xwant %.*s %s\n", (unsigned int)len, + (int)oid_hexsize, oid, git_str_cstr(&str)); git_str_dispose(&str); GIT_ERROR_CHECK_ALLOC_STR(buf); @@ -608,16 +682,19 @@ int git_pkt_buffer_wants( } for (; i < count; ++i) { - char oid[GIT_OID_SHA1_HEXSIZE]; + char oid[GIT_OID_MAX_HEXSIZE]; head = refs[i]; + if (head->local) continue; git_oid_fmt(oid, &head->oid); + git_str_put(buf, pkt_want_prefix, strlen(pkt_want_prefix)); - git_str_put(buf, oid, GIT_OID_SHA1_HEXSIZE); + git_str_put(buf, oid, git_oid_hexsize(head->oid.type)); git_str_putc(buf, '\n'); + if (git_str_oom(buf)) return -1; } diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 09778b335..7fc5f1669 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -32,6 +32,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) int error, flush = 0, recvd; const char *line_end = NULL; git_pkt *pkt = NULL; + git_pkt_parse_data pkt_parse_data = { 0 }; size_t i; /* Clear existing refs in case git_remote_connect() is called again @@ -45,7 +46,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) do { if (buf->offset > 0) - error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset); + error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset, &pkt_parse_data); else error = GIT_EBUFS; @@ -228,11 +229,12 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf { const char *ptr = buf->data, *line_end = ptr; git_pkt *pkt = NULL; + git_pkt_parse_data pkt_parse_data = { 0 }; int error = 0, ret; do { if (buf->offset > 0) - error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset); + error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset, &pkt_parse_data); else error = GIT_EBUFS; @@ -723,6 +725,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt) static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_str *data_pkt_buf) { git_pkt *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; const char *line, *line_end = NULL; size_t line_len; int error; @@ -741,7 +744,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, } while (line_len > 0) { - error = git_pkt_parse_line(&pkt, &line_end, line, line_len); + error = git_pkt_parse_line(&pkt, &line_end, line, line_len, &pkt_parse_data); if (error == GIT_EBUFS) { /* Buffer the data when the inner packet is split @@ -777,6 +780,7 @@ done: static int parse_report(transport_smart *transport, git_push *push) { git_pkt *pkt = NULL; + git_pkt_parse_data pkt_parse_data = { 0 }; const char *line_end = NULL; gitno_buffer *buf = &transport->buffer; int error, recvd; @@ -785,7 +789,8 @@ static int parse_report(transport_smart *transport, git_push *push) for (;;) { if (buf->offset > 0) error = git_pkt_parse_line(&pkt, &line_end, - buf->data, buf->offset); + buf->data, buf->offset, + &pkt_parse_data); else error = GIT_EBUFS; diff --git a/tests/libgit2/CMakeLists.txt b/tests/libgit2/CMakeLists.txt index 17f2253f0..69bb302af 100644 --- a/tests/libgit2/CMakeLists.txt +++ b/tests/libgit2/CMakeLists.txt @@ -70,6 +70,7 @@ add_clar_test(libgit2_tests online -v -sonline -xonline::customcert add_clar_test(libgit2_tests online_customcert -v -sonline::customcert) add_clar_test(libgit2_tests gitdaemon -v -sonline::push) add_clar_test(libgit2_tests gitdaemon_namespace -v -sonline::clone::namespace) +add_clar_test(libgit2_tests gitdaemon_sha256 -v -sonline::clone::sha256) add_clar_test(libgit2_tests ssh -v -sonline::push -sonline::clone::ssh_cert -sonline::clone::ssh_with_paths -sonline::clone::path_whitespace_ssh) add_clar_test(libgit2_tests proxy -v -sonline::clone::proxy) add_clar_test(libgit2_tests auth_clone -v -sonline::clone::cred) diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 96ff66ae0..8f89ba5cf 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -1058,3 +1058,20 @@ void test_online_clone__namespace_with_specified_branch(void) git_reference_free(head); } + +void test_online_clone__sha256(void) +{ + git_clone_options options = GIT_CLONE_OPTIONS_INIT; + git_reference *head; + + if (!_remote_url) + cl_skip(); + + cl_git_pass(git_clone(&g_repo, _remote_url, "./sha256", &options)); + cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); + cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head)); + + abort(); + + git_reference_free(head); +} diff --git a/tests/libgit2/transports/smart/packet.c b/tests/libgit2/transports/smart/packet.c index 8801ef833..2035e3b65 100644 --- a/tests/libgit2/transports/smart/packet.c +++ b/tests/libgit2/transports/smart/packet.c @@ -11,8 +11,9 @@ static void assert_flush_parses(const char *line) size_t linelen = strlen(line) + 1; const char *endptr; git_pkt *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_FLUSH); cl_assert_equal_strn(endptr, line + 4, linelen - 4); @@ -24,8 +25,9 @@ static void assert_data_pkt_parses(const char *line, const char *expected_data, size_t linelen = strlen(line) + 1; const char *endptr; git_pkt_data *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_DATA); cl_assert_equal_i(pkt->len, expected_len); cl_assert_equal_strn(pkt->data, expected_data, expected_len); @@ -38,8 +40,9 @@ static void assert_sideband_progress_parses(const char *line, const char *expect size_t linelen = strlen(line) + 1; const char *endptr; git_pkt_progress *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_PROGRESS); cl_assert_equal_i(pkt->len, expected_len); cl_assert_equal_strn(pkt->data, expected_data, expected_len); @@ -52,8 +55,9 @@ static void assert_error_parses(const char *line, const char *expected_error, si size_t linelen = strlen(line) + 1; const char *endptr; git_pkt_err *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_ERR); cl_assert_equal_i(pkt->len, expected_len); cl_assert_equal_strn(pkt->error, expected_error, expected_len); @@ -67,10 +71,11 @@ static void assert_ack_parses(const char *line, const char *expected_oid, enum g const char *endptr; git_pkt_ack *pkt; git_oid oid; + git_pkt_parse_data pkt_parse_data = { 0 }; cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1)); - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_ACK); cl_assert_equal_oid(&pkt->oid, &oid); cl_assert_equal_i(pkt->status, expected_status); @@ -83,8 +88,9 @@ static void assert_nak_parses(const char *line) size_t linelen = strlen(line) + 1; const char *endptr; git_pkt *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_NAK); cl_assert_equal_strn(endptr, line + 7, linelen - 7); @@ -96,8 +102,9 @@ static void assert_comment_parses(const char *line, const char *expected_comment size_t linelen = strlen(line) + 1; const char *endptr; git_pkt_comment *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_COMMENT); cl_assert_equal_strn(pkt->comment, expected_comment, strlen(expected_comment)); @@ -109,8 +116,9 @@ static void assert_ok_parses(const char *line, const char *expected_ref) size_t linelen = strlen(line) + 1; const char *endptr; git_pkt_ok *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_OK); cl_assert_equal_strn(pkt->ref, expected_ref, strlen(expected_ref)); @@ -122,8 +130,9 @@ static void assert_unpack_parses(const char *line, bool ok) size_t linelen = strlen(line) + 1; const char *endptr; git_pkt_unpack *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_UNPACK); cl_assert_equal_i(pkt->unpack_ok, ok); @@ -135,8 +144,9 @@ static void assert_ng_parses(const char *line, const char *expected_ref, const c size_t linelen = strlen(line) + 1; const char *endptr; git_pkt_ng *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_NG); cl_assert_equal_strn(pkt->ref, expected_ref, strlen(expected_ref)); cl_assert_equal_strn(pkt->msg, expected_msg, strlen(expected_msg)); @@ -153,10 +163,11 @@ static void assert_ref_parses_(const char *line, size_t linelen, const char *exp const char *endptr; git_pkt_ref *pkt; git_oid oid; + git_pkt_parse_data pkt_parse_data = { 0 }; cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1)); - cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data)); cl_assert_equal_i(pkt->type, GIT_PKT_REF); cl_assert_equal_oid(&pkt->head.oid, &oid); cl_assert_equal_strn(pkt->head.name, expected_ref, strlen(expected_ref)); @@ -171,8 +182,10 @@ static void assert_ref_parses_(const char *line, size_t linelen, const char *exp static void assert_pkt_fails(const char *line) { const char *endptr; + git_pkt_parse_data pkt_parse_data = { 0 }; + git_pkt *pkt; - cl_git_fail(git_pkt_parse_line(&pkt, &endptr, line, strlen(line) + 1)); + cl_git_fail(git_pkt_parse_line(&pkt, &endptr, line, strlen(line) + 1, &pkt_parse_data)); } void test_transports_smart_packet__parsing_garbage_fails(void) -- cgit v1.2.1