コード例 #1
0
ファイル: WebSocketChannel.cs プロジェクト: irseny/irseny
		private void ProcessInit() {
			// continue initializing through the html channel
			initSource.Process();
			// stop processing if something went wrong
			if (initSource.State == WebChannelState.Closed || initSource.State == WebChannelState.InitFailed) {
				State = WebChannelState.InitFailed;
				initSource = null;
			}
			// wait for the first header to arrive
			if (initSource.AvailableMessageNo > 0) {
				HttpHeader header = initSource.EmitMessage().Header;
				string headerKey = string.Empty;
				bool headerValid = false;
				bool canRecover = false;
				bool denySubprotocol = false;
				bool denyExtension = false;
				do {
					// check the header for errors
					if (header.Method != HttpMethod.Get) {
						break;
					}
					// TODO optional origin
					string connection;
					if (!header.Fields.TryGetValue("Connection", out connection)) {
						break;
					}
					if (!connection.ToLower().Contains("upgrade")) {
						break;
					}
					string upgrade;
					if (!header.Fields.TryGetValue("Upgrade", out upgrade)) {
						break;
					}
					if (!upgrade.ToLower().Contains("websocket")) {
						break;
					}
					if (!header.Fields.TryGetValue("Sec-WebSocket-Key", out headerKey)) {
						break;
					}
					string sVersion;
					if (header.Fields.TryGetValue("Sec-WebSocket-Version", out sVersion)) {
						// TODO improve detection
						bool acceptVersion = false;
						if (sVersion.Contains("13")) {
							acceptVersion = true;

						}
						if (!acceptVersion) {
							headerValid = false;
							canRecover = true;
							HttpHeader response = new HttpHeader(header.Version, HttpStatusCode.UpgradeRequired);
							response.Fields.Add("Sec-WebSocket-Version", "13");
							initSource.SendMessage(new HttpMessage(response));
							break;
						}
					}
					// this implementation does not support subprotocols or extensions
					// send null fields if these exist in the request
					if (header.Fields.ContainsKey("Subprotocol")) {
						denySubprotocol = true;
					}
					if (header.Fields.ContainsKey("Extension")) {
						denyExtension = true;
					}
					// TODO optional handle resource or send 404 not found
					headerValid = true;
				} while (false);
				if (!headerValid) {
					if (!canRecover) {
						// set the connection on ice if the setup failed
						State = WebChannelState.InitFailed;
						initSource.Close(false);
						initSource = null;
					}
				} else {
					// send an appropriate response header
					HttpHeader response = new HttpHeader(HttpVersion.Version11, HttpStatusCode.SwitchingProtocols);
					response.Fields.Add("Upgrade", "websocket");
					response.Fields.Add("Connection", "Upgrade");
					byte[] byteKey = Encoding.UTF8.GetBytes(headerKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
					byte[] sha1Key = System.Security.Cryptography.SHA1.Create().ComputeHash(byteKey);
					string base64Key = Convert.ToBase64String(sha1Key);
					response.Fields.Add("Sec-WebSocket-Accept", base64Key);

					if (denySubprotocol) {
						response.Fields.Add("Subprotocol", "null");
					}
					if (denyExtension) {
						response.Fields.Add("Extension", "null");
					}
					initSource.SendMessage(new HttpMessage(response));
					// since the upgrade is done no more http communication is necessary
					// ACK has to be sent first so initSource can not contain any websocket messages at this point
					initSource.Flush();
					initSource.Close(false);
					initSource = null;
					// the handshake has been completed
					// messages can now be sent
					State = WebChannelState.Open;
					// continue with sending all pending messages
					foreach (WebSocketMessage send in toSend) {
						byte[] encoded = EncodeMessage(send);
						messageSource.SendMessage(encoded);
					}
					toSend.Clear();				
				} 
			}
		}
コード例 #2
0
ファイル: HttpHeader.cs プロジェクト: irseny/irseny
        public static HttpHeader Parse(string text)
        {
            var result = new HttpHeader();

            // TODO make compatible with RESPONSE messages
            string[] split = text.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
            if (split.Length == 0)
            {
                throw new FormatException(text);
            }
            // read header
            string head = split[0];

            string[] sHead = head.Split(new char[1] {
                ' '
            }, StringSplitOptions.RemoveEmptyEntries);
            if (sHead.Length < 3)
            {
                throw new FormatException(head);
            }
            // read method

            try {
                result.Method = ParseHttpMethod(sHead[0]);
            } catch (FormatException) {
                throw new FormatException(sHead[0]);
            }
            // read resource
            result.Resource = sHead[1];
            // read protocol
            if (sHead[2].Length < ("HTTP/".Length + "1.1".Length))
            {
                throw new FormatException(sHead[2]);
            }
            if (!sHead[2].StartsWith("HTTP/", StringComparison.InvariantCulture))
            {
                throw new FormatException(sHead[2]);
            }
            string version = sHead[2].Substring("HTTP/".Length, 3);

            try {
                result.Version = Version.Parse(version);
            } catch (FormatException) {
                throw new FormatException(sHead[2]);
            }
            // read fields
            for (int s = 1; s < split.Length; s++)
            {
                string field      = split[s];
                int    appearance = field.IndexOf(':');
                if (appearance < 0)
                {
                    throw new FormatException(split[s]);
                }
                //if (appearance >= field.Length - 1) throw new FormatException(split[s]);
                string key   = field.Substring(0, appearance).Trim();
                string value = string.Empty;
                if (appearance < field.Length - 1)
                {
                    value = field.Substring(appearance + 1).Trim();
                }
                result.Fields.Add(key, value);
            }
            return(result);
        }