|  | @@ -3203,6 +3203,21 @@ get_header(const struct mg_request_info *ri, const char *name)
 | 
	
		
			
				|  |  |  	return NULL;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* Retrieve requested HTTP header multiple values, and return the number of found occurences */
 | 
	
		
			
				|  |  | +static int get_headers(const struct mg_request_info *ri, const char *name,
 | 
	
		
			
				|  |  | +		const char** output, int output_max_size) {
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +	int cnt = 0;
 | 
	
		
			
				|  |  | +	if (ri) {
 | 
	
		
			
				|  |  | +		for (i = 0; i < ri->num_headers && cnt < output_max_size; i++) {
 | 
	
		
			
				|  |  | +			if (!mg_strcasecmp(name, ri->http_headers[i].name)) {
 | 
	
		
			
				|  |  | +				output[cnt++] = ri->http_headers[i].value;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	return cnt;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const char *
 | 
	
		
			
				|  |  |  mg_get_header(const struct mg_connection *conn, const char *name)
 | 
	
	
		
			
				|  | @@ -10518,8 +10533,10 @@ handle_websocket_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  	/* Step 2: If a callback is responsible, call it. */
 | 
	
		
			
				|  |  |  	if (is_callback_resource) {
 | 
	
		
			
				|  |  |  		/* Step 2.1 check and select subprotocol */
 | 
	
		
			
				|  |  | -		const char *protocol = mg_get_header(conn, "Sec-WebSocket-Protocol");
 | 
	
		
			
				|  |  | -		if (protocol && subprotocols) {
 | 
	
		
			
				|  |  | +		const char* protocols[64]; // max 64 headers
 | 
	
		
			
				|  |  | +		int nbSubprotocolHeader = get_headers(&conn->request_info, "Sec-WebSocket-Protocol", protocols, 64);
 | 
	
		
			
				|  |  | +		if (nbSubprotocolHeader > 0 && subprotocols) {
 | 
	
		
			
				|  |  | +			int cnt = 0;
 | 
	
		
			
				|  |  |  			int idx;
 | 
	
		
			
				|  |  |  			unsigned long len;
 | 
	
		
			
				|  |  |  			const char *sep, *curSubProtocol,
 | 
	
	
		
			
				|  | @@ -10528,34 +10545,36 @@ handle_websocket_request(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			/* look for matching subprotocol */
 | 
	
		
			
				|  |  |  			do {
 | 
	
		
			
				|  |  | -				sep = strchr(protocol, ',');
 | 
	
		
			
				|  |  | -				curSubProtocol = protocol;
 | 
	
		
			
				|  |  | -				len = sep ? (unsigned long)(sep - protocol)
 | 
	
		
			
				|  |  | -				          : (unsigned long)strlen(protocol);
 | 
	
		
			
				|  |  | -				while (sep && isspace(*++sep)) {
 | 
	
		
			
				|  |  | -					; /* ignore leading whitespaces */
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -				protocol = sep;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				for (idx = 0; idx < subprotocols->nb_subprotocols; idx++) {
 | 
	
		
			
				|  |  | -					if ((strlen(subprotocols->subprotocols[idx]) == len)
 | 
	
		
			
				|  |  | -					    && (strncmp(curSubProtocol,
 | 
	
		
			
				|  |  | -					                subprotocols->subprotocols[idx],
 | 
	
		
			
				|  |  | -					                len) == 0)) {
 | 
	
		
			
				|  |  | -						acceptedWebSocketSubprotocol =
 | 
	
		
			
				|  |  | -						    subprotocols->subprotocols[idx];
 | 
	
		
			
				|  |  | -						break;
 | 
	
		
			
				|  |  | +				const char *protocol = protocols[cnt];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +				do {
 | 
	
		
			
				|  |  | +					sep = strchr(protocol, ',');
 | 
	
		
			
				|  |  | +					curSubProtocol = protocol;
 | 
	
		
			
				|  |  | +					len = sep ? (unsigned long)(sep - protocol) : strlen(protocol);
 | 
	
		
			
				|  |  | +					while(sep && isspace(*++sep)); // ignore leading whitespaces
 | 
	
		
			
				|  |  | +					protocol = sep;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +					for (idx = 0; idx < subprotocols->nb_subprotocols; idx++) {
 | 
	
		
			
				|  |  | +						if ((strlen(subprotocols->subprotocols[idx]) == len)
 | 
	
		
			
				|  |  | +							&& (strncmp(curSubProtocol,
 | 
	
		
			
				|  |  | +										subprotocols->subprotocols[idx],
 | 
	
		
			
				|  |  | +										len) == 0)) {
 | 
	
		
			
				|  |  | +							acceptedWebSocketSubprotocol =
 | 
	
		
			
				|  |  | +								subprotocols->subprotocols[idx];
 | 
	
		
			
				|  |  | +							break;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  |  					}
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			} while (sep && !acceptedWebSocketSubprotocol);
 | 
	
		
			
				|  |  | +				} while (sep && !acceptedWebSocketSubprotocol);
 | 
	
		
			
				|  |  | +			} while (++cnt < nbSubprotocolHeader && !acceptedWebSocketSubprotocol);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			conn->request_info.acceptedWebSocketSubprotocol =
 | 
	
		
			
				|  |  |  			    acceptedWebSocketSubprotocol;
 | 
	
		
			
				|  |  | -		} else if (protocol) {
 | 
	
		
			
				|  |  | +		} else if (nbSubprotocolHeader > 0) {
 | 
	
		
			
				|  |  |  			/* keep legacy behavior */
 | 
	
		
			
				|  |  | +			const char *protocol = protocols[0];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			/* The protocol is a comma seperated list of names. */
 | 
	
		
			
				|  |  | +			/* The protocol is a comma separated list of names. */
 | 
	
		
			
				|  |  |  			/* The server must only return one value from this list. */
 | 
	
		
			
				|  |  |  			/* First check if it is a list or just a single value. */
 | 
	
		
			
				|  |  |  			const char *sep = strrchr(protocol, ',');
 |