mod_zlib.inl 7.9 KB

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