introduce deflate compression extension
authorAndy Green <andy@warmcat.com>
Sun, 6 Mar 2011 13:32:53 +0000 (13:32 +0000)
committerAndy Green <andy@warmcat.com>
Sun, 6 Mar 2011 13:32:53 +0000 (13:32 +0000)
Signed-off-by: Andy Green <andy@warmcat.com>
lib/Makefile.am
lib/Makefile.in
lib/extension-deflate-stream.c [new file with mode: 0644]
lib/extension-deflate-stream.h [new file with mode: 0644]
lib/extension.c
lib/libwebsockets.c

index 3c17de6..b98e6ef 100644 (file)
@@ -7,6 +7,7 @@ dist_libwebsockets_la_SOURCES=libwebsockets.c \
                                base64-decode.c \
                                client-handshake.c \
                                extension.c \
+                               extension-deflate-stream.c \
                                private-libwebsockets.h
 if LIBCRYPTO
 else
index be10d3d..1ef72b3 100644 (file)
@@ -73,14 +73,16 @@ LTLIBRARIES = $(lib_LTLIBRARIES)
 libwebsockets_la_LIBADD =
 am__dist_libwebsockets_la_SOURCES_DIST = libwebsockets.c handshake.c \
        parsers.c libwebsockets.h base64-decode.c client-handshake.c \
-       extension.c private-libwebsockets.h md5.c sha-1.c
+       extension.c extension-deflate-stream.c private-libwebsockets.h \
+       md5.c sha-1.c
 @LIBCRYPTO_FALSE@am__objects_1 = libwebsockets_la-md5.lo \
 @LIBCRYPTO_FALSE@      libwebsockets_la-sha-1.lo
 dist_libwebsockets_la_OBJECTS = libwebsockets_la-libwebsockets.lo \
        libwebsockets_la-handshake.lo libwebsockets_la-parsers.lo \
        libwebsockets_la-base64-decode.lo \
        libwebsockets_la-client-handshake.lo \
-       libwebsockets_la-extension.lo $(am__objects_1)
+       libwebsockets_la-extension.lo \
+       libwebsockets_la-extension-deflate-stream.lo $(am__objects_1)
 libwebsockets_la_OBJECTS = $(dist_libwebsockets_la_OBJECTS)
 libwebsockets_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
        $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libwebsockets_la_CFLAGS) \
@@ -222,7 +224,8 @@ lib_LTLIBRARIES = libwebsockets.la
 include_HEADERS = libwebsockets.h
 dist_libwebsockets_la_SOURCES = libwebsockets.c handshake.c parsers.c \
        libwebsockets.h base64-decode.c client-handshake.c extension.c \
-       private-libwebsockets.h $(am__append_1)
+       extension-deflate-stream.c private-libwebsockets.h \
+       $(am__append_1)
 libwebsockets_la_CFLAGS := -rdynamic -fPIC -Wall -Werror -std=gnu99 -pedantic -c \
        -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
 
@@ -303,6 +306,7 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-base64-decode.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-client-handshake.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-extension-deflate-stream.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-extension.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-handshake.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-libwebsockets.Plo@am__quote@
@@ -373,6 +377,13 @@ libwebsockets_la-extension.lo: extension.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-extension.lo `test -f 'extension.c' || echo '$(srcdir)/'`extension.c
 
+libwebsockets_la-extension-deflate-stream.lo: extension-deflate-stream.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-extension-deflate-stream.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-extension-deflate-stream.Tpo -c -o libwebsockets_la-extension-deflate-stream.lo `test -f 'extension-deflate-stream.c' || echo '$(srcdir)/'`extension-deflate-stream.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/libwebsockets_la-extension-deflate-stream.Tpo $(DEPDIR)/libwebsockets_la-extension-deflate-stream.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='extension-deflate-stream.c' object='libwebsockets_la-extension-deflate-stream.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-extension-deflate-stream.lo `test -f 'extension-deflate-stream.c' || echo '$(srcdir)/'`extension-deflate-stream.c
+
 libwebsockets_la-md5.lo: md5.c
 @am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-md5.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-md5.Tpo -c -o libwebsockets_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
 @am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/libwebsockets_la-md5.Tpo $(DEPDIR)/libwebsockets_la-md5.Plo
