/// <summary>
 /// put the request into the cache if possible
 /// </summary>
 /// <param name="comms"></param>
 /// <param name="buffer"></param>
 public void ProcessCacheItem(ProxyRequestMessage comms, byte[] buffer)
 {
     int age = CacheAge;
     if (age != 0)
         RequestCache.AddCache(comms.Host, comms.RequestUrl, buffer, age);
 }
        /// <summary>
        ///  thread method to handle http request
        /// </summary>
        /// <param name="stateInfo">the TcpClient from the listener</param>
        private void HandleAsyncConnection(object stateInfo)
        {
            BabaluCounters.DecrementPendingThread();

            // initialize log information class
            LogRequest log = new LogRequest();

            Guid? activity = null;
            try
            {
                // increment the gateway call count
                activity = BabaluCounters.IncrementAllRequest();

                using (TcpClient realClient = stateInfo as TcpClient)
                {
                    // get client information for logging
                    IPEndPoint localIp = realClient.Client.LocalEndPoint as IPEndPoint;
                    if (localIp != null)
                        log.ServerPort = localIp.Port.ToString();
                    IPEndPoint remoteIp = realClient.Client.RemoteEndPoint as IPEndPoint;
                    if (remoteIp != null)
                        log.ClientIp = remoteIp.Address.ToString();

                    // get client stream
                    using (NetworkStream realClientStream = realClient.GetStream())
                    {
                        // get specific implementation of client stream
                        using (Stream realClientStreamImpl = GetRealClientStream(realClientStream))
                        {
                            // process the client stream
                            IExternalMessageHandler messageHandler = ExtensionConfig.BabaluExtension.MessageHandler(_proxiedServer.ServerType);
                            ProxyRequestMessage request = new ProxyRequestMessage(messageHandler, _proxiedServer.SupportGZip, realClientStreamImpl, log);

                            if (messageHandler.OverrideResponseFromRequest(log, request.UserName, request.UserAgent))
                            {
                                realClientStreamImpl.Write(messageHandler.ResponseBuffer, 0, messageHandler.ResponseBuffer.Length);
                                log.ScStatus = messageHandler.ResponseCode;
                                log.ScSubstatus = "0";
                            }
                            else if (request.HasData && _proxiedServer.ProxiedServers.ContainsKey(request.Host.ToLower()))
                            {
                                Tuple<string, int, bool> proxied = _proxiedServer.ProxiedServers[request.Host.ToLower()];
                                string proxiedServer = proxied.Item1;
                                int proxiedPort = proxied.Item2;
                                bool proxiedSsl = proxied.Item3;

                                // see if this request is cached on the server
                                byte[] buffer = (_proxiedServer.CacheContent ? RequestCache.GetCache(request.Host, request.RequestUrl) : null);

                                if (buffer != null)
                                {
                                    // write out cache result, no need to ask proxied server for data
                                    realClientStreamImpl.Write(buffer, 0, buffer.Length);
                                    log.ScStatus = "200";
                                    log.ScSubstatus = "0";

                                    LogFactory.LogDebug("Cache hit {0}", request.RequestUrl);
                                    log.BabaluStatus = "Cache";
                                }
                                else
                                {
                                    // create a connection to the proxied server and pass client request to that server
                                    using (TcpClient proxyClient = new TcpClient(proxiedServer, proxiedPort))
                                    {
                                        // change all ip/dns information from proxy server to proxied server
                                        byte[] data = request.Tranform(request.Host, proxiedServer);

                                        // get proxied client stream
                                        using (NetworkStream proxyClientStream = proxyClient.GetStream())
                                        {
                                            // get specific implementation of proxied client stream
                                            using (Stream proxyClientImpl = GetProxyClientStream(proxyClientStream, proxiedServer, proxiedSsl))
                                            {
                                                // Send the message to the connected proxied server
                                                proxyClientImpl.Write(data, 0, data.Length);

                                                // read the response from the proxied server
                                                ProxyResponseMessage response = new ProxyResponseMessage(messageHandler, _proxiedServer.SupportGZip, proxyClientImpl, log);
                                                if (response.HasData)
                                                {
                                                    if ( messageHandler.OverrideResponseFromResponse(response, request.UserName))
                                                    {
                                                        realClientStreamImpl.Write(messageHandler.ResponseBuffer, 0, messageHandler.ResponseBuffer.Length);
                                                        log.ScStatus = messageHandler.ResponseCode;
                                                        log.ScSubstatus = "0";

                                                        LogFactory.LogInformation("Response Overridden from Response: {0} User: {1}", log.ScStatus, request.UserName);
                                                    }
                                                    else
                                                    {
                                                        // change all ip/dns information from proxied server to proxy server - if provisional and it is a sync command special tranform processing
                                                        buffer = response.Tranform(proxiedServer, request.Host);
                                                        // write response back to the original client
                                                        realClientStreamImpl.Write(buffer, 0, buffer.Length);

                                                        // add request to server cache if possible
                                                        if (_proxiedServer.CacheContent)
                                                            response.ProcessCacheItem(request, buffer);
                                                    }
                                                }
                                                else
                                                    LogFactory.LogDebug("response has no data");

                                                ProxyMessage.RawLog(  request, response );
                                            }
                                        }
                                    }
                                }
                            }
                            else
                                LogFactory.LogDebug("request has no data");
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                LogFactory.LogException(excp, "Processing to Request: {0}", log);
                log.ScSubstatus = "-1";
                BabaluCounters.IncrementException();
            }
            finally
            {
                LogFactory.LogRequest(_proxiedServer.ProxyIP, log);
                BabaluCounters.DecrementAllRequest(activity);
            }
        }