瀏覽代碼

Use a faster compression logic in the response streaming.

silvioprog 6 年之前
父節點
當前提交
c07e15f394
共有 7 個文件被更改,包括 95 次插入69 次删除
  1. 1 0
      include/sagui.h
  2. 61 17
      src/sg_httpres.c
  3. 1 0
      src/sg_httpres.h
  4. 5 0
      src/sg_macros.h
  5. 27 42
      src/sg_utils.c
  6. 0 7
      src/sg_utils.h
  7. 0 3
      test/test_utils.c

+ 1 - 0
include/sagui.h

@@ -952,6 +952,7 @@ SG_EXTERN int sg_httpres_sendstream(struct sg_httpres *res, uint64_t size, sg_re
  * \retval ENOMEM Out of memory.
  * \retval ENOMEM Out of memory.
  * \retval ENOBUFS No buffer space available.
  * \retval ENOBUFS No buffer space available.
  * \retval EALREADY Operation already in progress.
  * \retval EALREADY Operation already in progress.
+ * \retval Z_<ERROR> zlib error as negative number.
  * \note When compression succeeds, the header `Content-Encoding: deflate` is automatically added to the response.
  * \note When compression succeeds, the header `Content-Encoding: deflate` is automatically added to the response.
  */
  */
 #define sg_httpres_zsend(res, val, content_type, status) \
 #define sg_httpres_zsend(res, val, content_type, status) \

+ 61 - 17
src/sg_httpres.c

@@ -47,29 +47,63 @@
 
 
 static ssize_t sg__httpres_zread_cb(void *handle, __SG_UNUSED uint64_t offset, char *dest, size_t size) {
 static ssize_t sg__httpres_zread_cb(void *handle, __SG_UNUSED uint64_t offset, char *dest, size_t size) {
     struct sg__httpres_zholder *holder = handle;
     struct sg__httpres_zholder *holder = handle;
-    void *buf;
     int errnum;
     int errnum;
-    buf = sg_malloc(size);
-    if (!buf)
-        return MHD_CONTENT_READER_END_WITH_ERROR;
-    size = (size_t) holder->read_cb(holder->handle, holder->offset, buf, size);
-    if (size == MHD_CONTENT_READER_END_WITH_ERROR || size == MHD_CONTENT_READER_END_OF_STREAM)
-        goto done;
+
+    size = (size_t) holder->read_cb(holder->handle, holder->offset, holder->buf, size);
     holder->offset += size;
     holder->offset += size;
-    sg__zdeflate(&holder->stream, buf, size, dest, &size, &errnum);
-    if (size == 0)
-        size = MHD_CONTENT_READER_END_OF_STREAM;
-done:
-    sg_free(buf);
-    return size;
+
+    switch (size) {
+        case MHD_CONTENT_READER_END_OF_STREAM: {
+            holder->stream.next_in = NULL;
+            holder->stream.avail_in = 0;
+            while (1) {
+                errnum = deflate(&holder->stream, Z_FINISH);
+                if (errnum < 0)
+                    if (errnum != Z_BUF_ERROR)
+                        return MHD_CONTENT_READER_END_WITH_ERROR;
+                if (errnum == Z_STREAM_END)
+                    break;
+                memcpy(dest, holder->buf, SG__ZBUF_SIZE - holder->stream.avail_out);
+
+                holder->stream.next_out = holder->buf;
+                holder->stream.avail_out = SG__ZBUF_SIZE;
+            }
+            size = SG__ZBUF_SIZE - holder->stream.avail_out;
+            if (holder->stream.avail_out < SG__ZBUF_SIZE)
+                memcpy(dest, holder->buf, size);
+            return size;
+        }
+        case MHD_CONTENT_READER_END_WITH_ERROR:
+            return size;
+        default:;
+    }
+
+    holder->stream.next_in = holder->buf;
+    holder->stream.avail_in = (uInt) size;
+
+    while (holder->stream.avail_in > 0) {
+        errnum = deflate(&holder->stream, Z_NO_FLUSH);
+        if (errnum < 0)
+            if (errnum != Z_BUF_ERROR)
+                return MHD_CONTENT_READER_END_WITH_ERROR;
+        if (holder->stream.avail_out == 0) {
+
+            memcpy(dest, holder->buf, SG__ZBUF_SIZE);
+
+            holder->stream.next_out = holder->buf;
+            holder->stream.avail_out = SG__ZBUF_SIZE;
+        }
+    }
+
+    return holder->stream.total_out;
 }
 }
 
 
 static void sg__httpres_zfree_cb(void *handle) {
 static void sg__httpres_zfree_cb(void *handle) {
     struct sg__httpres_zholder *holder = handle;
     struct sg__httpres_zholder *holder = handle;
-    int errnum;
     if (!holder)
     if (!holder)
         return;
         return;
-    sg__zend(&holder->stream, &errnum);
+    sg_free(holder->buf);
+    deflateEnd(&holder->stream);
     if (holder->free_cb)
     if (holder->free_cb)
         holder->free_cb(holder->handle);
         holder->free_cb(holder->handle);
     sg_free(holder);
     sg_free(holder);
@@ -272,7 +306,15 @@ int sg_httpres_zsendstream(struct sg_httpres *res, sg_read_cb read_cb, void *han
         errnum = ENOMEM;
         errnum = ENOMEM;
         goto error;
         goto error;
     }
     }
-    sg__zinit(&holder->stream, &errnum);
+    holder->buf = sg_malloc(SG__ZBUF_SIZE);
+    if (!holder->buf) {
+        errnum = ENOMEM;
+        goto error;
+    }
+    holder->stream.next_out = holder->buf;
+    holder->stream.avail_out = SG__ZBUF_SIZE;
+    errnum = deflateInit2(&holder->stream, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL,
+                          Z_DEFAULT_STRATEGY);
     if (errnum != Z_OK)
     if (errnum != Z_OK)
         goto error;
         goto error;
     holder->read_cb = read_cb;
     holder->read_cb = read_cb;
@@ -281,13 +323,15 @@ int sg_httpres_zsendstream(struct sg_httpres *res, sg_read_cb read_cb, void *han
     res->handle = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, SG__BLOCK_SIZE, sg__httpres_zread_cb, holder,
     res->handle = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, SG__BLOCK_SIZE, sg__httpres_zread_cb, holder,
                                                     sg__httpres_zfree_cb);
                                                     sg__httpres_zfree_cb);
     if (!res->handle) {
     if (!res->handle) {
-        sg__zend(&holder->stream, &errnum);
+        sg_free(holder->buf);
+        deflateEnd(&holder->stream);
         return ENOMEM;
         return ENOMEM;
     }
     }
     sg_strmap_set(&res->headers, MHD_HTTP_HEADER_CONTENT_ENCODING, "deflate");
     sg_strmap_set(&res->headers, MHD_HTTP_HEADER_CONTENT_ENCODING, "deflate");
     res->status = status;
     res->status = status;
     return 0;
     return 0;
 error:
 error:
+    sg_free(holder->buf);
     if (free_cb)
     if (free_cb)
         free_cb(handle);
         free_cb(handle);
     return errnum;
     return errnum;

+ 1 - 0
src/sg_httpres.h

@@ -53,6 +53,7 @@ struct sg__httpres_zholder {
     sg_free_cb free_cb;
     sg_free_cb free_cb;
     uint64_t offset;
     uint64_t offset;
     void *handle;
     void *handle;
+    void *buf;
 };
 };
 
 
 #endif
 #endif

