mod_zlib.inl 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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. #if !defined(MEM_LEVEL)
  6. #define MEM_LEVEL (8)
  7. #endif
  8. static void *
  9. zalloc(void *opaque, uInt items, uInt size)
  10. {
  11. struct mg_connection *conn = (struct mg_connection *)opaque;
  12. void *ret = mg_calloc_ctx(items, size, conn->phys_ctx);
  13. (void)conn; /* mg_calloc_ctx macro might not need it */
  14. return ret;
  15. }
  16. static void
  17. zfree(void *opaque, void *address)
  18. {
  19. struct mg_connection *conn = (struct mg_connection *)opaque;
  20. (void)conn; /* not required */
  21. mg_free(address);
  22. }
  23. static void
  24. send_compressed_data(struct mg_connection *conn, struct mg_file *filep)
  25. {
  26. int zret;
  27. z_stream zstream;
  28. int do_flush;
  29. unsigned bytes_avail;
  30. unsigned char in_buf[MG_BUF_LEN];
  31. unsigned char out_buf[MG_BUF_LEN];
  32. FILE *in_file = filep->access.fp;
  33. /* Prepare state buffer. User server context memory allocation. */
  34. memset(&zstream, 0, sizeof(zstream));
  35. zstream.zalloc = zalloc;
  36. zstream.zfree = zfree;
  37. zstream.opaque = (void *)conn;
  38. /* Initialize for GZIP compression (MAX_WBITS | 16) */
  39. zret = deflateInit2(&zstream,
  40. Z_BEST_COMPRESSION,
  41. Z_DEFLATED,
  42. MAX_WBITS | 16,
  43. MEM_LEVEL,
  44. Z_DEFAULT_STRATEGY);
  45. if (zret != Z_OK) {
  46. mg_cry_internal(conn,
  47. "GZIP init failed (%i): %s",
  48. zret,
  49. (zstream.msg ? zstream.msg : "<no error message>"));
  50. deflateEnd(&zstream);
  51. return;
  52. }
  53. /* Read until end of file */
  54. do {
  55. zstream.avail_in = fread(in_buf, 1, MG_BUF_LEN, in_file);
  56. if (ferror(in_file)) {
  57. mg_cry_internal(conn, "fread failed: %s", strerror(ERRNO));
  58. (void)deflateEnd(&zstream);
  59. return;
  60. }
  61. do_flush = (feof(in_file) ? Z_FINISH : Z_NO_FLUSH);
  62. zstream.next_in = in_buf;
  63. /* run deflate() on input until output buffer not full, finish
  64. * compression if all of source has been read in */
  65. do {
  66. zstream.avail_out = MG_BUF_LEN;
  67. zstream.next_out = out_buf;
  68. zret = deflate(&zstream, do_flush);
  69. if (zret == Z_STREAM_ERROR) {
  70. /* deflate error */
  71. zret = -97;
  72. break;
  73. }
  74. bytes_avail = MG_BUF_LEN - zstream.avail_out;
  75. if (bytes_avail) {
  76. if (mg_send_chunk(conn, (char *)out_buf, bytes_avail) < 0) {
  77. zret = -98;
  78. break;
  79. }
  80. }
  81. } while (zstream.avail_out == 0);
  82. if (zret < -90) {
  83. /* Forward write error */
  84. break;
  85. }
  86. if (zstream.avail_in != 0) {
  87. /* all input will be used, otherwise GZIP is incomplete */
  88. zret = -99;
  89. break;
  90. }
  91. /* done when last data in file processed */
  92. } while (do_flush != Z_FINISH);
  93. if (zret != Z_STREAM_END) {
  94. /* Error: We did not compress everything. */
  95. mg_cry_internal(conn,
  96. "GZIP incomplete (%i): %s",
  97. zret,
  98. (zstream.msg ? zstream.msg : "<no error message>"));
  99. }
  100. deflateEnd(&zstream);
  101. /* Send "end of chunked data" marker */
  102. mg_write(conn, "0\r\n\r\n", 5);
  103. }
  104. #if defined(USE_WEBSOCKET) && defined(MG_EXPERIMENTAL_INTERFACES)
  105. static int
  106. websocket_deflate_initialize(struct mg_connection *conn, int server)
  107. {
  108. int zret =
  109. deflateInit2(&conn->websocket_deflate_state,
  110. Z_BEST_COMPRESSION,
  111. Z_DEFLATED,
  112. server
  113. ? -1 * conn->websocket_deflate_server_max_windows_bits
  114. : -1 * conn->websocket_deflate_client_max_windows_bits,
  115. MEM_LEVEL,
  116. Z_DEFAULT_STRATEGY);
  117. if (zret != Z_OK) {
  118. mg_cry_internal(conn,
  119. "Websocket deflate init failed (%i): %s",
  120. zret,
  121. (conn->websocket_deflate_state.msg
  122. ? conn->websocket_deflate_state.msg
  123. : "<no error message>"));
  124. deflateEnd(&conn->websocket_deflate_state);
  125. return zret;
  126. }
  127. zret = inflateInit2(
  128. &conn->websocket_inflate_state,
  129. server ? -1 * conn->websocket_deflate_client_max_windows_bits
  130. : -1 * conn->websocket_deflate_server_max_windows_bits);
  131. if (zret != Z_OK) {
  132. mg_cry_internal(conn,
  133. "Websocket inflate init failed (%i): %s",
  134. zret,
  135. (conn->websocket_inflate_state.msg
  136. ? conn->websocket_inflate_state.msg
  137. : "<no error message>"));
  138. inflateEnd(&conn->websocket_inflate_state);
  139. return zret;
  140. }
  141. if ((conn->websocket_deflate_server_no_context_takeover && server)
  142. || (conn->websocket_deflate_client_no_context_takeover && !server))
  143. conn->websocket_deflate_flush = Z_FULL_FLUSH;
  144. else
  145. conn->websocket_deflate_flush = Z_SYNC_FLUSH;
  146. conn->websocket_deflate_initialized = 1;
  147. return Z_OK;
  148. }
  149. static void
  150. websocket_deflate_negotiate(struct mg_connection *conn)
  151. {
  152. const char *extensions = mg_get_header(conn, "Sec-WebSocket-Extensions");
  153. int val;
  154. if (extensions && !strncmp(extensions, "permessage-deflate", 18)) {
  155. conn->accept_gzip = 1;
  156. conn->websocket_deflate_client_max_windows_bits = 15;
  157. conn->websocket_deflate_server_max_windows_bits = 15;
  158. conn->websocket_deflate_server_no_context_takeover = 0;
  159. conn->websocket_deflate_client_no_context_takeover = 0;
  160. extensions += 18;
  161. while (*extensions != '\0') {
  162. if (*extensions == ';' || *extensions == ' ')
  163. ++extensions;
  164. else if (!strncmp(extensions, "server_no_context_takeover", 26)) {
  165. extensions += 26;
  166. conn->websocket_deflate_server_no_context_takeover = 1;
  167. } else if (!strncmp(extensions, "client_no_context_takeover", 26)) {
  168. extensions += 26;
  169. conn->websocket_deflate_client_no_context_takeover = 1;
  170. } else if (!strncmp(extensions, "server_max_window_bits", 22)) {
  171. extensions += 22;
  172. if (*extensions == '=') {
  173. ++extensions;
  174. if (*extensions == '"')
  175. ++extensions;
  176. val = 0;
  177. while (*extensions >= '0' && *extensions <= '9') {
  178. val = val * 10 + (*extensions - '0');
  179. ++extensions;
  180. }
  181. if (val < 9 || val > 15) {
  182. // The permessage-deflate spec specifies that a
  183. // value of 8 is also allowed, but zlib doesn't accept
  184. // that.
  185. mg_cry_internal(conn,
  186. "server-max-window-bits must be "
  187. "between 9 and 15. Got %i",
  188. val);
  189. } else
  190. conn->websocket_deflate_server_max_windows_bits = val;
  191. if (*extensions == '"')
  192. ++extensions;
  193. }
  194. } else if (!strncmp(extensions, "client_max_window_bits", 22)) {
  195. extensions += 22;
  196. if (*extensions == '=') {
  197. ++extensions;
  198. if (*extensions == '"')
  199. ++extensions;
  200. val = 0;
  201. while (*extensions >= '0' && *extensions <= '9') {
  202. val = val * 10 + (*extensions - '0');
  203. ++extensions;
  204. }
  205. if (val < 9 || val > 15)
  206. // The permessage-deflate spec specifies that a
  207. // value of 8 is also allowed, but zlib doesn't
  208. // accept that.
  209. mg_cry_internal(conn,
  210. "client-max-window-bits must be "
  211. "between 9 and 15. Got %i",
  212. val);
  213. else
  214. conn->websocket_deflate_client_max_windows_bits = val;
  215. if (*extensions == '"')
  216. ++extensions;
  217. }
  218. } else {
  219. mg_cry_internal(conn,
  220. "Unknown parameter %s for permessage-deflate",
  221. extensions);
  222. break;
  223. }
  224. }
  225. } else {
  226. conn->accept_gzip = 0;
  227. }
  228. conn->websocket_deflate_initialized = 0;
  229. }
  230. static void
  231. websocket_deflate_response(struct mg_connection *conn)
  232. {
  233. if (conn->accept_gzip) {
  234. mg_printf(conn,
  235. "Sec-WebSocket-Extensions: permessage-deflate; "
  236. "server_max_window_bits=%i; "
  237. "client_max_window_bits=%i"
  238. "%s%s\r\n",
  239. conn->websocket_deflate_server_max_windows_bits,
  240. conn->websocket_deflate_client_max_windows_bits,
  241. conn->websocket_deflate_client_no_context_takeover
  242. ? "; client_no_context_takeover"
  243. : "",
  244. conn->websocket_deflate_server_no_context_takeover
  245. ? "; server_no_context_takeover"
  246. : "");
  247. };
  248. }
  249. #endif