Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions ext/mysqli/tests/fake_server.inc
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,15 @@ class my_mysqli_fake_server_conn
fprintf(STDERR, "[*] Received: %s\n", bin2hex($data));
}

public function read_compressed_packet(): void
{
$header = $this->read_bytes(7);
$compressed_length = ord($header[0]) | (ord($header[1]) << 8) | (ord($header[2]) << 16);
$uncompressed_length = ord($header[4]) | (ord($header[5]) << 8) | (ord($header[6]) << 16);
$this->read_bytes($compressed_length);
fprintf(STDERR, "[*] Received compressed packet: %d bytes, uncompressed length %d\n", $compressed_length, $uncompressed_length);
}

public function close()
{
fclose($this->conn);
Expand Down Expand Up @@ -1445,6 +1454,19 @@ function my_mysqli_test_stmt_response_field_len_premature(my_mysqli_fake_server_
$conn->read(65536);
}

function my_mysqli_test_compressed_queries(my_mysqli_fake_server_conn $conn): void
{
$conn->send_server_greetings();
$conn->read();
$conn->send_server_ok();
for ($i = 0; $i < 2; $i++) {
$conn->read_compressed_packet();
$ok = $conn->packet_generator->server_ok("01")->to_bytes();
$conn->send(substr(pack('V', strlen($ok)), 0, 3) . "\x01\x00\x00\x00" . $ok, "Compressed Server OK");
}
$conn->read_compressed_packet();
}

function run_fake_server(string $test_function, int|string $port = 0): void
{
$host = '127.0.0.1';
Expand Down
43 changes: 43 additions & 0 deletions ext/mysqli/tests/mysqli_compression_threshold.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
--TEST--
Compressed protocol: packets below the threshold are sent uncompressed
--EXTENSIONS--
mysqli
--SKIPIF--
<?php
ob_start();
if (extension_loaded('mysqlnd')) {
(new ReflectionExtension('mysqlnd'))->info();
}
if (!str_contains(ob_get_clean(), 'Compression => supported')) {
die('skip mysqlnd is built without compression support');
}
?>
--FILE--
<?php
require_once 'fake_server.inc';

$process = run_fake_server_in_background('compressed_queries');
$process->wait();

$link = mysqli_init();
$link->real_connect('127.0.0.1', 'root', '', '', $process->getPort(), null, MYSQLI_CLIENT_COMPRESS);
var_dump($link->query("SELECT '" . str_repeat('a', 80) . "'"));
var_dump($link->query("SELECT '" . str_repeat('a', 1000) . "'"));
$link->close();

$process->terminate(true);
?>
--EXPECTF--
[*] Server started on 127.0.0.1:%d
[*] Connection established
[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
[*] Received: %s
[*] Sending - Server OK: 0700000200000002000000
[*] Received compressed packet: 94 bytes, uncompressed length 0
[*] Sending - Compressed Server OK: 0b0000010000000700000100000002000000
bool(true)
[*] Received compressed packet: %d bytes, uncompressed length 1014
[*] Sending - Compressed Server OK: 0b0000010000000700000100000002000000
bool(true)
[*] Received compressed packet: 5 bytes, uncompressed length 0
[*] Server finished
3 changes: 2 additions & 1 deletion ext/mysqlnd/mysqlnd_protocol_frame_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions ext/mysqlnd/mysqlnd_wireprotocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 100

#define MYSQLND_NULL_LENGTH (zend_ulong) ~0

Expand Down
Loading