private void WritePacket(byte method,
string protocol,
string req_uri,
string remote_addr,
string remote_host,
string server_name,
ushort server_port,
bool is_ssl,
int num_headers,
NameValueCollection httpHeaders,
String realPathInfo ="",
int sourcePort=0,
String vDirs="")
{
//locals
int pos = 0;
byte attributeByte = 0x00;
byte[] aUserData = new byte[BonCodeAJP13Settings.MAX_BONCODEAJP13_PACKET_LENGTH]; //allocate full number of bytes for processing
int packetFillBytes = 14; //bytes used to complete package
int expectedPacketSize = 0;
string keyName = "";
string keyValue = "";
NameValueCollection goodHeaders = CheckHeaders(httpHeaders); //determine headers to be transferred
num_headers = goodHeaders.AllKeys.Length;
PopulateRawHeaders(httpHeaders["ALL_RAW"]); //we use this to do retranslate the spelling (case) of header names
//populate log values
if (BonCodeAJP13Settings.BONCODEAJP13_LOG_LEVEL >= BonCodeAJP13LogLevels.BONCODEAJP13_LOG_HEADERS)
{
p_Method = BonCodeAJP13PacketHeaders.GetMethodString(method); //not using: GetKeyValue(httpHeaders, "REQUEST_METHOD");
p_Url = req_uri;
p_HttpHeaders = goodHeaders;
}
//add optional headers and reset count
NameValueCollection addlHeaders = new NameValueCollection();
if (BonCodeAJP13Settings.BONCODEAJP13_HEADER_SUPPORT) // "X-Tomcat-DocRoot";
{
addlHeaders.Add("x-tomcat-docroot", BonCodeAJP13Settings.BonCodeAjp13_DocRoot); // System.Web.HttpContext.Current.Server.MapPath("~"); alternatly we could use "appl-physical-path" http var
if (vDirs.Length > 3)
{
addlHeaders.Add("x-vdirs", vDirs);
}
//instance id
addlHeaders.Add("x-webserver-context", "W3SVC" + httpHeaders["INSTANCE_ID"]);
//if we have a shared key send it
if (BonCodeAJP13Settings.BONCODE_MODCFML_SECRET.Length > 0) {
addlHeaders.Add("X-ModCFML-SharedKey", BonCodeAJP13Settings.BONCODE_MODCFML_SECRET);
}
}
//path info alternate header determination
if (BonCodeAJP13Settings.BONCODEAJP13_PATHINFO_HEADER != "") // "xajp-path-info";
{
addlHeaders.Add(BonCodeAJP13Settings.BONCODEAJP13_PATHINFO_HEADER, realPathInfo); // httpHeaders["PATH_INFO"]
}
//determine client fingerprint based on HTTP information
if (BonCodeAJP13Settings.BONCODEAJP13_ENABLE_CLIENTFINGERPRINT)
{
addlHeaders.Add("xajp-clientfingerprint", GetFingerprint(httpHeaders));
}
//during debug logging also add thread id to headers
if (BonCodeAJP13Settings.BONCODEAJP13_LOG_LEVEL == BonCodeAJP13LogLevels.BONCODEAJP13_LOG_DEBUG) // debug test threadid
{
addlHeaders.Add("xajp-managedthreadid", "" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}
//reset count of headers
num_headers += addlHeaders.Count;
//add a mapping prefix if one is provided unless the same prefix is already on the start of Uri (case sensitive comparison)
if (BonCodeAJP13Settings.BONCODEAJP13_PATH_PREFIX.Length > 2
&& !BonCodeAJP13Settings.BONCODEAJP13_PATH_PREFIX.Equals(req_uri.Substring(0, BonCodeAJP13Settings.BONCODEAJP13_PATH_PREFIX.Length - 1), StringComparison.Ordinal))
{
req_uri = BonCodeAJP13Settings.BONCODEAJP13_PATH_PREFIX + req_uri;
}
//write start of a packet
// ============================================================
pos = SetByte(aUserData, BonCodeAJP13ServerPacketType.SERVER_FORWARD_REQUEST, pos); // all have to start with this
pos = SetByte(aUserData, method, pos); //method: e.g. we have clicked on URL
pos = SetString(aUserData, protocol, pos); //protocol
pos = SetString(aUserData, req_uri, pos); //uri any call to SetString will UTF8 encode by default
pos = SetString(aUserData, remote_addr, pos); //remote addr
pos = SetString(aUserData, remote_host, pos); //remote host
pos = SetString(aUserData, server_name, pos); //server name
pos = SetInt16(aUserData, server_port, pos); //port
pos = SetByte(aUserData, Convert.ToByte(is_ssl), pos); //is ssl
pos = SetInt16(aUserData, System.Convert.ToUInt16(num_headers), pos); //number of headers
//pos = SetInt16(aUserData, System.Convert.ToUInt16(goodHeaders.AllKeys.Length), pos); //number of headers
//iterate through headers and add to packet
//first write all additional headers
foreach (String key in addlHeaders)
{
pos = SetString(aUserData, key.ToLower(), pos);
pos = SetString(aUserData, addlHeaders[key], pos);
}
//TODO Remove this
/*
keyName = "xajp-setting-drive";
keyValue = BonCodeAJP13Logger.GetAssemblyDirectory();
pos = SetString(aUserData, keyName.ToLower(), pos);
pos = SetString(aUserData, keyValue, pos);
keyName = "xajp-setting-file";
keyValue = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
pos = SetString(aUserData, keyName.ToLower(), pos);
pos = SetString(aUserData, keyValue, pos);
*/
//END REMOVE THIS
//all other headers
for (int i = 0; i < goodHeaders.AllKeys.Length; i++)
{
keyName = goodHeaders.AllKeys[i];
keyValue = goodHeaders[keyName];
expectedPacketSize = keyName.Length + keyValue.Length + pos + packetFillBytes;
if (expectedPacketSize < BonCodeAJP13Settings.MAX_BONCODEAJP13_PACKET_LENGTH)
{
//add byte or string header name
if (BonCodeAJP13PacketHeaders.GetHeaderBytes(keyName) != null)
{
//byte header
pos = SetSimpleByteArray(aUserData, BonCodeAJP13PacketHeaders.GetHeaderBytes(keyName), pos);
}
else
{
//string header (remove HTTP prefix this is added by IIS) and change underscore
pos = SetString(aUserData, GetCorrectHeaderName(keyName), pos);
}
//add value if keyName is not empty string
pos = SetString(aUserData, keyValue, pos);
}
else
{
//raise error:
throw new Exception("Invalid content length. Last header processed [" + keyName + "]. Please reconfigure BonCode Connector and Apache Tomcat to allow larger transfer packets. Your max allowed content length is " + BonCodeAJP13Settings.MAX_BONCODEAJP13_USERDATA_LENGTH + " bytes. Provided content length would be at least " + expectedPacketSize + " bytes. Clearing cookies may allow you proceed.");
}
}
//add SSL-Cert information to AJP ATTRIBUTES as well since this is how the servlet container accepts them
if (clientCert != null)
{
//This is the only SSL attribute exchanged as byte type all others are explicitly named
//pos = SetByte(aUserData, BonCodeAJP13HTTPAttributes.BONCODEAJP13_SSL_CERT, pos); //attribute marker
//pos = SetString(aUserData, CertExportToPEM(clientCert), pos); //attribute value
//set named AJP Attributes
NameValueCollection addlAtts = new NameValueCollection();
addlAtts.Add("SSL_CLIENTCERT", CertExportToPEM(clientCert));
addlAtts.Add("CERT_ISSUER", clientCert.Issuer);
addlAtts.Add("CERT_SUBJECT", clientCert.Subject);
addlAtts.Add("CERT_COOKIE", httpHeaders["CERT_COOKIE"]);
addlAtts.Add("HTTPS_SERVER_SUBJECT", httpHeaders["CERT_SERVER_SUBJECT"]);
addlAtts.Add("CERT_FLAGS", httpHeaders["CERT_FLAGS"]);
//addlAtts.Add("HTTPS_SECRETKEYSIZE", httpHeaders["CERT_SECRETKEYSIZE"]); // this is done later and extracted from http headers
addlAtts.Add("CERT_SERIALNUMBER", clientCert.GetSerialNumberString());
addlAtts.Add("HTTPS_SERVER_ISSUER", httpHeaders["CERT_SERVER_ISSUER"]);
addlAtts.Add("HTTPS_KEYSIZE", httpHeaders["CERT_KEYSIZE"]);
//now write named attributes
for (int i = 0; i < addlAtts.AllKeys.Length; i++)
{
keyName = addlAtts.AllKeys[i];
keyValue = addlAtts[keyName];
expectedPacketSize = keyName.Length + keyValue.Length + pos + packetFillBytes;
attributeByte = BonCodeAJP13PacketHeaders.GetAttributeByte(keyName);
//check whether this is byte attribute if so wee need to add the header as attribute to packet
if (keyValue != "")
{
if (expectedPacketSize < BonCodeAJP13Settings.MAX_BONCODEAJP13_PACKET_LENGTH)
{
//set either name or byte attribute name
if (attributeByte == 0x00)
{
//set attribute name as string
pos = SetByte(aUserData, BonCodeAJP13HTTPAttributes.BONCODEAJP13_REQ_ATTRIBUTE, pos); //attribute marker
pos = SetString(aUserData, keyName, pos); //attribute name
}
else
{
//set as byte-type
pos = SetByte(aUserData, attributeByte, pos); //attribute marker
}
//set value of attribute
pos = SetString(aUserData, keyValue, pos); //attribute value as string
}
else
{
throw new Exception("Invalid content length. Last attribute processed [" + keyName + "]. Please reconfigure BonCode Connector and Apache Tomcat to allow larger transfer packets. Your max allowed content length is " + BonCodeAJP13Settings.MAX_BONCODEAJP13_USERDATA_LENGTH + " bytes. Provided content length would be at least " + expectedPacketSize + " bytes.");
}
}
}
}
//EXTRACT AND WRITE BYTE TYPE ATTRIBUTES FOLLOW:
//Second iteration through headers Some header values have to be passed as attributes REMOTE_USER, AUTH_TYPE, QUERY_STRING
for (int i = 0; i < httpHeaders.AllKeys.Length; i++)
{
keyName = httpHeaders.AllKeys[i];
keyValue = httpHeaders[keyName];
expectedPacketSize = keyName.Length + keyValue.Length + pos + packetFillBytes;
attributeByte = BonCodeAJP13PacketHeaders.GetAttributeByte(keyName);
//check whether this is byte attribute if so wee need to add the header as attribute to packet
if (attributeByte != 0x00 && keyValue != "")
{
if (expectedPacketSize < BonCodeAJP13Settings.MAX_BONCODEAJP13_PACKET_LENGTH)
{
pos = SetByte(aUserData, attributeByte, pos); //attribute marker
if (attributeByte == 0x0B) //the SSL Key Size attribute is the only one currently that needs to be sent as Uint
{
pos = SetUInt16(aUserData, System.Convert.ToUInt16(keyValue), pos); //attribute value as int (high/low)
}
else
{
pos = SetString(aUserData, keyValue, pos); //attribute value as string
}
}
else
{
throw new Exception("Invalid content length. Last header processed [" + keyName + "]. Please reconfigure BonCode Connector and Apache Tomcat to allow larger transfer packets. Your max allowed content length is " + BonCodeAJP13Settings.MAX_BONCODEAJP13_USERDATA_LENGTH + " bytes. Provided content length would be at least " + expectedPacketSize + " bytes.");
}
}
}
//WRITE NAMED ATTRIBUTES
//add secure session attribute
if (BonCodeAJP13Settings.BONCODEAJP13_FORCE_SECURE_SESSION)
{
pos = SetByte(aUserData, BonCodeAJP13HTTPAttributes.BONCODEAJP13_SSL_SESSION, pos); //attribute marker
pos = SetString(aUserData, "on", pos); //attribute value
}
//add request shared secret key
if (BonCodeAJP13Settings.BONCODEAJP13_REQUEST_SECRET.Length > 0)
{
pos = SetByte(aUserData, BonCodeAJP13HTTPAttributes.BONCODEAJP13_SECRET, pos); //attribute marker
pos = SetString(aUserData, BonCodeAJP13Settings.BONCODEAJP13_REQUEST_SECRET, pos); //attribute value
}
//add constant attribute for AJP13 JVM Route
/*
pos = SetByte(aUserData, BonCodeAJP13HTTPAttributes.BONCODEAJP13_JVM_ROUTE, pos); //attribute marker
pos = SetString(aUserData, BonCodeAJP13Markers.BONCODEAJP13_PROTOCOL_MARKER, pos); //attribute value
*/
//add pathinfo attempt to bypass tomcat bug
/*
pos = SetByte(aUserData, BonCodeAJP13HTTPAttributes.BONCODEAJP13_REQ_ATTRIBUTE, pos); //attribute marker
pos = SetString(aUserData, "path_info", pos); //attribute name
pos = SetString(aUserData, httpHeaders["PATH_INFO"], pos); //attribute value
*/
//START ADOBE MODIFICATIONS
//add Adobe ColdFusion 10 specific attributes, this is backwards since this data is already available, adobe chose to
//transfer again in attributes because of problems with ISAPI constructed connector
//SERVER_SOFTWARE VIA ATTRIBUTES
//pos = SetByte(aUserData, 0x0E, pos); //attribute marker for web server
//pos = SetString(aUserData, httpHeaders["SERVER_SOFTWARE"], pos); //attribute value
//END OF ADOBE MODIFICATIONS
//Remote port marker seems to be a common element transferred in attributes
if (sourcePort > 0)
{
pos = SetByte(aUserData, BonCodeAJP13HTTPAttributes.BONCODEAJP13_REQ_ATTRIBUTE, pos); //attribute marker
pos = SetString(aUserData, "AJP_REMOTE_PORT", pos); //attribute name
pos = SetString(aUserData, sourcePort.ToString(), pos); //attribute value
}
//add packet terminator
pos = SetByte(aUserData, 0xFF, pos); //marks the end of user packet
//assess length of package and type
int pLength = pos; // true length of user data
p_UserDataLength = Convert.ToUInt16(pLength);
//assemble full package now in the final array container of the object
p_ByteStore = new byte[pos + 4]; // this is the true length as we add magic and length bytes
int pos2 = 0;
pos2 = SetByte(p_ByteStore, BonCodeAJP13Markers.BONCODEAJP13_PACKET_START, pos2);
pos2 = SetByte(p_ByteStore, BonCodeAJP13Markers.BONCODEAJP13_PACKET_START2, pos2);
pos2 = SetUInt16(p_ByteStore, p_UserDataLength, pos2);
Array.Copy(aUserData, 0, p_ByteStore, 4, pos); //only copy relevant data values from temporary store
//determine overall packet length
p_PacketLength = p_ByteStore.Length;
}