]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
* modules/filters/mod_deflate.c (consume_buffer, flush_libz_buffer):
authorJoe Orton <jorton@apache.org>
Wed, 8 Apr 2026 14:15:36 +0000 (14:15 +0000)
committerJoe Orton <jorton@apache.org>
Wed, 8 Apr 2026 14:15:36 +0000 (14:15 +0000)
  Refactor to use flags parameter instead of int for controlling CRC
  updates and bucket type. Add TRANSIENT flag to create transient
  buckets when buffer content will be immediately sent down the filter
  chain.
  (deflate_out_filter, inflate_out_filter): Use transient buckets when
  flushing full output buffers.

Github: closes #622

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1932904 13f79535-47bb-0310-9956-ffa450edef68

changes-entries/deflate-transient.txt [new file with mode: 0644]
modules/filters/mod_deflate.c

diff --git a/changes-entries/deflate-transient.txt b/changes-entries/deflate-transient.txt
new file mode 100644 (file)
index 0000000..cf1bedc
--- /dev/null
@@ -0,0 +1,2 @@
+  *) mod_deflate: Reduce CPU/RAM consumption in output filters
+     by using transient buckets.  [Joe Orton]
index ad753dc61811726e0327f5229a5e04bb0fcb2d2c..ca5d7f9b8caf79d9e098e476802ed8c128c7c77b 100644 (file)
@@ -412,13 +412,18 @@ typedef struct deflate_ctx_t
 
 /* Number of validation bytes (CRC and length) after the compressed data */
 #define VALIDATION_SIZE 8
+
 /* Do not update ctx->crc, see comment in flush_libz_buffer */
-#define NO_UPDATE_CRC 0
+#define NO_UPDATE_CRC 0x0
 /* Do update ctx->crc, see comment in flush_libz_buffer */
-#define UPDATE_CRC 1
+#define UPDATE_CRC    0x1
+/* Use a transient bucket, which is ONLY safe if the bucket will be
+ * passed down the filter chain immediately before the zlib stream is
+ * used again. */
+#define TRANSIENT     0x2
 
 static void consume_buffer(deflate_ctx *ctx, deflate_filter_config *c,
-                           int len, int crc, apr_bucket_brigade *bb)
+                           int len, unsigned int flags, apr_bucket_brigade *bb)
 {
     apr_bucket *b;
 
@@ -427,12 +432,16 @@ static void consume_buffer(deflate_ctx *ctx, deflate_filter_config *c,
      * inflate action where we need to do a crc on the output, whereas
      * in the deflate case we need to do a crc on the input
      */
-    if (crc) {
+    if (flags & UPDATE_CRC) {
         ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
     }
 
-    b = apr_bucket_heap_create((char *)ctx->buffer, len, NULL,
-                               bb->bucket_alloc);
+    if (flags & TRANSIENT)
+        b = apr_bucket_transient_create((char *)ctx->buffer, len,
+                                        bb->bucket_alloc);
+    else
+        b = apr_bucket_heap_create((char *)ctx->buffer, len, NULL,
+                                   bb->bucket_alloc);
     APR_BRIGADE_INSERT_TAIL(bb, b);
 
     ctx->stream.next_out = ctx->buffer;
@@ -441,7 +450,7 @@ static void consume_buffer(deflate_ctx *ctx, deflate_filter_config *c,
 
 static int flush_libz_buffer(deflate_ctx *ctx, deflate_filter_config *c,
                              int (*libz_func)(z_streamp, int), int flush,
-                             int crc)
+                             unsigned int flags)
 {
     int zRC = Z_OK;
     int done = 0;
@@ -450,7 +459,7 @@ static int flush_libz_buffer(deflate_ctx *ctx, deflate_filter_config *c,
     for (;;) {
          deflate_len = c->bufferSize - ctx->stream.avail_out;
          if (deflate_len > 0) {
-             consume_buffer(ctx, c, deflate_len, crc, ctx->bb);
+             consume_buffer(ctx, c, deflate_len, flags, ctx->bb);
          }
 
          if (done)
@@ -1019,7 +1028,10 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
 
         while (ctx->stream.avail_in != 0) {
             if (ctx->stream.avail_out == 0) {
-                consume_buffer(ctx, c, c->bufferSize, NO_UPDATE_CRC, ctx->bb);
+                /* Use a transient bucket since it will be sent down
+                 * the filter chain immediately. */
+                consume_buffer(ctx, c, c->bufferSize,
+                               NO_UPDATE_CRC|TRANSIENT, ctx->bb);
 
                 /* Send what we have right now to the next filter. */
                 rv = ap_pass_brigade(f->next, ctx->bb);
@@ -1840,7 +1852,10 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
 
         while (ctx->stream.avail_in != 0) {
             if (ctx->stream.avail_out == 0) {
-                consume_buffer(ctx, c, c->bufferSize, UPDATE_CRC, ctx->bb);
+                /* Use a transient bucket since it will be sent down
+                 * the filter chain immediately. */
+                consume_buffer(ctx, c, c->bufferSize,
+                               UPDATE_CRC|TRANSIENT, ctx->bb);
 
                 /* Send what we have right now to the next filter. */
                 rv = ap_pass_brigade(f->next, ctx->bb);