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..c9b11216dd26 --- /dev/null +++ b/ext/mysqli/tests/mysqli_compression_packet_sizes.phpt @@ -0,0 +1,46 @@ +--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); + } +} + +$stmt = $link->prepare("SELECT HEX(?)"); +for ($i = 0; $i < 200; $i++) { + $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!"; +?> +--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