1/* Experimental implementation for on-the-fly compression */ 2#if !defined(USE_ZLIB) 3#error "This file must only be included, if USE_ZLIB is set" 4#endif 5 6#include "zconf.h" 7#include "zlib.h" 8 9#if !defined(MEM_LEVEL) 10#define MEM_LEVEL (8) 11#endif 12 13static void * 14zalloc(void *opaque, uInt items, uInt size) 15{ 16 struct mg_connection *conn = (struct mg_connection *)opaque; 17 void *ret = mg_calloc_ctx(items, size, conn->phys_ctx); 18 19 return ret; 20} 21 22 23static void 24zfree(void *opaque, void *address) 25{ 26 struct mg_connection *conn = (struct mg_connection *)opaque; 27 (void)conn; /* not required */ 28 29 mg_free(address); 30} 31 32 33static void 34send_compressed_data(struct mg_connection *conn, struct mg_file *filep) 35{ 36 37 int zret; 38 z_stream zstream; 39 int do_flush; 40 unsigned bytes_avail; 41 unsigned char in_buf[MG_BUF_LEN]; 42 unsigned char out_buf[MG_BUF_LEN]; 43 FILE *in_file = filep->access.fp; 44 45 /* Prepare state buffer. User server context memory allocation. */ 46 memset(&zstream, 0, sizeof(zstream)); 47 zstream.zalloc = zalloc; 48 zstream.zfree = zfree; 49 zstream.opaque = (void *)conn; 50 51 /* Initialize for GZIP compression (MAX_WBITS | 16) */ 52 zret = deflateInit2(&zstream, 53 Z_BEST_COMPRESSION, 54 Z_DEFLATED, 55 MAX_WBITS | 16, 56 MEM_LEVEL, 57 Z_DEFAULT_STRATEGY); 58 59 if (zret != Z_OK) { 60 mg_cry_internal(conn, 61 "GZIP init failed (%i): %s", 62 zret, 63 (zstream.msg ? zstream.msg : "<no error message>")); 64 deflateEnd(&zstream); 65 return; 66 } 67 68 /* Read until end of file */ 69 do { 70 zstream.avail_in = fread(in_buf, 1, MG_BUF_LEN, in_file); 71 if (ferror(in_file)) { 72 mg_cry_internal(conn, "fread failed: %s", strerror(ERRNO)); 73 (void)deflateEnd(&zstream); 74 return; 75 } 76 77 do_flush = (feof(in_file) ? Z_FINISH : Z_NO_FLUSH); 78 zstream.next_in = in_buf; 79 80 /* run deflate() on input until output buffer not full, finish 81 * compression if all of source has been read in */ 82 do { 83 zstream.avail_out = MG_BUF_LEN; 84 zstream.next_out = out_buf; 85 zret = deflate(&zstream, do_flush); 86 87 if (zret == Z_STREAM_ERROR) { 88 /* deflate error */ 89 zret = -97; 90 break; 91 } 92 93 bytes_avail = MG_BUF_LEN - zstream.avail_out; 94 if (bytes_avail) { 95 if (mg_send_chunk(conn, (char *)out_buf, bytes_avail) < 0) { 96 zret = -98; 97 break; 98 } 99 } 100 101 } while (zstream.avail_out == 0); 102 103 if (zret < -90) { 104 /* Forward write error */ 105 break; 106 } 107 108 if (zstream.avail_in != 0) { 109 /* all input will be used, otherwise GZIP is incomplete */ 110 zret = -99; 111 break; 112 } 113 114 /* done when last data in file processed */ 115 } while (do_flush != Z_FINISH); 116 117 if (zret != Z_STREAM_END) { 118 /* Error: We did not compress everything. */ 119 mg_cry_internal(conn, 120 "GZIP incomplete (%i): %s", 121 zret, 122 (zstream.msg ? zstream.msg : "<no error message>")); 123 } 124 125 deflateEnd(&zstream); 126 127 /* Send "end of chunked data" marker */ 128 mg_write(conn, "0\r\n\r\n", 5); 129} 130