/// <summary> /// Reads the Flash policy request and returns the policy response if Flash requests are allowed. /// </summary> /// <param name="sender">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">The bytes read from the socket</param> /// <param name="tag">A tag identifying the read request</param> void ReadPolicyRequest(AsyncSocket sender, byte[] readBytes, long tag) { // remove this now that we are done with it this.socket.DidRead -= new AsyncSocket.SocketDidRead(ReadPolicyRequest); if (tag == FLASH_POLICY_REQUEST_TAG) { Data data = new Data(readBytes); this.AlreadyReceivedData.Append(data.ToString()); string request = this.AlreadyReceivedData.ToString(); if (request == FlashPolicy.REQUEST) { if (this.allowFlash) { this.socket.Write(FlashPolicy.ResponseBytes, TIMEOUT_FLASHPOLICYRESPONSE, FLASH_POLICY_RESPONSE_TAG); this.socket.CloseAfterWriting(); } else { OnError(ErrorCode.NOT_AUTHORIZED, ErrorDescription.BROWSER_CONNECTIONS_NOT_ALLOWED); } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNRECOGNIZED_REQUEST); } } }
/// <summary> /// Reads the socket data and handles the request /// </summary> /// <param name="alreadyReadBytes">Any bytes that were already read from the socket</param> public void Read(byte[] alreadyReadBytes) { Data data = new Data(alreadyReadBytes); string s = data.ToString(); this.AlreadyReceivedData.Append(s); this.socket.DidRead += new AsyncSocket.SocketDidRead(ReadPolicyRequest); this.socket.Read(FlashPolicy.REQUEST.Length - s.Length, TIMEOUT_FLASHPOLICYREQUEST, FLASH_POLICY_REQUEST_TAG); }
/// <summary> /// Reads the socket data and handles the request /// </summary> /// <param name="alreadyReadBytes">Any bytes that were already read from the socket</param> public void Read(byte[] alreadyReadBytes) { Data data = new Data(alreadyReadBytes); string s = data.ToString(); this.AlreadyReceivedData.Append(s); this.socket.DidRead += new AsyncSocket.SocketDidRead(ReadPolicyRequest); this.socket.Read(FlashPolicy.REQUEST.Length - s.Length, TIMEOUT_FLASHPOLICYREQUEST, FLASH_POLICY_REQUEST_TAG); }
/// <summary> /// Reads the Flash policy request and returns the policy response if Flash requests are allowed. /// </summary> /// <param name="sender">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">The bytes read from the socket</param> /// <param name="tag">A tag identifying the read request</param> void ReadPolicyRequest(AsyncSocket sender, byte[] readBytes, long tag) { // remove this now that we are done with it this.socket.DidRead -= new AsyncSocket.SocketDidRead(ReadPolicyRequest); if (tag == FLASH_POLICY_REQUEST_TAG) { Data data = new Data(readBytes); this.AlreadyReceivedData.Append(data.ToString()); string request = this.AlreadyReceivedData.ToString(); if (request == FlashPolicy.REQUEST) { if (this.allowFlash) { this.socket.Write(FlashPolicy.ResponseBytes, TIMEOUT_FLASHPOLICYRESPONSE, FLASH_POLICY_RESPONSE_TAG); this.socket.CloseAfterWriting(); } else { OnError(ErrorCode.NOT_AUTHORIZED, ErrorDescription.BROWSER_CONNECTIONS_NOT_ALLOWED); } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNRECOGNIZED_REQUEST); } } }
/// <summary> /// Handles the socket's DidRead event after reading only the first four bytes of data. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">Array of <see cref="byte"/>s that were read</param> /// <param name="tag">The tag identifying the read operation</param> private void SocketDidReadIndicatorBytes(AsyncSocket socket, byte[] readBytes, long tag) { // remove this event handler since we dont need it any more socket.DidRead -= new AsyncSocket.SocketDidRead(this.SocketDidReadIndicatorBytes); Data data = new Data(readBytes); string s = data.ToString(); if (tag == ACCEPT_TAG) { if (s == FlashPolicy.REQUEST_INDICATOR) { GNTPFlashSocketReader gfsr = new GNTPFlashSocketReader(socket, allowBrowserConnections); gfsr.Read(readBytes); } else if (s == WebSocketHandshakeHandler.REQUEST_INDICATOR) { // this is a GNTP over WebSocket request, so we have to do the WebSocket handshake first socket.Tag = readBytes; WebSocketHandshakeHandler wshh = new WebSocketHandshakeHandler(socket, "*", "ws://localhost:23053"); wshh.DoHandshake(delegate() { // now pass off to the GNTPWebSocketReader (which is just a normal GNTPSocketReader that can deal with the WebSocket framing of packets) GNTPWebSocketReader gwsr = new GNTPWebSocketReader(socket, passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, this.requestInfo); this.requestReader = gwsr; gwsr.MessageParsed += new GNTPRequestReader.GNTPRequestReaderMessageParsedEventHandler(requestReader_MessageParsed); gwsr.Error += new GNTPRequestReader.GNTPRequestReaderErrorEventHandler(requestReader_Error); gwsr.Read(readBytes); }); } else { // this is a normal GNTP/TCP connection, so handle it as such GNTPSocketReader gsr = new GNTPSocketReader(socket, passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, this.requestInfo); this.requestReader = gsr; gsr.MessageParsed += new GNTPRequestReader.GNTPRequestReaderMessageParsedEventHandler(requestReader_MessageParsed); gsr.Error += new GNTPRequestReader.GNTPRequestReaderErrorEventHandler(requestReader_Error); gsr.Read(readBytes); } } else { WriteError(socket, ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST); } }
/// <summary> /// Handles the socket's DidRead event. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">Array of <see cref="byte"/>s that were read</param> /// <param name="tag">The tag identifying the read operation</param> protected virtual void SocketDidRead(AsyncSocket socket, byte[] readBytes, long tag) { try { Data data = new Data(readBytes); this.AlreadyReceivedData.Append(data.ToString()); GNTPParser parser = (GNTPParser)socket.Tag; NextIndicator next = parser.Parse(readBytes); if (next.ShouldContinue) { if (next.UseBytes) { socket.Read(next.Bytes, TIMEOUT_GNTP_HEADER, parser.Tag); } else { socket.Read(next.Length, TIMEOUT_GNTP_BINARY, parser.Tag); } } } catch (GrowlException gEx) { OnError(gEx.ErrorCode, gEx.Message, gEx.AdditionalInfo); } catch (Exception ex) { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST, ex.Message); } }
private void ProcessBuffer() { try { Data data = new Data(buffer.ToArray()); string s = data.ToString(); alreadyReceived.Append(s); if (tag == START_TAG) { // start looking for GNTP header tag = GNTP_IDENTIFIER_TAG; ContinueProcessing(); } else if (tag == GNTP_IDENTIFIER_TAG) { string line = s; Match match = ParseGNTPHeaderLine(line, this.passwordRequired); if (match.Success) { this.version = match.Groups["Version"].Value; if (version == MessageParser.GNTP_SUPPORTED_VERSION) { string d = match.Groups["Directive"].Value; if (Enum.IsDefined(typeof(RequestType), d)) { this.directive = (RequestType)Enum.Parse(typeof(RequestType), d); // check for supported but not allowed requests if (this.directive == RequestType.SUBSCRIBE && !this.allowSubscriptions) { OnError(ErrorCode.NOT_AUTHORIZED, ErrorDescription.SUBSCRIPTIONS_NOT_ALLOWED); } else { this.encryptionAlgorithm = Cryptography.GetEncryptionType(match.Groups["EncryptionAlgorithm"].Value); this.ivHex = (match.Groups["IV"] != null ? match.Groups["IV"].Value : null); if (!String.IsNullOrEmpty(this.ivHex)) this.iv = Cryptography.HexUnencode(this.ivHex); string keyHash = match.Groups["KeyHash"].Value.ToUpper(); bool authorized = false; // Any of the following criteria require a password: // 1. the request did not originate on the local machine or LAN // 2. the request came from the LAN, but LAN passwords are required // 2. it is a SUBSCRIBE request (all subscriptions require a password) // 3. the user's preferences require even local requests to supply a password // Additionally, even if a password is not required, it will be validated if the // sending appplication includes one string errorDescription = ErrorDescription.INVALID_KEY; if (this.passwordRequired || this.directive == RequestType.SUBSCRIBE || !String.IsNullOrEmpty(keyHash)) { if (String.IsNullOrEmpty(keyHash)) { errorDescription = ErrorDescription.MISSING_KEY; } else { string keyHashAlgorithmType = match.Groups["KeyHashAlgorithm"].Value; this.keyHashAlgorithm = Cryptography.GetKeyHashType(keyHashAlgorithmType); string salt = match.Groups["Salt"].Value.ToUpper(); authorized = this.passwordManager.IsValid(keyHash, salt, this.keyHashAlgorithm, this.encryptionAlgorithm, out this.key); } } else { authorized = true; this.key = Key.None; } if (authorized) { if (this.encryptionAlgorithm == Cryptography.SymmetricAlgorithmType.PlainText) { tag = HEADER_TAG; ContinueProcessing(); } else { tag = ENCRYPTED_HEADERS_TAG; ContinueProcessing(); } } else { OnError(ErrorCode.NOT_AUTHORIZED, errorDescription); } } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNSUPPORTED_DIRECTIVE, d); } } else { OnError(ErrorCode.UNKNOWN_PROTOCOL_VERSION, ErrorDescription.UNSUPPORTED_VERSION, version); } } else { OnError(ErrorCode.UNKNOWN_PROTOCOL, ErrorDescription.MALFORMED_REQUEST); } } else if (tag == HEADER_TAG) { if (s == MessageParser.BLANK_LINE) { // if this is a REGISTER message, check Notifications-Count value // to see how many notification sections to expect if (this.directive == RequestType.REGISTER) { if (this.expectedNotifications > 0) { tag = NOTIFICATION_TYPE_TAG; ContinueProcessing(); } else { // a REGISTER request with no notifications is not valid OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.NO_NOTIFICATIONS_REGISTERED); } } else { // otherwise, check the number of resource pointers we got and start reading those this.pointersExpected = GetNumberOfPointers(); if (this.pointersExpected > 0) { this.pointersExpectedRemaining = this.pointersExpected; this.currentPointer = 1; tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } else { OnMessageParsed(); } } } else { Header header = Header.ParseHeader(s); if (header != null) { bool addHeader = true; if (header.Name == Header.APPLICATION_NAME) { this.applicationName = header.Value; } if (header.Name == Header.NOTIFICATIONS_COUNT) { this.expectedNotifications = Convert.ToInt32(header.Value); this.expectedNotificationsRemaining = this.expectedNotifications; this.currentNotification = 1; } if (header.Name == Header.NOTIFICATION_CALLBACK_CONTEXT) { this.callbackData = header.Value; } if (header.Name == Header.NOTIFICATION_CALLBACK_CONTEXT_TYPE) { this.callbackDataType = header.Value; } if (header.Name == Header.NOTIFICATION_CALLBACK_TARGET || header.Name == Header.NOTIFICATION_CALLBACK_CONTEXT_TARGET) // left in for compatibility { this.callbackUrl = header.Value; } if (header.Name == Header.RECEIVED) { this.requestInfo.PreviousReceivedHeaders.Add(header); addHeader = false; } if (addHeader) this.headers.AddHeader(header); } tag = HEADER_TAG; ContinueProcessing(); } } else if (tag == NOTIFICATION_TYPE_TAG) { if (s == MessageParser.BLANK_LINE) { this.expectedNotificationsRemaining--; if (this.expectedNotificationsRemaining > 0) { this.currentNotification++; tag = NOTIFICATION_TYPE_TAG; ContinueProcessing(); } else { // otherwise, check the number of resource pointers we got and start reading those this.pointersExpected = GetNumberOfPointers(); if (this.pointersExpected > 0) { this.pointersExpectedRemaining = this.pointersExpected; this.currentPointer = 1; tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } else { OnMessageParsed(); } } } else { if (this.notificationsToBeRegistered.Count < this.currentNotification) { this.notificationsToBeRegistered.Add(new HeaderCollection()); } Header header = Header.ParseHeader(s); this.notificationsToBeRegistered[this.currentNotification - 1].AddHeader(header); tag = NOTIFICATION_TYPE_TAG; ContinueProcessing(); } } else if (tag == RESOURCE_HEADER_TAG) { if (s == MessageParser.BLANK_LINE) { // we should have found an Identifier header and Length header, or we are just starting a new section Pointer p = this.pointers[this.currentPointer - 1]; if (p.Identifier != null && p.Length > 0) { // read #of bytes int length = this.pointers[this.currentPointer - 1].Length; tag = RESOURCE_TAG; ContinueProcessing(); } else { tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } } else { Header header = Header.ParseHeader(s); // should be Identifer or Length if (header != null) { bool validHeader = false; if (header.Name == Header.RESOURCE_IDENTIFIER) { this.pointers[this.currentPointer - 1].Identifier = header.Value; validHeader = true; } else if (header.Name == Header.RESOURCE_LENGTH) { this.pointers[this.currentPointer - 1].Length = Convert.ToInt32(header.Value); validHeader = true; } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNRECOGNIZED_RESOURCE_HEADER, header.Name); } if (validHeader) { tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNRECOGNIZED_RESOURCE_HEADER); } } } else if (tag == RESOURCE_TAG) { // deal with data bytes byte[] bytes = this.key.Decrypt(data.ByteArray, this.iv); Pointer pointer = this.pointers[this.currentPointer - 1]; pointer.ByteArray = bytes; BinaryData binaryData = new BinaryData(pointer.Identifier, pointer.ByteArray); ResourceCache.Add(this.applicationName, binaryData); this.pointersExpectedRemaining--; if (this.pointersExpectedRemaining > 0) { this.currentPointer++; tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } else { OnMessageParsed(); } } else if (tag == ENCRYPTED_HEADERS_TAG) { // see if a length was specified (the original spec did not require the main encrypted headers portion to specify a length) if (s.StartsWith(Header.RESOURCE_LENGTH)) { Header header = Header.ParseHeader(s); if (header != null) { int len = Convert.ToInt32(header.Value); tag = ENCRYPTED_HEADERS_TAG; ContinueProcessing(); } } ParseEncryptedMessage(data.ByteArray); if (this.pointersExpected > 0) { tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } else { OnMessageParsed(); } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST); } } catch (GrowlException gEx) { OnError(gEx.ErrorCode, gEx.Message, gEx.AdditionalInfo); } catch (Exception ex) { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST, ex.Message); } }
/// <summary> /// Logs the specified data. /// </summary> /// <param name="data">The <see cref="Data"/> to log</param> public void Log(Data data) { try { if (this.loggingEnabled && !String.IsNullOrEmpty(this.logFolder)) { string filename = String.Format(@"GNTP_{0}.txt", this.requestInfo.RequestID); string filepath = PathUtility.Combine(this.logFolder, filename); bool exists = System.IO.File.Exists(filepath); if (!exists) { // log the initial request/response System.IO.StreamWriter w = System.IO.File.CreateText(filepath); using (w) { w.Write("Timestamp: {0}\r\n", DateTime.Now.ToString()); foreach (string item in this.requestInfo.HandlingInfo) { w.Write(String.Format("{0}\r\n", item)); } w.Write(SEPERATOR); if (this.requestReader != null) { w.Write(this.requestReader.ReceivedData); if (!String.IsNullOrEmpty(this.requestReader.DecryptedData)) { w.Write(SEPERATOR); w.Write(this.requestReader.DecryptedData); } } w.Write(SEPERATOR); w.Write(data.ToString()); w.Close(); this.requestInfo.HandlingInfo.Clear(); } } else { // this is for logging callback data System.IO.StreamWriter w = new System.IO.StreamWriter(filepath, true); using (w) { w.Write(SEPERATOR); w.Write("Timestamp: {0}\r\n", DateTime.Now.ToString()); foreach (string item in this.requestInfo.HandlingInfo) { w.Write(String.Format("{0}\r\n", item)); } w.Write(SEPERATOR); w.Write(data.ToString()); w.Close(); } } } } catch { // suppress logging exceptions } }
/// <summary> /// Handles the socket's DidRead event after reading only the first four bytes of data. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">Array of <see cref="byte"/>s that were read</param> /// <param name="tag">The tag identifying the read operation</param> private void SocketDidReadIndicatorBytes(AsyncSocket socket, byte[] readBytes, long tag) { // remove this event handler since we dont need it any more socket.DidRead -= new AsyncSocket.SocketDidRead(this.SocketDidReadIndicatorBytes); Data data = new Data(readBytes); string s = data.ToString(); if (tag == ACCEPT_TAG) { if (s == FlashPolicy.REQUEST_INDICATOR) { GNTPFlashSocketReader gfsr = new GNTPFlashSocketReader(socket, allowBrowserConnections); gfsr.Read(readBytes); } else if (s == WebSocketHandshakeHandler.REQUEST_INDICATOR) { // this is a GNTP over WebSocket request, so we have to do the WebSocket handshake first socket.Tag = readBytes; WebSocketHandshakeHandler wshh = new WebSocketHandshakeHandler(socket, "*", "ws://localhost:23053"); wshh.DoHandshake(delegate() { // now pass off to the GNTPWebSocketReader (which is just a normal GNTPSocketReader that can deal with the WebSocket framing of packets) GNTPWebSocketReader gwsr = new GNTPWebSocketReader(socket, passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, this.requestInfo); this.requestReader = gwsr; gwsr.MessageParsed += new GNTPRequestReader.GNTPRequestReaderMessageParsedEventHandler(requestReader_MessageParsed); gwsr.Error += new GNTPRequestReader.GNTPRequestReaderErrorEventHandler(requestReader_Error); gwsr.Read(readBytes); }); } else { // this is a normal GNTP/TCP connection, so handle it as such GNTPSocketReader gsr = new GNTPSocketReader(socket, passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, this.requestInfo); this.requestReader = gsr; gsr.MessageParsed += new GNTPRequestReader.GNTPRequestReaderMessageParsedEventHandler(requestReader_MessageParsed); gsr.Error += new GNTPRequestReader.GNTPRequestReaderErrorEventHandler(requestReader_Error); gsr.Read(readBytes); } } else { WriteError(socket, ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST); } }
private void ProcessBuffer() { try { Data data = new Data(buffer.ToArray()); string s = data.ToString(); alreadyReceived.Append(s); if (tag == START_TAG) { // start looking for GNTP header tag = GNTP_IDENTIFIER_TAG; ContinueProcessing(); } else if (tag == GNTP_IDENTIFIER_TAG) { string line = s; Match match = ParseGNTPHeaderLine(line, this.passwordRequired); if (match.Success) { this.version = match.Groups["Version"].Value; if (version == MessageParser.GNTP_SUPPORTED_VERSION) { string d = match.Groups["Directive"].Value; if (Enum.IsDefined(typeof(RequestType), d)) { this.directive = (RequestType)Enum.Parse(typeof(RequestType), d); // check for supported but not allowed requests if (this.directive == RequestType.SUBSCRIBE && !this.allowSubscriptions) { OnError(ErrorCode.NOT_AUTHORIZED, ErrorDescription.SUBSCRIPTIONS_NOT_ALLOWED); } else { this.encryptionAlgorithm = Cryptography.GetEncryptionType(match.Groups["EncryptionAlgorithm"].Value); this.ivHex = (match.Groups["IV"] != null ? match.Groups["IV"].Value : null); if (!String.IsNullOrEmpty(this.ivHex)) { this.iv = Cryptography.HexUnencode(this.ivHex); } string keyHash = match.Groups["KeyHash"].Value.ToUpper(); bool authorized = false; // Any of the following criteria require a password: // 1. the request did not originate on the local machine or LAN // 2. the request came from the LAN, but LAN passwords are required // 2. it is a SUBSCRIBE request (all subscriptions require a password) // 3. the user's preferences require even local requests to supply a password // Additionally, even if a password is not required, it will be validated if the // sending appplication includes one string errorDescription = ErrorDescription.INVALID_KEY; if (this.passwordRequired || this.directive == RequestType.SUBSCRIBE || !String.IsNullOrEmpty(keyHash)) { if (String.IsNullOrEmpty(keyHash)) { errorDescription = ErrorDescription.MISSING_KEY; } else { string keyHashAlgorithmType = match.Groups["KeyHashAlgorithm"].Value; this.keyHashAlgorithm = Cryptography.GetKeyHashType(keyHashAlgorithmType); string salt = match.Groups["Salt"].Value.ToUpper(); authorized = this.passwordManager.IsValid(keyHash, salt, this.keyHashAlgorithm, this.encryptionAlgorithm, out this.key); } } else { authorized = true; this.key = Key.None; } if (authorized) { if (this.encryptionAlgorithm == Cryptography.SymmetricAlgorithmType.PlainText) { tag = HEADER_TAG; ContinueProcessing(); } else { tag = ENCRYPTED_HEADERS_TAG; ContinueProcessing(); } } else { OnError(ErrorCode.NOT_AUTHORIZED, errorDescription); } } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNSUPPORTED_DIRECTIVE, d); } } else { OnError(ErrorCode.UNKNOWN_PROTOCOL_VERSION, ErrorDescription.UNSUPPORTED_VERSION, version); } } else { OnError(ErrorCode.UNKNOWN_PROTOCOL, ErrorDescription.MALFORMED_REQUEST); } } else if (tag == HEADER_TAG) { if (s == MessageParser.BLANK_LINE) { // if this is a REGISTER message, check Notifications-Count value // to see how many notification sections to expect if (this.directive == RequestType.REGISTER) { if (this.expectedNotifications > 0) { tag = NOTIFICATION_TYPE_TAG; ContinueProcessing(); } else { // a REGISTER request with no notifications is not valid OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.NO_NOTIFICATIONS_REGISTERED); } } else { // otherwise, check the number of resource pointers we got and start reading those this.pointersExpected = GetNumberOfPointers(); if (this.pointersExpected > 0) { this.pointersExpectedRemaining = this.pointersExpected; this.currentPointer = 1; tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } else { OnMessageParsed(); } } } else { Header header = Header.ParseHeader(s); if (header != null) { bool addHeader = true; if (header.Name == Header.APPLICATION_NAME) { this.applicationName = header.Value; } if (header.Name == Header.NOTIFICATIONS_COUNT) { this.expectedNotifications = Convert.ToInt32(header.Value); this.expectedNotificationsRemaining = this.expectedNotifications; this.currentNotification = 1; } if (header.Name == Header.NOTIFICATION_CALLBACK_CONTEXT) { this.callbackData = header.Value; } if (header.Name == Header.NOTIFICATION_CALLBACK_CONTEXT_TYPE) { this.callbackDataType = header.Value; } if (header.Name == Header.NOTIFICATION_CALLBACK_TARGET || header.Name == Header.NOTIFICATION_CALLBACK_CONTEXT_TARGET) // left in for compatibility { this.callbackUrl = header.Value; } if (header.Name == Header.RECEIVED) { this.requestInfo.PreviousReceivedHeaders.Add(header); addHeader = false; } if (addHeader) { this.headers.AddHeader(header); } } tag = HEADER_TAG; ContinueProcessing(); } } else if (tag == NOTIFICATION_TYPE_TAG) { if (s == MessageParser.BLANK_LINE) { this.expectedNotificationsRemaining--; if (this.expectedNotificationsRemaining > 0) { this.currentNotification++; tag = NOTIFICATION_TYPE_TAG; ContinueProcessing(); } else { // otherwise, check the number of resource pointers we got and start reading those this.pointersExpected = GetNumberOfPointers(); if (this.pointersExpected > 0) { this.pointersExpectedRemaining = this.pointersExpected; this.currentPointer = 1; tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } else { OnMessageParsed(); } } } else { if (this.notificationsToBeRegistered.Count < this.currentNotification) { this.notificationsToBeRegistered.Add(new HeaderCollection()); } Header header = Header.ParseHeader(s); this.notificationsToBeRegistered[this.currentNotification - 1].AddHeader(header); tag = NOTIFICATION_TYPE_TAG; ContinueProcessing(); } } else if (tag == RESOURCE_HEADER_TAG) { if (s == MessageParser.BLANK_LINE) { // we should have found an Identifier header and Length header, or we are just starting a new section Pointer p = this.pointers[this.currentPointer - 1]; if (p.Identifier != null && p.Length > 0) { // read #of bytes int length = this.pointers[this.currentPointer - 1].Length; tag = RESOURCE_TAG; ContinueProcessing(); } else { tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } } else { Header header = Header.ParseHeader(s); // should be Identifer or Length if (header != null) { bool validHeader = false; if (header.Name == Header.RESOURCE_IDENTIFIER) { this.pointers[this.currentPointer - 1].Identifier = header.Value; validHeader = true; } else if (header.Name == Header.RESOURCE_LENGTH) { this.pointers[this.currentPointer - 1].Length = Convert.ToInt32(header.Value); validHeader = true; } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNRECOGNIZED_RESOURCE_HEADER, header.Name); } if (validHeader) { tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.UNRECOGNIZED_RESOURCE_HEADER); } } } else if (tag == RESOURCE_TAG) { // deal with data bytes byte[] bytes = this.key.Decrypt(data.ByteArray, this.iv); Pointer pointer = this.pointers[this.currentPointer - 1]; pointer.ByteArray = bytes; BinaryData binaryData = new BinaryData(pointer.Identifier, pointer.ByteArray); ResourceCache.Add(this.applicationName, binaryData); this.pointersExpectedRemaining--; if (this.pointersExpectedRemaining > 0) { this.currentPointer++; tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } else { OnMessageParsed(); } } else if (tag == ENCRYPTED_HEADERS_TAG) { // see if a length was specified (the original spec did not require the main encrypted headers portion to specify a length) if (s.StartsWith(Header.RESOURCE_LENGTH)) { Header header = Header.ParseHeader(s); if (header != null) { int len = Convert.ToInt32(header.Value); tag = ENCRYPTED_HEADERS_TAG; ContinueProcessing(); } } ParseEncryptedMessage(data.ByteArray); if (this.pointersExpected > 0) { tag = RESOURCE_HEADER_TAG; ContinueProcessing(); } else { OnMessageParsed(); } } else { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST); } } catch (GrowlException gEx) { OnError(gEx.ErrorCode, gEx.Message, gEx.AdditionalInfo); } catch (Exception ex) { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST, ex.Message); } }
/// <summary> /// Handles the socket's DidRead event. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="readBytes">Array of <see cref="byte"/>s that were read</param> /// <param name="tag">The tag identifying the read operation</param> protected virtual void SocketDidRead(AsyncSocket socket, byte[] readBytes, long tag) { try { Data data = new Data(readBytes); this.AlreadyReceivedData.Append(data.ToString()); GNTPParser parser = (GNTPParser)socket.Tag; NextIndicator next = parser.Parse(readBytes); if (next.ShouldContinue) { if (next.UseBytes) socket.Read(next.Bytes, TIMEOUT_GNTP_HEADER, parser.Tag); else socket.Read(next.Length, TIMEOUT_GNTP_BINARY, parser.Tag); } } catch (GrowlException gEx) { OnError(gEx.ErrorCode, gEx.Message, gEx.AdditionalInfo); } catch (Exception ex) { OnError(ErrorCode.INVALID_REQUEST, ErrorDescription.MALFORMED_REQUEST, ex.Message); } }