You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			134 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //------------------------------------------------------------------------------
 | |
| // <copyright file="SubProtocolUtil.cs" company="Microsoft">
 | |
| //     Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| namespace System.Web.WebSockets {
 | |
|     using System;
 | |
|     using System.Collections.Generic;
 | |
|     using System.Linq;
 | |
| 
 | |
|     // Utility class for creating and parsing "Sec-WebSocket-Protocol" headers
 | |
|     //
 | |
|     // From the WebSocket protocol spec, sec. 4.1:
 | |
|     // 10.  The request MAY include a header field with the name "Sec-
 | |
|     //      WebSocket-Protocol".  If present, this value indicates one or
 | |
|     //      more comma separated subprotocol the client wishes to speak,
 | |
|     //      ordered by preference.  The elements that comprise this value
 | |
|     //      MUST be non-empty strings with characters in the range U+0021 to
 | |
|     //      U+007E not including separator characters as defined in
 | |
|     //      [RFC2616], and MUST all be unique strings.  The ABNF for the
 | |
|     //      value of this header field is 1#token, where the definitions of
 | |
|     //      constructs and rules are as given in [RFC2616].
 | |
|     //
 | |
|     // RFC 2616, sec. 2.1:
 | |
|     // #rule
 | |
|     //    A construct "#" is defined, similar to "*", for defining lists of
 | |
|     //    elements. The full form is "<n>#<m>element" indicating at least
 | |
|     //    <n> and at most <m> elements, each separated by one or more commas
 | |
|     //    (",") and OPTIONAL linear white space (LWS). This makes the usual
 | |
|     //    form of lists very easy; a rule such as
 | |
|     //       ( *LWS element *( *LWS "," *LWS element ))
 | |
|     //    can be shown as
 | |
|     //       1#element
 | |
|     //    Wherever this construct is used, null elements are allowed, but do
 | |
|     //    not contribute to the count of elements present. That is,
 | |
|     //    "(element), , (element) " is permitted, but counts as only two
 | |
|     //    elements. Therefore, where at least one element is required, at
 | |
|     //    least one non-null element MUST be present. Default values are 0
 | |
|     //    and infinity so that "#element" allows any number, including zero;
 | |
|     //    "1#element" requires at least one; and "1#2element" allows one or
 | |
|     //    two.
 | |
| 
 | |
|     internal static class SubProtocolUtil {
 | |
| 
 | |
|         // RFC 2616, sec. 2.2:
 | |
|         // LWS            = [CRLF] 1*( SP | HT )
 | |
|         // We use a subset: _lwsTrimChars = SP | HT
 | |
|         private static readonly char[] _lwsTrimChars = new char[] { ' ', '\t' };
 | |
|         private static readonly char[] _splitChars = new char[] { ',' };
 | |
| 
 | |
|         // Returns a value stating whether the specified SubProtocol is valid
 | |
|         public static bool IsValidSubProtocolName(string subprotocol) {
 | |
|             return (!String.IsNullOrEmpty(subprotocol) && subprotocol.All(IsValidSubProtocolChar));
 | |
|         }
 | |
| 
 | |
|         private static bool IsValidSubProtocolChar(char c) {
 | |
|             return ('\u0021' <= c && c <= '\u007e' && !IsSeparatorChar(c));
 | |
|         }
 | |
| 
 | |
|         // RFC 2616, sec. 2.2:
 | |
|         // separators     = "(" | ")" | "<" | ">" | "@"
 | |
|         //                | "," | ";" | ":" | "\" | <">
 | |
|         //                | "/" | "[" | "]" | "?" | "="
 | |
|         //                | "{" | "}" | SP | HT
 | |
|         private static bool IsSeparatorChar(char c) {
 | |
|             switch (c) {
 | |
|                 case '(':
 | |
|                 case ')':
 | |
|                 case '<':
 | |
|                 case '>':
 | |
|                 case '@':
 | |
|                 case ',':
 | |
|                 case ';':
 | |
|                 case ':':
 | |
|                 case '\\':
 | |
|                 case '"':
 | |
|                 case '/':
 | |
|                 case '[':
 | |
|                 case ']':
 | |
|                 case '?':
 | |
|                 case '=':
 | |
|                 case '{':
 | |
|                 case '}':
 | |
|                 case ' ':
 | |
|                 case '\t':
 | |
|                     return true;
 | |
| 
 | |
|                 default:
 | |
|                     return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Returns a list of preferred subprotocols by parsing an incoming header value, or null if the incoming header was improperly formatted.
 | |
|         public static List<string> ParseHeader(string headerValue) {
 | |
|             if (headerValue == null) {
 | |
|                 // No incoming values
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             List<string> subprotocols = new List<string>();
 | |
|             foreach (string subprotocolCandidate in headerValue.Split(_splitChars)) {
 | |
|                 string subprotocolCandidateTrimmed = subprotocolCandidate.Trim(_lwsTrimChars); // remove LWS according to '#' rule
 | |
| 
 | |
|                 // skip LWS between commas according to '#' rule
 | |
|                 if (subprotocolCandidateTrimmed.Length == 0) {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 // reject improperly formatted header values
 | |
|                 if (!IsValidSubProtocolName(subprotocolCandidateTrimmed)) {
 | |
|                     return null;
 | |
|                 }
 | |
| 
 | |
|                 // otherwise this subprotocol is OK
 | |
|                 subprotocols.Add(subprotocolCandidateTrimmed);
 | |
|             }
 | |
| 
 | |
|             if (subprotocols.Count == 0) {
 | |
|                 // header is improperly formatted (contained no usable values)
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             if (subprotocols.Distinct(StringComparer.Ordinal).Count() != subprotocols.Count) {
 | |
|                 // header is improperly formatted (contained duplicate values)
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             return subprotocols;
 | |
|         }
 | |
| 
 | |
|     }
 | |
| }
 |