diff --git a/lib/extension-deflate-stream.c b/lib/extension-deflate-stream.c
new file mode 100644 (file)
index 0000000..8d439df
--- /dev/null
@@ -0,0 +1,137 @@
+#include "private-libwebsockets.h"
+#include "extension-deflate-stream.h"
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+
+
+int lws_extension_callback_deflate_stream(
+       struct libwebsocket_context *context, struct libwebsocket *wsi,
+                       enum libwebsocket_extension_callback_reasons reason,
+                                              void *user, void *in, size_t len)
+{
+       struct lws_ext_deflate_stream_conn *conn =
+                                    (struct lws_ext_deflate_stream_conn *)user;
+       int n;
+       struct lws_tokens *eff_buf = (struct lws_tokens *)in;
+
+       switch (reason) {
+
+       /*
+        * for deflate-stream, both client and server sides act the same
+        */
+
+       case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT:
+       case LWS_EXT_CALLBACK_CONSTRUCT:
+               conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL;
+               conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL;
+               conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL;
+               n = inflateInit(&conn->zs_in);
+               if (n != Z_OK) {
+                       fprintf(stderr, "deflateInit returned %d\n", n);
+                       return 1;
+               }
+               n = deflateInit(&conn->zs_out,
+                                             DEFLATE_STREAM_COMPRESSION_LEVEL);
+               if (n != Z_OK) {
+                       fprintf(stderr, "deflateInit returned %d\n", n);
+                       return 1;
+               }
+               fprintf(stderr, "zlibs constructed\n");
+               break;
+
+       case LWS_EXT_CALLBACK_DESTROY:
+               (void)inflateEnd(&conn->zs_in);
+               (void)deflateEnd(&conn->zs_out);
+               fprintf(stderr, "zlibs destructed\n");
+               break;
+
+       case LWS_EXT_CALLBACK_PACKET_RX_PREPARSE:
+
+               /*
+                * inflate the incoming compressed data
+                * Notice, length may be 0 and pointer NULL
+                * in the case we are flushing with nothing new coming in
+                */
+
+               conn->zs_in.next_in = (unsigned char *)eff_buf->token;
+               conn->zs_in.avail_in = eff_buf->token_len;
+
+               conn->zs_in.next_out = conn->buf;
+               conn->zs_in.avail_out = sizeof(conn->buf);
+
+               n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
+               switch (n) {
+               case Z_NEED_DICT:
+               case Z_DATA_ERROR:
+               case Z_MEM_ERROR:
+                       /*
+                        * screwed.. close the connection... we will get a
+                        * destroy callback to take care of closing nicely
+                        */
+                       fprintf(stderr, "zlib error inflate %d\n", n);
+                       return -1;
+               }
+
+               /* rewrite the buffer pointers and length */
+
+               eff_buf->token = (char *)conn->buf;
+               eff_buf->token_len = sizeof(conn->buf) - conn->zs_in.avail_out;
+
+               /*
+                * if we filled the output buffer, signal that we likely have
+                * more and need to be called again
+                */
+
+               if (eff_buf->token_len == sizeof(conn->buf))
+                       return 1;
+
+               /* we don't need calling again until new input data comes */
+
+               return 0;
+
+       case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
+
+               /*
+                * deflate the outgoing compressed data
+                */
+
+               conn->zs_out.next_in = (unsigned char *)eff_buf->token;
+               conn->zs_out.avail_in = eff_buf->token_len;
+
+               conn->zs_out.next_out = conn->buf;
+               conn->zs_out.avail_out = sizeof(conn->buf);
+
+               n = deflate(&conn->zs_out, Z_PARTIAL_FLUSH);
+               if (n == Z_STREAM_ERROR) {
+                       /*
+                        * screwed.. close the connection... we will get a
+                        * destroy callback to take care of closing nicely
+                        */
+                       fprintf(stderr, "zlib error deflate\n");
+
+                       return -1;
+               }
+
+               /* rewrite the buffer pointers and length */
+
+               eff_buf->token = (char *)conn->buf;
+               eff_buf->token_len = sizeof(conn->buf) - conn->zs_out.avail_out;
+
+               /*
+                * if we filled the output buffer, signal that we likely have
+                * more and need to be called again... even in deflate case
+                * we might sometimes need to spill more than came in
+                */
+
+               if (eff_buf->token_len == sizeof(conn->buf))
+                       return 1;
+
+               /* we don't need calling again until new input data comes */
+
+               return 0;       
+       }
+
+       return 0;
+}
diff --git a/lib/extension-deflate-stream.h b/lib/extension-deflate-stream.h
new file mode 100644 (file)
index 0000000..ff43b47
--- /dev/null
@@ -0,0 +1,17 @@
+
+#include <zlib.h>
+
+#define DEFLATE_STREAM_CHUNK 128
+#define DEFLATE_STREAM_COMPRESSION_LEVEL 1
+
+struct lws_ext_deflate_stream_conn {
+       z_stream zs_in;
+       z_stream zs_out;
+       unsigned char buf[2000];
+};
+
+extern int lws_extension_callback_deflate_stream(
+       struct libwebsocket_context *context,
+                       struct libwebsocket *wsi,
+                       enum libwebsocket_extension_callback_reasons reason,
+                                             void *user, void *in, size_t len);
index 16d62d9..df62bd5 100644 (file)
@@ -1,6 +1,13 @@
 #include "private-libwebsockets.h"
 
+#include "extension-deflate-stream.h"
+
 struct libwebsocket_extension libwebsocket_internal_extensions[] = {
+       {
+               "deflate-stream",
+               lws_extension_callback_deflate_stream,
+               sizeof (struct lws_ext_deflate_stream_conn)
+       },
        { /* terminator */
                NULL, NULL, 0
        }
index efce3db..c6aca20 100644 (file)
@@ -557,7 +557,6 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
        int okay = 0;
        char ext_name[128];
        struct lws_tokens eff_buf;
-       int more = 1;
        int ext_count = 0;
        struct libwebsocket_extension *ext;