+ 5 - 0
src/sg_macros.h

@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <string.h>
+#include <limits.h>
 #ifndef NDEBUG
 #ifndef NDEBUG
 #include <unistd.h>
 #include <unistd.h>
 #include <errno.h>
 #include <errno.h>
@@ -70,6 +71,10 @@
 #endif
 #endif
 #endif
 #endif
 
 
+#ifndef SG__ZBUF_SIZE
+#define SG__ZBUF_SIZE UINT16_MAX
+#endif
+
 /* used by utstring library */
 /* used by utstring library */
 #ifndef oom
 #ifndef oom
 #define oom() (void) 0
 #define oom() (void) 0

+ 27 - 42
src/sg_utils.c

@@ -196,52 +196,37 @@ bool sg__is_cookie_val(const char *val) {
 
 
 #ifdef SG_HTTP_COMPRESSION
 #ifdef SG_HTTP_COMPRESSION
 
 
-void sg__zinit(z_stream *stream, int *errnum) {
-    stream->zalloc = NULL;
-    stream->zfree = NULL;
-    stream->opaque = NULL;
-    *errnum = deflateInit2(stream, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
-}
-
-void sg__zend(z_stream *stream, int *errnum) {
-    int ret = deflateEnd(stream);
-    if (*errnum == Z_STREAM_END)
-        *errnum = ret;
-}
-
-void sg__zdeflate(z_stream *stream, const void *src, size_t src_size, void *dest, size_t *dest_size, int *errnum) {
-    const uInt max = (uInt) -1;
-    uLong left = *dest_size;
-    stream->next_out = dest;
-    stream->avail_out = 0;
-    stream->next_in = (z_const Bytef *) src;
-    stream->avail_in = 0;
-    do {
-        if (stream->avail_out == 0) {
-            stream->avail_out = left > (uLong) max ? max : (uInt) left;
-            left -= stream->avail_out;
-        }
-        if (stream->avail_in == 0) {
-            stream->avail_in = src_size > (uLong) max ? max : (uInt) src_size;
-            src_size -= stream->avail_in;
-        }
-        *errnum = deflate(stream, src_size ? Z_NO_FLUSH : Z_FINISH);
-    } while (*errnum == Z_OK);
-    *dest_size = stream->total_out;
-}
-
 int sg__compress(const void *src, size_t src_size, void *dest, size_t *dest_size) {
 int sg__compress(const void *src, size_t src_size, void *dest, size_t *dest_size) {
     z_stream stream;
     z_stream stream;
-    int errnum, saved_errnum;
-    sg__zinit(&stream, &errnum);
+    const uInt max = (uInt) -1;
+    uLong left;
+    int errnum;
+    left = *dest_size;
+    *dest_size = 0;
+    stream.zalloc = NULL;
+    stream.zfree = NULL;
+    stream.opaque = NULL;
+    errnum = deflateInit2(&stream, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
     if (errnum != Z_OK)
     if (errnum != Z_OK)
         return errnum;
         return errnum;
-    sg__zdeflate(&stream, src, src_size, dest, dest_size, &errnum);
-    saved_errnum = errnum;
-    sg__zend(&stream, &errnum);
-    if (saved_errnum != Z_OK && saved_errnum != Z_STREAM_END)
-        errnum = saved_errnum;
-    return errnum;
+    stream.next_out = dest;
+    stream.avail_out = 0;
+    stream.next_in = (z_const Bytef *) src;
+    stream.avail_in = 0;
+    do {
+        if (stream.avail_out == 0) {
+            stream.avail_out = left > (uLong) max ? max : (uInt) left;
+            left -= stream.avail_out;
+        }
+        if (stream.avail_in == 0) {
+            stream.avail_in = src_size > (uLong) max ? max : (uInt) src_size;
+            src_size -= stream.avail_in;
+        }
+        errnum = deflate(&stream, src_size ? Z_NO_FLUSH : Z_FINISH);
+    } while (errnum == Z_OK);
+    *dest_size = stream.total_out;
+    deflateEnd(&stream);
+    return errnum == Z_STREAM_END ? Z_OK : errnum;
 }
 }
 
 
 #endif
 #endif

+ 0 - 7
src/sg_utils.h

@@ -71,13 +71,6 @@ SG__EXTERN bool sg__is_cookie_val(const char *val);
 
 
 #ifdef SG_HTTP_COMPRESSION
 #ifdef SG_HTTP_COMPRESSION
 
 
-SG__EXTERN void sg__zinit(z_stream *stream, int *errnum);
-
-SG__EXTERN void sg__zend(z_stream *stream, int *errnum);
-
-SG__EXTERN void sg__zdeflate(z_stream *stream, const void *src, size_t src_size, void *dest, size_t *dest_size,
-                             int *errnum);
-
 SG__EXTERN int sg__compress(const void *src, size_t src_size, void *dest, size_t *dest_size);
 SG__EXTERN int sg__compress(const void *src, size_t src_size, void *dest, size_t *dest_size);
 
 
 #endif
 #endif

+ 0 - 3
test/test_utils.c

@@ -405,9 +405,6 @@ int main(void) {
     test__strjoin();
     test__strjoin();
     test__is_cookie_name();
     test__is_cookie_name();
     test__is_cookie_val();
     test__is_cookie_val();
-    /*TODO: test__zinit() */
-    /*TODO: test__zend() */
-    /*TODO: test__zdeflate() */
     /*TODO: test__compress() */
     /*TODO: test__compress() */
     test_version();
     test_version();
     test_malloc();
     test_malloc();