|  | @@ -3818,9 +3818,9 @@ static void send_websocket_handshake(struct mg_connection *conn) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void read_websocket(struct mg_connection *conn) {
 | 
	
		
			
				|  |  |    unsigned char *buf = (unsigned char *) conn->buf + conn->request_len;
 | 
	
		
			
				|  |  | -  int n, stop = 0;
 | 
	
		
			
				|  |  | +  int bits, n, stop = 0;
 | 
	
		
			
				|  |  |    size_t i, len, mask_len, data_len, header_len, body_len;
 | 
	
		
			
				|  |  | -  char mem[4 * 1024], *data;
 | 
	
		
			
				|  |  | +  char mem[4 * 1024], mask[4], *data;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    assert(conn->content_len == 0);
 | 
	
		
			
				|  |  |    while (!stop) {
 | 
	
	
		
			
				|  | @@ -3841,6 +3841,14 @@ static void read_websocket(struct mg_connection *conn) {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    // Data layout is as follows:
 | 
	
		
			
				|  |  | +    //  conn->buf               buf
 | 
	
		
			
				|  |  | +    //     v                     v              frame1           | frame2
 | 
	
		
			
				|  |  | +    //     |---------------------|----------------|--------------|-------
 | 
	
		
			
				|  |  | +    //     |                     |<--header_len-->|<--data_len-->|
 | 
	
		
			
				|  |  | +    //     |<-conn->request_len->|<-----body_len----------->|
 | 
	
		
			
				|  |  | +    //     |<-------------------conn->data_len------------->|
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (header_len > 0) {
 | 
	
		
			
				|  |  |        // Allocate space to hold websocket payload
 | 
	
		
			
				|  |  |        data = mem;
 | 
	
	
		
			
				|  | @@ -3850,6 +3858,10 @@ static void read_websocket(struct mg_connection *conn) {
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +      // Save mask and bits, otherwise it may be clobbered by memmove below
 | 
	
		
			
				|  |  | +      bits = buf[0];
 | 
	
		
			
				|  |  | +      memcpy(mask, buf + header_len - mask_len, mask_len);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        // Read frame payload into the allocated buffer.
 | 
	
		
			
				|  |  |        assert(body_len >= header_len);
 | 
	
		
			
				|  |  |        if (data_len + header_len > body_len) {
 | 
	
	
		
			
				|  | @@ -3868,15 +3880,15 @@ static void read_websocket(struct mg_connection *conn) {
 | 
	
		
			
				|  |  |        // Apply mask if necessary
 | 
	
		
			
				|  |  |        if (mask_len > 0) {
 | 
	
		
			
				|  |  |          for (i = 0; i < data_len; i++) {
 | 
	
		
			
				|  |  | -          data[i] ^= buf[header_len - mask_len + (i % 4)];
 | 
	
		
			
				|  |  | +          data[i] ^= mask[i % 4];
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        // Exit the loop if callback signalled to exit,
 | 
	
		
			
				|  |  |        // or "connection close" opcode received.
 | 
	
		
			
				|  |  |        if ((conn->ctx->callbacks.websocket_data != NULL &&
 | 
	
		
			
				|  |  | -          !conn->ctx->callbacks.websocket_data(conn, buf[0], data, data_len)) ||
 | 
	
		
			
				|  |  | -          (buf[0] & 0xf) == 8) {  // Opcode == 8, connection close
 | 
	
		
			
				|  |  | +          !conn->ctx->callbacks.websocket_data(conn, bits, data, data_len)) ||
 | 
	
		
			
				|  |  | +          (bits & 0xf) == 8) {  // Opcode == 8, connection close
 | 
	
		
			
				|  |  |          stop = 1;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 |