/// <summary> /// Primary Signature for Analyzing Package. Review received bytes and put them into the package container. /// Added delayWriteIndicator in case write occured in this context we want to delay writing for POST. /// </summary> private byte[] AnalyzePackage(ref bool delayWriteIndicator, byte[] receiveBuffer, bool skipFlush = false, int iOffset = 0) { //the packages received by tomcat have to start with the correct package signature start bytes (41 42 or AB) int iStart = 0 + iOffset; //offset determines where we start in this package byte[] searchFor = new byte[2] { 0x41, 0x42 }; int packetLength = 0; byte[] unalyzedBytes = null; int iSafety = 0; //safety check for exit condition (with standard packets and a min packet size of 4 bytes max theoretical packets to be analyze is 8196/4) while (iStart >= 0 && iStart <= receiveBuffer.Length - 1 && iSafety <= 2050) { iSafety++; //find packet start bytes (41 42 or AB) iStart = ByteSearch(receiveBuffer, searchFor, iStart); if (iStart >= 0) { //determine end of packet if this is negative we need continue scanning try { packetLength = GetInt16B(receiveBuffer, iStart + 2); } catch (Exception e) { //log exception if (p_Logger != null) p_Logger.LogException(e, "packet length determination problem", 1); } //check whether we have sufficient data in receive buffer to analyze package if (packetLength + iStart + 4 <= receiveBuffer.Length) { //TODO: check whether packet length is beyond maximum and throw error int packetType = (int)receiveBuffer[iStart + 4]; byte[] userData = new byte[packetLength]; string adobePath = ""; string requestPath = ""; //we skip 4-bytes:magic (AB) and packet length markers when determining user data Array.Copy(receiveBuffer, iStart + 4, userData, 0, packetLength); //Detect Correct packet Type and create instance of store switch (packetType) { case BonCodeAJP13TomcatPacketType.TOMCAT_GETBODYCHUNK: p_PacketsReceived.Add(new TomcatGetBodyChunk(userData)); //if this command is encountered when only one GET package was previously send (no multi-packets) we need to send a terminator body package if (p_PacketsToSend.Count == 1) { p_SendTermPacket = true; } //p_NetworkStream.Write(sendPacket.GetDataBytes(), 0, sendPacket.PacketLength); break; case BonCodeAJP13TomcatPacketType.TOMCAT_ENDRESPONSE: p_PacketsReceived.Add(new TomcatEndResponse(userData)); //this is the termination indicator we need to stop processing from here on. This can happen //when we post data as well. Tomcat can indicate a connection stop and we need to stop processing as well. break; case BonCodeAJP13TomcatPacketType.TOMCAT_SENDHEADERS: p_PacketsReceived.Add(new TomcatSendHeaders(userData)); break; case BonCodeAJP13TomcatPacketType.TOMCAT_CPONGREPLY: p_PacketsReceived.Add(new TomcatCPongReply(userData)); break; case BonCodeAJP13TomcatPacketType.TOMCAT_SENDBODYCHUNK: //only add user data if there is something so we don't create null packets (this condition may not occur) if (userData.Length > 0) { p_PacketsReceived.Add(new TomcatSendBodyChunk(userData)); //check whether we have an AJP flush and whether we will accept it. In that case we have only four bytes in the packet. No user payload. if (userData.Length == 4 && (BonCodeAJP13Settings.BONCODEAJP13_AUTOFLUSHDETECTION_TICKS > 0 || BonCodeAJP13Settings.BONCODEAJP13_AUTOFLUSHDETECTION_BYTES > 0)) { p_IsFlush = true; } } else { //warning if (p_Logger != null) p_Logger.LogMessage("Received empty user packet in TOMCAT_SENDBODYCHUNK, skipping.", BonCodeAJP13LogLevels.BONCODEAJP13_LOG_DEBUG); } break; case BonCodeAJP13TomcatPacketType.TOMCAT_CFPATHREQUEST: //this is Adobe specific we will need to send back a header p_PacketsReceived.Add(new TomcatPhysicalPathRequest(userData)); requestPath = ((TomcatPhysicalPathRequest)p_PacketsReceived[p_PacketsReceived.Count - 1]).GetFilePath(); adobePath = ""; //this will contain the resolved absolute path //TODO: move the following into a response queue //prep response and return now CF will ask for two paths one for index.htm one for the actual URI //The user did not ask for index.htm it is how CF marks docroot vs final path if (requestPath == "/index.htm") { adobePath = BonCodeAJP13Settings.BonCodeAjp13_DocRoot + "index.htm"; } else { //if we get bogus requests to paths that don't exist or have fake data this will error. Adobe CF just appends the request to doc root when error. We will do the same. try { adobePath = ServerPath(requestPath); //System.Web.HttpContext.Current.Server.MapPath("/yeah") ;//BonCodeAJP13Settings.BonCodeAjp13_PhysicalFilePath; } catch (Exception e) { //if (p_Logger != null) p_Logger.LogException(e, "Problem determining absolute path [" + adobePath + "] for provided relative path: [" + requestPath + "]. Please ensure that provided path is a relative path and there is a virtual mapping and you have spelled correctly."); if (p_Logger != null) p_Logger.LogMessageAndType("Problem determining absolute path [" + adobePath + "] for provided relative path: [" + requestPath + "]. Please ensure that provided path is a relative path and there is a virtual mapping and you have spelled correctly.", "warning", BonCodeAJP13LogLevels.BONCODEAJP13_LOG_BASIC); adobePath = BonCodeAJP13Settings.BonCodeAjp13_DocRoot + requestPath; } }; //build a response package BonCodeFilePathPacket pathResponse = null; pathResponse = new BonCodeFilePathPacket(adobePath); p_NetworkStream.Write(pathResponse.GetDataBytes(), 0, pathResponse.PacketLength); if (p_Logger != null) p_Logger.LogPacket(pathResponse); delayWriteIndicator = true; //prevent main process from writing to network stream break; default: //we don't know this type of package; add to collection anyway and log it, we will not raise error but continue processing p_PacketsReceived.Add(new TomcatReturn(userData)); if (p_Logger != null) { p_Logger.LogMessage("Unknown Packet Type Received, see next log entry:", BonCodeAJP13LogLevels.BONCODEAJP13_LOG_ERRORS); p_Logger.LogPacket(p_PacketsReceived[p_PacketsReceived.Count - 1], true); }; break; } //Log packets Received. Whether the packet will actually be logged depends on log level chosen. if (p_Logger != null) p_Logger.LogPacket(p_PacketsReceived[p_PacketsReceived.Count - 1]); //reset new iStart iStart = iStart + 4 + packetLength - 1; //detect end package if (packetType == BonCodeAJP13TomcatPacketType.TOMCAT_ENDRESPONSE) { p_IsLastPacket = true; p_IsFlush = false; } else { //old flush check position /* //check whether we need monitor for tomcat flush signs if (BonCodeAJP13Settings.BONCODEAJP13_AUTOFLUSHDETECTION_TICKS > 0) { long elapsedTicks = p_StopWatch.ElapsedTicks; p_TickDelta = elapsedTicks - p_LastTick; p_LastTick = elapsedTicks; if (p_TickDelta > BonCodeAJP13Settings.BONCODEAJP13_AUTOFLUSHDETECTION_TICKS) { //flush has been detected set the flag. We should flush after this receiveBuffer has been processed. //no flush is needed if we see end marker during receiveBuffer processing p_IsFlush = true; } } */ } } else { //we need to read more data before we can process. For now mark these bytes as unanalyzed and return to stream reader unalyzedBytes = new byte[receiveBuffer.Length - iStart]; Array.Copy(receiveBuffer, iStart, unalyzedBytes, 0, receiveBuffer.Length - iStart); //set breakout conditions iStart = iStart + packetLength - 1; break; } } } //flush skip check if (skipFlush) { p_IsFlush = false; } //flush processing if (p_IsFlush) { //do what is needed to flush data so far ProcessFlush(); //reset flush marker p_IsFlush = false; } return unalyzedBytes; }