/* Experimental implementation for on-the-fly compression */ #if !defined(USE_ZLIB) #error "This file must only be included, if USE_ZLIB is set" #endif #include "zconf.h" #include "zlib.h" #if !defined(MEM_LEVEL) #define MEM_LEVEL (8) #endif static void * zalloc(void *opaque, uInt items, uInt size) { struct mg_connection *conn = (struct mg_connection *)opaque; void *ret = mg_calloc_ctx(items, size, conn->phys_ctx); return ret; } static void zfree(void *opaque, void *address) { struct mg_connection *conn = (struct mg_connection *)opaque; (void)conn; /* not required */ mg_free(address); } static void send_compressed_data(struct mg_connection *conn, struct mg_file *filep) { int zret; z_stream zstream; int do_flush; unsigned bytes_avail; unsigned char in_buf[MG_BUF_LEN]; unsigned char out_buf[MG_BUF_LEN]; FILE *in_file = filep->access.fp; /* Prepare state buffer. User server context memory allocation. */ memset(&zstream, 0, sizeof(zstream)); zstream.zalloc = zalloc; zstream.zfree = zfree; zstream.opaque = (void *)conn; /* Initialize for GZIP compression (MAX_WBITS | 16) */ zret = deflateInit2(&zstream, Z_BEST_COMPRESSION, Z_DEFLATED, MAX_WBITS | 16, MEM_LEVEL, Z_DEFAULT_STRATEGY); if (zret != Z_OK) { mg_cry_internal(conn, "GZIP init failed (%i): %s", zret, (zstream.msg ? zstream.msg : "")); deflateEnd(&zstream); return; } /* Read until end of file */ do { zstream.avail_in = fread(in_buf, 1, MG_BUF_LEN, in_file); if (ferror(in_file)) { mg_cry_internal(conn, "fread failed: %s", strerror(ERRNO)); (void)deflateEnd(&zstream); return; } do_flush = (feof(in_file) ? Z_FINISH : Z_NO_FLUSH); zstream.next_in = in_buf; /* run deflate() on input until output buffer not full, finish * compression if all of source has been read in */ do { zstream.avail_out = MG_BUF_LEN; zstream.next_out = out_buf; zret = deflate(&zstream, do_flush); if (zret == Z_STREAM_ERROR) { /* deflate error */ zret = -97; break; } bytes_avail = MG_BUF_LEN - zstream.avail_out; if (bytes_avail) { if (mg_send_chunk(conn, (char *)out_buf, bytes_avail) < 0) { zret = -98; break; } } } while (zstream.avail_out == 0); if (zret < -90) { /* Forward write error */ break; } if (zstream.avail_in != 0) { /* all input will be used, otherwise GZIP is incomplete */ zret = -99; break; } /* done when last data in file processed */ } while (do_flush != Z_FINISH); if (zret != Z_STREAM_END) { /* Error: We did not compress everything. */ mg_cry_internal(conn, "GZIP incomplete (%i): %s", zret, (zstream.msg ? zstream.msg : "")); } deflateEnd(&zstream); /* Send "end of chunked data" marker */ mg_write(conn, "0\r\n\r\n", 5); }