Skip to content

Commit 9894306

Browse files
committed
feat: dictionary support in output handler
1 parent b01ccfa commit 9894306

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

brotli.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <php.h>
66
#include <SAPI.h>
77
#include <php_ini.h>
8+
#include <ext/standard/file.h>
89
#include <ext/standard/info.h>
910
#include <ext/standard/php_smart_string.h>
1011
#if defined(HAVE_APCU_SUPPORT)
@@ -356,16 +357,78 @@ static int php_brotli_output_encoding(void)
356357
return BROTLI_G(compression_coding);
357358
}
358359

360+
static zend_string *php_brotli_output_handler_load_dict(php_brotli_context *ctx)
361+
{
362+
char *file = BROTLI_G(output_compression_dict);
363+
if (!file || strlen(file) == 0) {
364+
return NULL;
365+
}
366+
367+
#if defined(USE_BROTLI_DICTIONARY)
368+
php_stream *stream = NULL;
369+
zval *zcontext = NULL;
370+
php_stream_context *context = NULL;
371+
zend_long maxlen = (ssize_t) PHP_STREAM_COPY_ALL;
372+
373+
context = php_stream_context_from_zval(zcontext, 0);
374+
stream = php_stream_open_wrapper_ex(file, "rb",
375+
REPORT_ERRORS,
376+
NULL, context);
377+
if (!stream) {
378+
php_error_docref(NULL, E_WARNING,
379+
"brotli: failed to load dictionary");
380+
return NULL;
381+
}
382+
383+
if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
384+
php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
385+
PHP_STREAM_BUFFER_NONE, NULL);
386+
}
387+
388+
/* dictionary size limit:
389+
zend_off_t file_size = php_stream_tell(stream);
390+
if (file_size < 0 || file_size > (64 * 1024)) {
391+
php_error_docref(NULL, E_WARNING,
392+
"brotli: dictionary size (%lld bytes) "
393+
"exceeds 64 KiB limit",
394+
(long long)file_size);
395+
php_stream_close(stream);
396+
return NULL;
397+
}
398+
*/
399+
400+
zend_string *dict = php_stream_copy_to_mem(stream, maxlen, 0);
401+
402+
php_stream_close(stream);
403+
404+
return dict;
405+
#else
406+
php_error_docref(NULL, E_WARNING,
407+
"brotli: not supported compression dictionary");
408+
return NULL;
409+
#endif
410+
}
411+
359412
static int php_brotli_output_handler_context_start(php_brotli_context *ctx)
360413
{
361414
long level = BROTLI_G(output_compression_level);
415+
zend_string *dict = php_brotli_output_handler_load_dict(ctx);
416+
if (!BROTLI_G(compression_coding)) {
417+
if (dict) {
418+
zend_string_release(dict);
419+
}
420+
return FAILURE;
421+
}
362422

363423
int result = php_brotli_context_create_encoder_ex(ctx,
364424
level,
365425
BROTLI_DEFAULT_WINDOW,
366426
BROTLI_MODE_GENERIC,
367427
dict,
368428
0);
429+
if (dict) {
430+
zend_string_release(dict);
431+
}
369432

370433
return result;
371434
}
@@ -633,6 +696,9 @@ PHP_INI_BEGIN()
633696
TOSTRING(BROTLI_DEFAULT_QUALITY),
634697
PHP_INI_ALL, OnUpdateLong, output_compression_level,
635698
zend_brotli_globals, brotli_globals)
699+
STD_PHP_INI_ENTRY("brotli.output_compression_dict", "",
700+
PHP_INI_ALL, OnUpdateString, output_compression_dict,
701+
zend_brotli_globals, brotli_globals)
636702
PHP_INI_END()
637703

638704
static void php_brotli_init_globals(zend_brotli_globals *brotli_globals)

php_brotli.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ ZEND_BEGIN_MODULE_GLOBALS(brotli)
3434
zend_long output_compression;
3535
zend_long output_compression_default;
3636
zend_long output_compression_level;
37+
char *output_compression_dict;
3738
zend_bool handler_registered;
3839
int compression_coding;
3940
php_brotli_context *ob_handler;

0 commit comments

Comments
 (0)