From 3e9a9979f016496a0804255aa3ce02e5297aa1b3 Mon Sep 17 00:00:00 2001 From: Nikita Massalitin <17572243+lohmag@users.noreply.github.com> Date: Sun, 25 Oct 2026 23:16:06 +0200 Subject: [PATCH 1/2] mysqlnd: Do not compress packets smaller than 512 bytes --- .../mysqli_compression_packet_sizes.phpt | 39 +++++++++++++++++++ ext/mysqlnd/mysqlnd_protocol_frame_codec.c | 3 +- ext/mysqlnd/mysqlnd_wireprotocol.h | 2 + 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 ext/mysqli/tests/mysqli_compression_packet_sizes.phpt diff --git a/ext/mysqli/tests/mysqli_compression_packet_sizes.phpt b/ext/mysqli/tests/mysqli_compression_packet_sizes.phpt new file mode 100644 index 000000000000..51a748cfe313 --- /dev/null +++ b/ext/mysqli/tests/mysqli_compression_packet_sizes.phpt @@ -0,0 +1,39 @@ +--TEST-- +Compressed protocol: packets on both sides of the compression threshold +--EXTENSIONS-- +mysqli +--SKIPIF-- + +--FILE-- +query("SHOW SESSION STATUS LIKE 'Compression'")->fetch_row()[1]); + +foreach ([1, 230, 235, 236, 237, 238, 240, 600, 4000, 100000, 3000000] as $length) { + $value = substr(str_repeat('compressed protocol packet ', intdiv($length, 27) + 1), 0, $length); + $row = $link->query("SELECT '$value' AS v, LENGTH('$value') AS l")->fetch_assoc(); + if ($row['v'] !== $value || (int) $row['l'] !== $length) { + printf("[002] Round trip failed for %d bytes\n", $length); + } +} + +for ($i = 0; $i < 200; $i++) { + $value = bin2hex(random_bytes(1 + $i * 37)); + if ($link->query("SELECT '$value' AS v")->fetch_assoc()['v'] !== $value) { + printf("[003] Round trip failed for %d bytes\n", strlen($value)); + } +} + +$link->close(); +print "done!"; +?> +--EXPECT-- +string(2) "ON" +done! diff --git a/ext/mysqlnd/mysqlnd_protocol_frame_codec.c b/ext/mysqlnd/mysqlnd_protocol_frame_codec.c index 70a81befdd71..2663a101ed0a 100644 --- a/ext/mysqlnd/mysqlnd_protocol_frame_codec.c +++ b/ext/mysqlnd/mysqlnd_protocol_frame_codec.c @@ -55,7 +55,8 @@ static ssize_t write_compressed_packet( /* here we need to compress the data and then write it, first comes the compressed header */ size_t tmp_complen = to_be_sent; size_t payload_size; - if (PASS == pfc->data->m.encode((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, + if (to_be_sent >= MYSQLND_MIN_COMPRESS_LENGTH + && PASS == pfc->data->m.encode((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, uncompressed_payload, to_be_sent)) { int3store(compress_buf + MYSQLND_HEADER_SIZE, to_be_sent); diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h index ad452ec4f928..134c389ced04 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.h +++ b/ext/mysqlnd/mysqlnd_wireprotocol.h @@ -18,6 +18,8 @@ #define MYSQLND_HEADER_SIZE 4 #define COMPRESSED_HEADER_SIZE 3 +/* Packets smaller than this are sent uncompressed: they barely shrink. */ +#define MYSQLND_MIN_COMPRESS_LENGTH 512 #define MYSQLND_NULL_LENGTH (zend_ulong) ~0 From 3d3b1c94765a9d3b59cad35fae18eb3a32624967 Mon Sep 17 00:00:00 2001 From: Nikita Massalitin <17572243+lohmag@users.noreply.github.com> Date: Mon, 26 Oct 2026 15:53:05 +0200 Subject: [PATCH 2/2] Use incompressible data in the compression packet size test --- ext/mysqli/tests/mysqli_compression_packet_sizes.phpt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ext/mysqli/tests/mysqli_compression_packet_sizes.phpt b/ext/mysqli/tests/mysqli_compression_packet_sizes.phpt index 51a748cfe313..c9b11216dd26 100644 --- a/ext/mysqli/tests/mysqli_compression_packet_sizes.phpt +++ b/ext/mysqli/tests/mysqli_compression_packet_sizes.phpt @@ -24,12 +24,19 @@ foreach ([1, 230, 235, 236, 237, 238, 240, 600, 4000, 100000, 3000000] as $lengt } } +$stmt = $link->prepare("SELECT HEX(?)"); for ($i = 0; $i < 200; $i++) { - $value = bin2hex(random_bytes(1 + $i * 37)); - if ($link->query("SELECT '$value' AS v")->fetch_assoc()['v'] !== $value) { + $value = random_bytes(1 + $i * 37); + $stmt->bind_param('s', $value); + $stmt->execute(); + $stmt->bind_result($hex); + $stmt->fetch(); + $stmt->free_result(); + if ($hex !== strtoupper(bin2hex($value))) { printf("[003] Round trip failed for %d bytes\n", strlen($value)); } } +$stmt->close(); $link->close(); print "done!";