/// <summary> /// Handles the HTTP response. /// </summary> /// <param name="iEvent">Socket event arguments object.</param> private void ProcessHttp(SocketAsyncEventArgs iEvent) { // resize response buffer if not enough if ((_RspLength + iEvent.BytesTransferred) < _RspBfr.Length) { Array.Resize(ref _RspBfr, _RspLength + iEvent.BytesTransferred); } // append new data to response buffer Array.Copy(iEvent.Buffer, 0, _RspBfr, _RspLength, iEvent.BytesTransferred); // update new response length _RspLength += iEvent.BytesTransferred; Int32 aBeg = 0; Int32 aB = 0; Int32 aEnd = _RspLength; String aTemp = String.Empty; Int32 aMsgLength = 0; byte[] aCookie = null; bool aClear = true; // process response buffer loop while (aBeg < aEnd) { // skip whitespaces while ((Char.IsWhiteSpace((char)_RspBfr[aBeg])) && (aBeg < aEnd)) { aBeg++; } // buffer overflow protection if (aBeg == aEnd) { aClear = false; break; // not enough bytes } // make sure we can read the protocol header if (aBeg + HTTP_HDR.Length > aEnd) { aClear = false; break; // not enough bytes } // read the protocol header aTemp = System.Text.Encoding.ASCII.GetString(_RspBfr, aBeg, HTTP_HDR.Length); if (aTemp != HTTP_HDR) { // EMIT PROTOCOL ERROR SocketErrorEventArgs aSocketError = new SocketErrorEventArgs(); aSocketError.Error = "Unknown Procotol"; SocketErrorEvent(this, aSocketError); break; } aB = aBeg; // extract Set-Cookie and Content-Length loop do { // scan past next newline while (aB < aEnd && ((char)_RspBfr[aB++]) != '\n') { ; } if (aB + SET_COOKIE.Length < aEnd && _RspBfr[aB] == 'S' && _RspBfr[aB + 1] == 'e' && _RspBfr[aB + 2] == 't' && _RspBfr[aB + 3] == '-' && _RspBfr[aB + 4] == 'C' && _RspBfr[aB + 5] == 'o' && _RspBfr[aB + 6] == 'o' && _RspBfr[aB + 7] == 'k' && _RspBfr[aB + 8] == 'i' && _RspBfr[aB + 9] == 'e') { // scan past the colon (:) while ((aB < aEnd) && (_RspBfr[aB++] != ':')) { ; } if (aB < aEnd) { Int32 aEol = 0; if (_RspBfr[aB] == ' ') { aB++; } for (aEol = aB; (aEol < aEnd) && (_RspBfr[aEol] != '\r') && (_RspBfr[aEol] != '\n'); aEol++) { ; } aCookie = new byte[aEol - aB]; Array.Copy(_RspBfr, aB, aCookie, 0, aEol - aB); } } else if (aB + CONTENT_LENGTH.Length < aEnd && _RspBfr[aB] == 'C' && _RspBfr[aB + 1] == 'o' && _RspBfr[aB + 2] == 'n' && _RspBfr[aB + 3] == 't' && _RspBfr[aB + 4] == 'e' && _RspBfr[aB + 5] == 'n' && _RspBfr[aB + 6] == 't' && _RspBfr[aB + 7] == '-' && _RspBfr[aB + 8] == 'L' && _RspBfr[aB + 9] == 'e' && _RspBfr[aB + 10] == 'g' && _RspBfr[aB + 11] == 'n' && _RspBfr[aB + 12] == 't' && _RspBfr[aB + 13] == 'h') { while ((aB < aEnd) && _RspBfr[aB] < '0' || _RspBfr[aB] > '9') { aB++; } // get the content-length if (aB < aEnd) { Int32 aEol = 0; for (aEol = aB; (aEol < aEnd) && (_RspBfr[aEol] != '\r') && (_RspBfr[aEol] != '\n'); aEol++) { ; } aTemp = Encoding.ASCII.GetString(_RspBfr, aB, (aEol - aB)); try { aMsgLength = Int32.Parse(aTemp); } catch (FormatException) { Debug.WriteLine("Invalid Content-Length value."); } } } else if (_RspBfr[aB] == '\r') { aB++; } } // extract Set-Cookie and Content-Length loop while (aB < aEnd && (_RspBfr[aB++]) != '\n'); // partial. save the partial request. // aBeg = Beginning of this message // aB = Beginning of the body of request if (aB + aMsgLength > aEnd) { // if aBeg has been moved past the beginning of the buffer // just keep the partial if (aBeg > 0) { // create new buffer byte[] aNewBfr = new byte[aEnd - aBeg]; Array.Copy(_RspBfr, aBeg, aNewBfr, 0, aNewBfr.Length); _RspBfr = aNewBfr; } aBeg = aB + aMsgLength; // DO NOT CLEAR BUFFER aClear = false; // quit the main loop break; } else { ResponseEventArgs aHtmlResponse = new ResponseEventArgs(); aHtmlResponse.ResponseBuffer = new byte[aMsgLength]; aHtmlResponse.CookieBuffer = aCookie; Array.Copy(_RspBfr, aB, aHtmlResponse.ResponseBuffer, 0, aMsgLength); // emit response signal ResponseEvent(this, aHtmlResponse); // move aBeg to end of body aBeg += aMsgLength; } } if (aClear) { _RspLength = 0; } // call asynchronous read again _RemoteSocket.ReceiveAsync(iEvent); } // end of process response buffer loop
/// <summary> /// Handles the XML response. /// </summary> /// <param name="iEvent">Socket event arguments object.</param> private void ProcessXml(SocketAsyncEventArgs iEvent) { // resize response buffer if not enough if ((_RspLength + iEvent.BytesTransferred) < _RspBfr.Length) { Array.Resize(ref _RspBfr, _RspLength + iEvent.BytesTransferred); } // append new data to response buffer Array.Copy(iEvent.Buffer, 0, _RspBfr, _RspLength, iEvent.BytesTransferred); // update new response length _RspLength += iEvent.BytesTransferred; Int32 aBeg = 0; Int32 aB = 0; Int32 aEnd = _RspLength; String aTemp = String.Empty; bool aClear = true; // process response buffer loop while (aBeg < aEnd) { // skip whitespaces while ((Char.IsWhiteSpace((char)_RspBfr[aBeg])) && (aBeg < aEnd)) { aBeg++; } // buffer overflow protection if (aBeg == aEnd) { aClear = false; break; // not enough bytes } // make sure we can read the protocol header if (aBeg + XML_HDR.Length > aEnd) { aClear = false; break; // not enough bytes } // read the protocol header aTemp = System.Text.Encoding.ASCII.GetString(_RspBfr, aBeg, XML_HDR.Length); if (aTemp != XML_HDR) { // EMIT PROTOCOL ERROR SocketErrorEventArgs aSocketError = new SocketErrorEventArgs(); aSocketError.Error = "Unknown Protocol"; SocketErrorEvent(this, aSocketError); break; } for (aB = aBeg; aB < aEnd && _RspBfr[aB] > MSG_TERM; aB++) { ; } // if read past the last character if (aB == aEnd) { // DO NOT CLEAR BUFFER aClear = false; break; } // partial. save partial request. // aBeg - Beginning of next response // aB - end of this response if (_RspBfr[aB] > MSG_TERM) { // if aBeg has been moved past the beginning of the buffer if (aBeg > 0) { byte[] aNewBuffer = new byte[aEnd - aBeg]; Array.Copy(_RspBfr, aBeg, aNewBuffer, 0, aNewBuffer.Length); _RspBfr = aNewBuffer; } // DO NOT CLEAR BUFFER aClear = false; break; } // NULL terminate the response _RspBfr[aB] = (byte)MSG_NULL; ResponseEventArgs aResponse = new ResponseEventArgs(); aResponse.ResponseBuffer = new byte[aB + 1]; Array.Copy(_RspBfr, aBeg, aResponse.ResponseBuffer, 0, aB + 1); // emit response signal ResponseEvent(this, aResponse); // move aBeg to aBeg = aB + 1; } if (aClear) { _RspLength = 0; } // call asynchronous read again _RemoteSocket.ReceiveAsync(iEvent); }
/// <summary> /// Handles the APP response. /// </summary> /// <param name="iEvent">Async receive arguments object.</param> private void ProcessApp(SocketAsyncEventArgs iEvent) { byte[] aBuffer = iEvent.Buffer; // buffer reference String aTemp = String.Empty; // temporary string String aErrorMessage = String.Empty; // error message bool aError = false; // error flag bool aEmit = false; // emit signal flag switch (_AppReadState) { case AppReadState.ReadingResponseLength: // check if length field was read correctly // and message delimiter is present if (iEvent.BytesTransferred == LENGTH_SIZE && aBuffer[LENGTH_SIZE - 1] == MSG_DELIM) { // convert length field to integer aTemp = Encoding.ASCII.GetString(aBuffer, 0, LENGTH_SIZE - 1); try { // get the expected size of response _ResponseSize = Int32.Parse(aTemp); } catch (FormatException) { // error in number conversion aErrorMessage = "Invalid response message size format."; aError = true; } // response size is valid if (_ResponseSize > 0) { // set state to reading data length _AppReadState = AppReadState.ReadingDataLength; } else { // response size is invalid aErrorMessage = "Invalid response message size."; aError = true; } } else { // protocol error aErrorMessage = "Unable to extract response message size."; aError = true; } break; case AppReadState.ReadingDataLength: // check if length field was read correctly if (iEvent.BytesTransferred == LENGTH_SIZE && aBuffer[LENGTH_SIZE - 1] == MSG_DELIM) { // convert binary data length field to integer aTemp = Encoding.ASCII.GetString(aBuffer, 0, LENGTH_SIZE - 1); try { // get the expected size of binary data _DataSize = Int32.Parse(aTemp); } catch (FormatException) { // error in number conversion aErrorMessage = "Invalid binary data size format."; aError = true; } if (_DataSize >= 0) { // check size of response buffer if (_RspBfr.Length <= _ResponseSize) { // increase buffer size _RspBfr = new byte[_ResponseSize + 1]; } // read the response message (including terminator) _AppReadState = AppReadState.ReadingResponse; iEvent.SetBuffer(_RspBfr, 0, _ResponseSize + 1); } else { // binary data size is invalid aErrorMessage = "Invalid binary data size."; aError = true; } } else { // protocol error aErrorMessage = "Unable to extract binary data size"; aError = true; } break; case AppReadState.ReadingResponse: // update the bytes received _RspLength += iEvent.BytesTransferred; // if read response is complete if (_RspLength == _ResponseSize + 1) { // check if terminator is present if (_RspBfr[_ResponseSize] > MSG_TERM) { // allow to continue Debug.WriteLine("Encountered unterminated response in message."); } // put null terminator _RspBfr[_ResponseSize] = (byte)MSG_NULL; // if binary data is expected if (_DataSize > 0) { // if data buffer not present or not enough if (_DataBfr == null || _DataBfr.Length < _DataSize) { _DataBfr = new byte[_DataSize]; } // read data _AppReadState = AppReadState.ReadingData; iEvent.SetBuffer(_DataBfr, 0, _DataSize); } else { // read complete, signal response event aEmit = true; } } else { // partial response received // continue reading the remaining bytes iEvent.SetBuffer(_RspLength, _ResponseSize - _RspLength + 1); } break; case AppReadState.ReadingData: // update the bytes received _DataLength += iEvent.BytesTransferred; // if read binary data is complete if (_DataLength == _DataSize) { // read complete, signal response event aEmit = true; } else { // partial binary data received // continue reading the remaining bytes iEvent.SetBuffer(_DataLength, _DataSize - _DataLength); } break; } // on emit if (aEmit) { // Get ready to emit response to subscribers ResponseEventArgs aResEvtArgs = new ResponseEventArgs(); aResEvtArgs.ResponseBuffer = new byte[_ResponseSize + 1]; Array.Copy(_RspBfr, aResEvtArgs.ResponseBuffer, _ResponseSize + 1); // if binary data is available if (_DataLength > 0) { aResEvtArgs.DataBuffer = new byte[_DataSize]; Array.Copy(_DataBfr, aResEvtArgs.DataBuffer, _DataSize); } // Signal response event ResponseEvent(this, aResEvtArgs); // Reset state variables _RspLength = 0; _ResponseSize = 0; _DataLength = 0; _DataSize = 0; _AppReadState = AppReadState.ReadingResponseLength; iEvent.SetBuffer(_RspBfr, 0, LENGTH_SIZE); } // on error if (aError) { // Display error message Debug.WriteLine(aErrorMessage); // Clear socket buffer DumpSocketBuffer(); // Reset read state _RspLength = 0; _ResponseSize = 0; _DataLength = 0; _DataSize = 0; _AppReadState = AppReadState.ReadingResponseLength; iEvent.SetBuffer(_RspBfr, 0, LENGTH_SIZE); } // trigger next asynchronous read _RemoteSocket.ReceiveAsync(iEvent); }