|  | @@ -441,6 +441,11 @@ _civet_safe_clock_gettime(int clk_id, struct timespec *t)
 | 
	
		
			
				|  |  |  	(((err) == EAGAIN) || ((err) == EWOULDBLOCK) || ((err) == EINTR))
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | +#include "zconf.h"
 | 
	
		
			
				|  |  | +#include "zlib.h"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /********************************************************************/
 | 
	
		
			
				|  |  |  /* CivetWeb configuration defines */
 | 
	
	
		
			
				|  | @@ -2960,23 +2965,6 @@ enum {
 | 
	
		
			
				|  |  |  	PROTOCOL_TYPE_HTTP2 = 2
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#define mg_cry_internal(conn, fmt, ...)                                        \
 | 
	
		
			
				|  |  | -	mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#define mg_cry_ctx_internal(ctx, fmt, ...)                                     \
 | 
	
		
			
				|  |  | -	mg_cry_internal_wrap(NULL, ctx, __func__, __LINE__, fmt, __VA_ARGS__)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static void mg_cry_internal_wrap(const struct mg_connection *conn,
 | 
	
		
			
				|  |  | -                                 struct mg_context *ctx,
 | 
	
		
			
				|  |  | -                                 const char *func,
 | 
	
		
			
				|  |  | -                                 unsigned line,
 | 
	
		
			
				|  |  | -                                 const char *fmt,
 | 
	
		
			
				|  |  | -                                 ...) PRINTF_ARGS(5, 6);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -#include "mod_zlib.inl"
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  struct mg_connection {
 | 
	
		
			
				|  |  |  	int connection_type; /* see CONNECTION_TYPE_* above */
 | 
	
		
			
				|  |  |  	int protocol_type;   /* see PROTOCOL_TYPE_*: 0=http/1.x, 1=ws, 2=http/2 */
 | 
	
	
		
			
				|  | @@ -3027,17 +3015,18 @@ struct mg_connection {
 | 
	
		
			
				|  |  |  	                       * pages */
 | 
	
		
			
				|  |  |  #if defined(USE_WEBSOCKET)
 | 
	
		
			
				|  |  |  	int in_websocket_handling; /* 1 if in read_websocket */
 | 
	
		
			
				|  |  | -#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -	/* Parameters for websocket data compression according to https://tools.ietf.org/html/rfc7692 */
 | 
	
		
			
				|  |  | -    int websocket_deflate_server_max_windows_bits;
 | 
	
		
			
				|  |  | -    int websocket_deflate_client_max_windows_bits;
 | 
	
		
			
				|  |  | -    int websocket_deflate_server_no_context_takeover;
 | 
	
		
			
				|  |  | -    int websocket_deflate_client_no_context_takeover;
 | 
	
		
			
				|  |  | -    int websocket_deflate_initialized;
 | 
	
		
			
				|  |  | -    int websocket_deflate_flush;
 | 
	
		
			
				|  |  | -    z_stream websocket_deflate_state;
 | 
	
		
			
				|  |  | -    z_stream websocket_inflate_state;
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB) && defined(USE_WEBSOCKET)                                \
 | 
	
		
			
				|  |  | +    && defined(MG_EXPERIMENTAL_INTERFACES)
 | 
	
		
			
				|  |  | +	/* Parameters for websocket data compression according to rfc7692 */
 | 
	
		
			
				|  |  | +	int websocket_deflate_server_max_windows_bits;
 | 
	
		
			
				|  |  | +	int websocket_deflate_client_max_windows_bits;
 | 
	
		
			
				|  |  | +	int websocket_deflate_server_no_context_takeover;
 | 
	
		
			
				|  |  | +	int websocket_deflate_client_no_context_takeover;
 | 
	
		
			
				|  |  | +	int websocket_deflate_initialized;
 | 
	
		
			
				|  |  | +	int websocket_deflate_flush;
 | 
	
		
			
				|  |  | +	z_stream websocket_deflate_state;
 | 
	
		
			
				|  |  | +	z_stream websocket_inflate_state;
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  	int handled_requests; /* Number of requests handled by this connection
 | 
	
		
			
				|  |  |  	                       */
 | 
	
	
		
			
				|  | @@ -3069,6 +3058,20 @@ struct de {
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define mg_cry_internal(conn, fmt, ...)                                        \
 | 
	
		
			
				|  |  | +	mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define mg_cry_ctx_internal(ctx, fmt, ...)                                     \
 | 
	
		
			
				|  |  | +	mg_cry_internal_wrap(NULL, ctx, __func__, __LINE__, fmt, __VA_ARGS__)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void mg_cry_internal_wrap(const struct mg_connection *conn,
 | 
	
		
			
				|  |  | +                                 struct mg_context *ctx,
 | 
	
		
			
				|  |  | +                                 const char *func,
 | 
	
		
			
				|  |  | +                                 unsigned line,
 | 
	
		
			
				|  |  | +                                 const char *fmt,
 | 
	
		
			
				|  |  | +                                 ...) PRINTF_ARGS(5, 6);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #if !defined(NO_THREAD_NAME)
 | 
	
		
			
				|  |  |  #if defined(_WIN32) && defined(_MSC_VER)
 | 
	
		
			
				|  |  |  /* Set the thread name for debugging purposes in Visual Studio
 | 
	
	
		
			
				|  | @@ -4297,71 +4300,6 @@ get_req_headers(const struct mg_request_info *ri,
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#if defined(USE_WEBSOCKET) && defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -int websocket_deflate_initialize(struct mg_connection *conn) {
 | 
	
		
			
				|  |  | -  fflush(stdout);
 | 
	
		
			
				|  |  | -  z_stream websocket_deflate_state;
 | 
	
		
			
				|  |  | -  int websocket_deflate_server_max_windows_bits;
 | 
	
		
			
				|  |  | -  int websocket_deflate_client_max_windows_bits;
 | 
	
		
			
				|  |  | -  int websocket_deflate_server_no_context_takeover;
 | 
	
		
			
				|  |  | -  int websocket_deflate_client_no_context_takeover;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  uint8_t deflate_bits;
 | 
	
		
			
				|  |  | -  uint8_t inflate_bits;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // if (server)
 | 
	
		
			
				|  |  | -  deflate_bits = conn->websocket_deflate_server_max_windows_bits;
 | 
	
		
			
				|  |  | -  inflate_bits = conn->websocket_deflate_client_max_windows_bits;
 | 
	
		
			
				|  |  | -  /*
 | 
	
		
			
				|  |  | -      deflate_bits = conn->websocket_deflate_client_max_windows_bits;
 | 
	
		
			
				|  |  | -      inflate_bits = conn->websocket_deflate_server_max_windows_bits;
 | 
	
		
			
				|  |  | -      */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  int ret = deflateInit2(&conn->websocket_deflate_state, Z_DEFAULT_COMPRESSION,
 | 
	
		
			
				|  |  | -                         Z_DEFLATED, -1 * deflate_bits,
 | 
	
		
			
				|  |  | -                         4,  // memory level 1-9
 | 
	
		
			
				|  |  | -                         Z_DEFAULT_STRATEGY);
 | 
	
		
			
				|  |  | -  if (ret != Z_OK) return ret;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  ret = inflateInit2(&conn->websocket_inflate_state, -1 * inflate_bits);
 | 
	
		
			
				|  |  | -  if (ret != Z_OK) return ret;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /*
 | 
	
		
			
				|  |  | -  if ((m_server_no_context_takeover && is_server) ||
 | 
	
		
			
				|  |  | -      (m_client_no_context_takeover && !is_server)) {
 | 
	
		
			
				|  |  | -      */
 | 
	
		
			
				|  |  | -  conn->websocket_deflate_flush = Z_FULL_FLUSH;
 | 
	
		
			
				|  |  | -  //} else
 | 
	
		
			
				|  |  | -  //  conn->websocket_deflate_flush = Z_SYNC_FLUSH;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  conn->websocket_deflate_initialized = 1;
 | 
	
		
			
				|  |  | -  return Z_OK;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void websocket_deflate_negotiate(struct mg_connection *conn) {
 | 
	
		
			
				|  |  | -  const char *extensions = mg_get_header(conn, "Sec-WebSocket-Extensions");
 | 
	
		
			
				|  |  | -  if (extensions && strstr(extensions, "permessage-deflate")) {
 | 
	
		
			
				|  |  | -    conn->accept_gzip = 1;
 | 
	
		
			
				|  |  | -    conn->websocket_deflate_client_max_windows_bits = 15;
 | 
	
		
			
				|  |  | -    conn->websocket_deflate_server_max_windows_bits = 15;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    conn->accept_gzip = 0;
 | 
	
		
			
				|  |  | -    conn->websocket_deflate_client_max_windows_bits = 0;
 | 
	
		
			
				|  |  | -    conn->websocket_deflate_server_max_windows_bits = 0;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  conn->websocket_deflate_initialized = 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void websocket_deflate_response(struct mg_connection *conn) {
 | 
	
		
			
				|  |  | -  if (conn->accept_gzip) {
 | 
	
		
			
				|  |  | -    mg_printf(conn,
 | 
	
		
			
				|  |  | -              "Sec-WebSocket-Extensions: permessage-deflate; "
 | 
	
		
			
				|  |  | -              "client_no_context_takeover; server_no_context_takeover\r\n");
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  const char *
 | 
	
		
			
				|  |  |  mg_get_header(const struct mg_connection *conn, const char *name)
 | 
	
		
			
				|  |  |  {
 | 
	
	
		
			
				|  | @@ -10118,6 +10056,11 @@ fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | +#include "mod_zlib.inl"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #if !defined(NO_FILESYSTEMS)
 | 
	
		
			
				|  |  |  static void
 | 
	
		
			
				|  |  |  handle_static_file_request(struct mg_connection *conn,
 | 
	
	
		
			
				|  | @@ -12608,12 +12551,12 @@ send_websocket_handshake(struct mg_connection *conn, const char *websock_key)
 | 
	
		
			
				|  |  |  	          "Connection: Upgrade\r\n"
 | 
	
		
			
				|  |  |  	          "Sec-WebSocket-Accept: %s\r\n",
 | 
	
		
			
				|  |  |  	          b64_sha);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -    // Send negotiated compression extension parameters
 | 
	
		
			
				|  |  | -    websocket_deflate_response(conn);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
 | 
	
		
			
				|  |  | +	// Send negotiated compression extension parameters
 | 
	
		
			
				|  |  | +	websocket_deflate_response(conn);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	if (conn->request_info.acceptedWebSocketSubprotocol) {
 | 
	
		
			
				|  |  |  		mg_printf(conn,
 | 
	
		
			
				|  |  |  		          "Sec-WebSocket-Protocol: %s\r\n\r\n",
 | 
	
	
		
			
				|  | @@ -12852,51 +12795,73 @@ read_websocket(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			} else {
 | 
	
		
			
				|  |  |  				/* Exit the loop if callback signals to exit (server side),
 | 
	
		
			
				|  |  |  				 * or "connection close" opcode received (client side). */
 | 
	
		
			
				|  |  | -				if (ws_data_handler != NULL) {
 | 
	
		
			
				|  |  | -#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -				  if (mop & 0x40) {
 | 
	
		
			
				|  |  | -					/* Inflate the data received if bit RSV1 is set. */
 | 
	
		
			
				|  |  | -					if (!conn->websocket_deflate_initialized) {
 | 
	
		
			
				|  |  | -					  if (websocket_deflate_initialize(conn) != Z_OK)
 | 
	
		
			
				|  |  | -						exit_by_callback = 1;
 | 
	
		
			
				|  |  | -					}
 | 
	
		
			
				|  |  | -					if (!exit_by_callback) {
 | 
	
		
			
				|  |  | -					  Bytef *inflated = mg_calloc(10 * 1024 * 1024, sizeof(Bytef));
 | 
	
		
			
				|  |  | -					  // Add trailing 0x00 0x00 0xff 0xff bytes
 | 
	
		
			
				|  |  | -					  data[data_len] = '\x00';
 | 
	
		
			
				|  |  | -					  data[data_len + 1] = '\x00';
 | 
	
		
			
				|  |  | -					  data[data_len + 2] = '\xff';
 | 
	
		
			
				|  |  | -					  data[data_len + 3] = '\xff';
 | 
	
		
			
				|  |  | -					  conn->websocket_inflate_state.avail_in = data_len + 4;
 | 
	
		
			
				|  |  | -					  conn->websocket_inflate_state.next_in = data;
 | 
	
		
			
				|  |  | -					  conn->websocket_inflate_state.avail_out = 10 * 1024 * 1024;
 | 
	
		
			
				|  |  | -					  conn->websocket_inflate_state.next_out = inflated;
 | 
	
		
			
				|  |  | -					  int ret = inflate(&conn->websocket_inflate_state, Z_SYNC_FLUSH);
 | 
	
		
			
				|  |  | -					  // TODO loop allocate bigger buffer if needed
 | 
	
		
			
				|  |  | -					  if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR ||
 | 
	
		
			
				|  |  | -						  ret == Z_MEM_ERROR || ret < 0)
 | 
	
		
			
				|  |  | -						exit_by_callback = 1;
 | 
	
		
			
				|  |  | -					  inflated[10 * 1024 * 1024 -
 | 
	
		
			
				|  |  | -							   conn->websocket_inflate_state.avail_out] = '\0';
 | 
	
		
			
				|  |  | -					  // if (conn->websocket_inflate_state.avail_out == 0)
 | 
	
		
			
				|  |  | -					  //   TODO output buffer overflow
 | 
	
		
			
				|  |  | -					  if (!ws_data_handler(conn, mop, (char *)inflated,
 | 
	
		
			
				|  |  | -										   10 * 1024 * 1024 -
 | 
	
		
			
				|  |  | -											   conn->websocket_inflate_state.avail_out,
 | 
	
		
			
				|  |  | -										   callback_data)) {
 | 
	
		
			
				|  |  | -						exit_by_callback = 1;
 | 
	
		
			
				|  |  | -					  }
 | 
	
		
			
				|  |  | -					}
 | 
	
		
			
				|  |  | -				  } else
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -        	  if (!ws_data_handler(conn,
 | 
	
		
			
				|  |  | -				                        mop,
 | 
	
		
			
				|  |  | -				                        (char *)data,
 | 
	
		
			
				|  |  | -				                        (size_t)data_len,
 | 
	
		
			
				|  |  | -				                        callback_data)) {
 | 
	
		
			
				|  |  | -					exit_by_callback = 1;
 | 
	
		
			
				|  |  | +				if (ws_data_handler != NULL) {
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
 | 
	
		
			
				|  |  | +					if (mop & 0x40) {
 | 
	
		
			
				|  |  | +						/* Inflate the data received if bit RSV1 is set. */
 | 
	
		
			
				|  |  | +						if (!conn->websocket_deflate_initialized) {
 | 
	
		
			
				|  |  | +							if (websocket_deflate_initialize(conn, 1) != Z_OK)
 | 
	
		
			
				|  |  | +								exit_by_callback = 1;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +						if (!exit_by_callback) {
 | 
	
		
			
				|  |  | +							int inflate_buf_size_old = 0;
 | 
	
		
			
				|  |  | +							int inflate_buf_size =
 | 
	
		
			
				|  |  | +							    1024 * 1024; // Start with 1 MB and double the
 | 
	
		
			
				|  |  | +							                 // memory when needed
 | 
	
		
			
				|  |  | +							Bytef *inflated;
 | 
	
		
			
				|  |  | +							conn->websocket_inflate_state.avail_in =
 | 
	
		
			
				|  |  | +							    data_len + 4;
 | 
	
		
			
				|  |  | +							conn->websocket_inflate_state.next_in = data;
 | 
	
		
			
				|  |  | +							// Add trailing 0x00 0x00 0xff 0xff bytes
 | 
	
		
			
				|  |  | +							data[data_len] = '\x00';
 | 
	
		
			
				|  |  | +							data[data_len + 1] = '\x00';
 | 
	
		
			
				|  |  | +							data[data_len + 2] = '\xff';
 | 
	
		
			
				|  |  | +							data[data_len + 3] = '\xff';
 | 
	
		
			
				|  |  | +							do {
 | 
	
		
			
				|  |  | +								if (inflate_buf_size_old == 0) {
 | 
	
		
			
				|  |  | +									inflated = mg_calloc(inflate_buf_size,
 | 
	
		
			
				|  |  | +									                     sizeof(Bytef));
 | 
	
		
			
				|  |  | +								} else {
 | 
	
		
			
				|  |  | +									inflate_buf_size *= 2;
 | 
	
		
			
				|  |  | +									inflated =
 | 
	
		
			
				|  |  | +									    mg_realloc(inflated, inflate_buf_size);
 | 
	
		
			
				|  |  | +								}
 | 
	
		
			
				|  |  | +								conn->websocket_inflate_state.avail_out =
 | 
	
		
			
				|  |  | +								    inflate_buf_size - inflate_buf_size_old;
 | 
	
		
			
				|  |  | +								conn->websocket_inflate_state.next_out =
 | 
	
		
			
				|  |  | +								    inflated + inflate_buf_size_old;
 | 
	
		
			
				|  |  | +								int ret =
 | 
	
		
			
				|  |  | +								    inflate(&conn->websocket_inflate_state,
 | 
	
		
			
				|  |  | +								            Z_SYNC_FLUSH);
 | 
	
		
			
				|  |  | +								if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR
 | 
	
		
			
				|  |  | +								    || ret == Z_MEM_ERROR || ret < 0)
 | 
	
		
			
				|  |  | +									exit_by_callback = 1;
 | 
	
		
			
				|  |  | +								inflate_buf_size_old = inflate_buf_size;
 | 
	
		
			
				|  |  | +							} while (!exit_by_callback
 | 
	
		
			
				|  |  | +							         && conn->websocket_inflate_state.avail_out
 | 
	
		
			
				|  |  | +							                == 0);
 | 
	
		
			
				|  |  | +							inflate_buf_size -=
 | 
	
		
			
				|  |  | +							    conn->websocket_inflate_state.avail_out;
 | 
	
		
			
				|  |  | +							inflated[inflate_buf_size] = '\0';
 | 
	
		
			
				|  |  | +							if (!ws_data_handler(conn,
 | 
	
		
			
				|  |  | +							                     mop,
 | 
	
		
			
				|  |  | +							                     (char *)inflated,
 | 
	
		
			
				|  |  | +							                     inflate_buf_size,
 | 
	
		
			
				|  |  | +							                     callback_data)) {
 | 
	
		
			
				|  |  | +								exit_by_callback = 1;
 | 
	
		
			
				|  |  | +							}
 | 
	
		
			
				|  |  | +							mg_free(inflated);
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					} else
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +					    if (!ws_data_handler(conn,
 | 
	
		
			
				|  |  | +					                         mop,
 | 
	
		
			
				|  |  | +					                         (char *)data,
 | 
	
		
			
				|  |  | +					                         (size_t)data_len,
 | 
	
		
			
				|  |  | +					                         callback_data)) {
 | 
	
		
			
				|  |  | +						exit_by_callback = 1;
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			/* It a buffer has been allocated, free it again */
 | 
	
	
		
			
				|  | @@ -12994,47 +12959,52 @@ mg_websocket_write_exec(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  	size_t headerLen;
 | 
	
		
			
				|  |  |  	int retval;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -    uLong deflated_size;
 | 
	
		
			
				|  |  | -    Bytef *deflated;
 | 
	
		
			
				|  |  | -    // Deflate websocket messages over 100kb
 | 
	
		
			
				|  |  | -    int use_deflate = dataLen > 100 * 1024 && conn->accept_gzip;
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  #if defined(GCC_DIAGNOSTIC)
 | 
	
		
			
				|  |  |  /* Disable spurious conversion warning for GCC */
 | 
	
		
			
				|  |  |  #pragma GCC diagnostic push
 | 
	
		
			
				|  |  |  #pragma GCC diagnostic ignored "-Wconversion"
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	/* TODO: Check if this lock should be moved to user land.
 | 
	
		
			
				|  |  | -	 * Currently the server sets this lock for websockets, but
 | 
	
		
			
				|  |  | -	 * not for any other connection. It must be set for every
 | 
	
		
			
				|  |  | -	 * conn read/written by more than one thread, no matter if
 | 
	
		
			
				|  |  | -	 * it is a websocket or regular connection. */
 | 
	
		
			
				|  |  | -	(void)mg_lock_connection(conn);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -	if (use_deflate) {
 | 
	
		
			
				|  |  | -		if (!conn->websocket_deflate_initialized) {
 | 
	
		
			
				|  |  | -		  if (websocket_deflate_initialize(conn) != Z_OK) return 0;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		// Deflating the message
 | 
	
		
			
				|  |  | -		header[0] = 0xC0u | (unsigned char)((unsigned)opcode & 0xf);
 | 
	
		
			
				|  |  | -		conn->websocket_deflate_state.avail_in = dataLen;
 | 
	
		
			
				|  |  | -		conn->websocket_deflate_state.next_in = (unsigned char *)data;
 | 
	
		
			
				|  |  | -		deflated_size = compressBound(dataLen);
 | 
	
		
			
				|  |  | -		deflated = mg_calloc(deflated_size, sizeof(Bytef));
 | 
	
		
			
				|  |  | -		conn->websocket_deflate_state.avail_out = deflated_size;
 | 
	
		
			
				|  |  | -		conn->websocket_deflate_state.next_out = deflated =
 | 
	
		
			
				|  |  | -			mg_calloc(deflated_size, sizeof(Bytef));
 | 
	
		
			
				|  |  | -		deflate(&conn->websocket_deflate_state, conn->websocket_deflate_flush);
 | 
	
		
			
				|  |  | -		dataLen = deflated_size - conn->websocket_deflate_state.avail_out -
 | 
	
		
			
				|  |  | -				  4;  // Strip trailing 0x00 0x00 0xff 0xff bytes
 | 
	
		
			
				|  |  | -	} else
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -	header[0] = 0x80u | (unsigned char)((unsigned)opcode & 0xf);
 | 
	
		
			
				|  |  | +	/* Note that POSIX/Winsock's send() is threadsafe
 | 
	
		
			
				|  |  | +	 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
 | 
	
		
			
				|  |  | +	 * but mongoose's mg_printf/mg_write is not (because of the loop in
 | 
	
		
			
				|  |  | +	 * push(), although that is only a problem if the packet is large or
 | 
	
		
			
				|  |  | +	 * outgoing buffer is full). */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* TODO: Check if this lock should be moved to user land.
 | 
	
		
			
				|  |  | +	 * Currently the server sets this lock for websockets, but
 | 
	
		
			
				|  |  | +	 * not for any other connection. It must be set for every
 | 
	
		
			
				|  |  | +	 * conn read/written by more than one thread, no matter if
 | 
	
		
			
				|  |  | +	 * it is a websocket or regular connection. */
 | 
	
		
			
				|  |  | +	(void)mg_lock_connection(conn);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
 | 
	
		
			
				|  |  | +	uLong deflated_size;
 | 
	
		
			
				|  |  | +	Bytef *deflated;
 | 
	
		
			
				|  |  | +	// Deflate websocket messages over 100kb
 | 
	
		
			
				|  |  | +	int use_deflate = dataLen > 100 * 1024 && conn->accept_gzip;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (use_deflate) {
 | 
	
		
			
				|  |  | +		if (!conn->websocket_deflate_initialized) {
 | 
	
		
			
				|  |  | +			if (websocket_deflate_initialize(conn, 1) != Z_OK)
 | 
	
		
			
				|  |  | +				return 0;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		// Deflating the message
 | 
	
		
			
				|  |  | +		header[0] = 0xC0u | (unsigned char)((unsigned)opcode & 0xf);
 | 
	
		
			
				|  |  | +		conn->websocket_deflate_state.avail_in = dataLen;
 | 
	
		
			
				|  |  | +		conn->websocket_deflate_state.next_in = (unsigned char *)data;
 | 
	
		
			
				|  |  | +		deflated_size = compressBound(dataLen);
 | 
	
		
			
				|  |  | +		deflated = mg_calloc(deflated_size, sizeof(Bytef));
 | 
	
		
			
				|  |  | +		conn->websocket_deflate_state.avail_out = deflated_size;
 | 
	
		
			
				|  |  | +		conn->websocket_deflate_state.next_out = deflated =
 | 
	
		
			
				|  |  | +		    mg_calloc(deflated_size, sizeof(Bytef));
 | 
	
		
			
				|  |  | +		deflate(&conn->websocket_deflate_state, conn->websocket_deflate_flush);
 | 
	
		
			
				|  |  | +		dataLen = deflated_size - conn->websocket_deflate_state.avail_out
 | 
	
		
			
				|  |  | +		          - 4; // Strip trailing 0x00 0x00 0xff 0xff bytes
 | 
	
		
			
				|  |  | +	} else
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +		header[0] = 0x80u | (unsigned char)((unsigned)opcode & 0xf);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(GCC_DIAGNOSTIC)
 | 
	
		
			
				|  |  |  #pragma GCC diagnostic pop
 | 
	
	
		
			
				|  | @@ -13068,25 +13038,19 @@ mg_websocket_write_exec(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  		headerLen += 4;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	/* Note that POSIX/Winsock's send() is threadsafe
 | 
	
		
			
				|  |  | -	 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
 | 
	
		
			
				|  |  | -	 * but mongoose's mg_printf/mg_write is not (because of the loop in
 | 
	
		
			
				|  |  | -	 * push(), although that is only a problem if the packet is large or
 | 
	
		
			
				|  |  | -	 * outgoing buffer is full). */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  	retval = mg_write(conn, header, headerLen);
 | 
	
		
			
				|  |  |  	if (retval != (int)headerLen) {
 | 
	
		
			
				|  |  |  		/* Did not send complete header */
 | 
	
		
			
				|  |  |  		retval = -1;
 | 
	
		
			
				|  |  |  	} else {
 | 
	
		
			
				|  |  |  		if (dataLen > 0) {
 | 
	
		
			
				|  |  | -#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -		  if (use_deflate) {
 | 
	
		
			
				|  |  | -			  retval = mg_write(conn, deflated, dataLen);
 | 
	
		
			
				|  |  | -			  mg_free(deflated);
 | 
	
		
			
				|  |  | -		  } else
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -			  retval = mg_write(conn, data, dataLen);
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
 | 
	
		
			
				|  |  | +			if (use_deflate) {
 | 
	
		
			
				|  |  | +				retval = mg_write(conn, deflated, dataLen);
 | 
	
		
			
				|  |  | +				mg_free(deflated);
 | 
	
		
			
				|  |  | +			} else
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +				retval = mg_write(conn, data, dataLen);
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		/* if dataLen == 0, the header length (2) is returned */
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -13303,10 +13267,10 @@ handle_websocket_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#if defined(USE_ZLIB)
 | 
	
		
			
				|  |  | -        websocket_deflate_negotiate(conn);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
 | 
	
		
			
				|  |  | +		websocket_deflate_negotiate(conn);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  		if ((ws_connect_handler != NULL)
 | 
	
		
			
				|  |  |  		    && (ws_connect_handler(conn, cbData) != 0)) {
 | 
	
		
			
				|  |  |  			/* C callback has returned non-zero, do not proceed with
 | 
	
	
		
			
				|  | @@ -13377,7 +13341,15 @@ handle_websocket_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	/* Step 8: Call the close handler */
 | 
	
		
			
				|  |  | +#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
 | 
	
		
			
				|  |  | +	/* Step 8: Close the deflate & inflate buffers */
 | 
	
		
			
				|  |  | +	if (conn->websocket_deflate_initialized) {
 | 
	
		
			
				|  |  | +		deflateEnd(&conn->websocket_deflate_state);
 | 
	
		
			
				|  |  | +		inflateEnd(&conn->websocket_inflate_state);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Step 9: Call the close handler */
 | 
	
		
			
				|  |  |  	if (ws_close_handler) {
 | 
	
		
			
				|  |  |  		ws_close_handler(conn, cbData);
 | 
	
		
			
				|  |  |  	}
 |