private RedirectType DetermineRedirectType(RequestObj pRequestObj)
        {
            String lRedirectHeader = String.Empty;

            try { lRedirectHeader = pRequestObj.ServerResponseHeaders.FirstOrDefault(hdr => hdr.Item1.ToLower().Contains("location")).Item2; } catch (Exception) {}
            Boolean lHasRedirectHeader = String.IsNullOrEmpty(lRedirectHeader) ? false : true;
            Uri     lTmpUri            = lHasRedirectHeader ? new Uri(lRedirectHeader) : null;

            String lRequestScheme  = pRequestObj.Scheme;
            String lRequestURL     = String.Format("{0}{1}", pRequestObj.Host, pRequestObj.Path);
            String lRedirectURL    = lHasRedirectHeader ? (String.Format("{0}{1}", lTmpUri.Host, lTmpUri.PathAndQuery)) : String.Empty;
            String lRedirectScheme = lHasRedirectHeader ? lTmpUri.Scheme.ToLower() : String.Empty;

            Logging.LogMessage(String.Format("HTTPClientRequest.DetermineRedirectType() : \"{0}://{1}\" -> Redirected:{2} to \"{3}://{4}\"", lRequestScheme, lRequestURL, lHasRedirectHeader, lRedirectScheme, lRedirectURL), Logging.Level.DEBUG, pRequestObj.Counter);

            if (lRequestScheme == "http" && lHasRedirectHeader == false)
            {
                return(RedirectType.Http2http2XX);
            }
            else if (lRequestScheme == "http" && lHasRedirectHeader == true && lRedirectScheme == "http")
            {
                return(RedirectType.Http2Http3XX);
            }
            else if (lRequestScheme == "http" && lHasRedirectHeader == true && lRedirectScheme == "https" && lRequestURL != lRedirectURL)
            {
                return(RedirectType.Http2Https3XXDifferentURL);
            }
            else if (lRequestScheme == "http" && lHasRedirectHeader == true && lRedirectScheme == "https" && lRequestURL == lRedirectURL)
            {
                return(RedirectType.Http2Https3XXSameURL);
            }

            else if (lRequestScheme == "https" && lHasRedirectHeader == false)
            {
                return(RedirectType.Https2Http2XX);
            }
            else if (lRequestScheme == "https" && lHasRedirectHeader == true && lRedirectScheme == "https" && lRequestURL != lRedirectURL)
            {
                return(RedirectType.Https2Https3XXDifferentURL);
            }
            else if (lRequestScheme == "https" && lHasRedirectHeader == true && lRedirectScheme == "https" && lRequestURL == lRedirectURL)
            {
                return(RedirectType.Https2Https3XXSameURL);
            }

            else
            {
                return(RedirectType.Error);
            }
        }
        /*
         *
         *
         */
        private void SendRequest2RedirectLocation(RequestObj pRequestObj)
        {
            String lRedirectLocationHTTPS = pRequestObj.ServerWebResponse.GetResponseHeader("Location");
            String lRedirectLocationHTTP  = pRequestObj.getRequestedURL();

            try { RedirectCache.Instance.addElement(lRedirectLocationHTTP, lRedirectLocationHTTPS); } catch { }

            Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Http2Https3XXSameURL \"{0}\" -> \"{1}\"", lRedirectLocationHTTP, lRedirectLocationHTTPS), Logging.Level.DEBUG, pRequestObj.Counter);


            // Close the preceding WebResponse (stream & headers)
            pRequestObj.ServerResponseHeaders.Clear();

            if (pRequestObj.ServerWebResponse != null)
            {
                pRequestObj.ServerWebResponse.Close();
            }

            RequestObj lTmpReqObj = (RequestObj)pRequestObj.Clone();
            Uri        lTmpUri    = new Uri(lRedirectLocationHTTPS);

            lTmpReqObj.Scheme = lTmpUri.Scheme;
            lTmpReqObj.Host   = lTmpUri.Host;
            lTmpReqObj.Path   = lTmpUri.PathAndQuery;
            if (lTmpReqObj.ClientRequestHeaders.ContainsKey("host"))
            {
                lTmpReqObj.ClientRequestHeaders.Remove("host");
                lTmpReqObj.ClientRequestHeaders.Add("host", lTmpReqObj.Host);
            }
            lTmpReqObj.Counter++;


            this.DoHttpProcessing(lTmpReqObj);

            pRequestObj.ServerWebResponse     = lTmpReqObj.ServerWebResponse;
            pRequestObj.ServerResponseHeaders = lTmpReqObj.ServerResponseHeaders;
        }
Пример #3
0
        /*
         *
         *
         */
        private void ProcessServerResponseHeaders(RequestObj pRequestObj)
        {
            String lValue = null;
            String header = null;

            pRequestObj.ServerResponseHeaders.Clear();

            foreach (String lTmp in pRequestObj.ServerWebResponse.Headers.Keys)
            {
                if (lTmp.ToLower() == "set-cookie")
                {
                    header = lTmp;
                    lValue = pRequestObj.ServerWebResponse.Headers[lTmp];
                }
                else if (lTmp.ToLower() == "strict-transport-security" && Config.IgnoreHSTS)
                {
                    Logging.LogMessage(String.Format("HTTPAccounts.ProcessServerResponseHeaders() : Strict-Transport-Security header removed"), Logging.Level.INFO, pRequestObj.Counter);
                    HSTSCache.Instance.addElement(pRequestObj.Host);
                }
                else
                {
                    pRequestObj.ServerResponseHeaders.Add(new Tuple <String, String>(lTmp, pRequestObj.ServerWebResponse.Headers[lTmp]));
                }
            } // foreach (St...


            if (!String.IsNullOrWhiteSpace(lValue))
            {
                pRequestObj.ServerWebResponse.Headers.Remove(header);
                String[] lCookies = cCookieSplitRegEx.Split(lValue);

                foreach (String lCookie in lCookies)
                {
                    pRequestObj.ServerResponseHeaders.Add(new Tuple <String, String>("Set-Cookie", lCookie));
                }
            } // if (!Strin...
        }
        /*
         *
         *
         */
        private void ReadRequestHeadersFromClient(RequestObj pRequestObj)
        {
            String lHTTPHeader;
            int    lContentLen = 0;


            do
            {
                lHTTPHeader = pRequestObj.ClientStreamReader.ReadLine();

                if (String.IsNullOrEmpty(lHTTPHeader))
                {
                    break;
                }

                String[] lHeader = lHTTPHeader.Split(new string[] { ": " }, 2, StringSplitOptions.None);
                Logging.LogMessage(String.Format("HTTPClientRequest.ReadRequestHeadersFromClient() : {0}: {1}", lHeader[0], lHeader[1]), Logging.Level.DEBUG, pRequestObj.Counter);


                switch (lHeader[0].ToLower())
                {
                case "host":
                    pRequestObj.ClientRequestHeaders.Add("host", lHeader[1]);
                    break;

                case "user-agent":
                    pRequestObj.ClientRequestHeaders.Add("user-agent", lHeader[1]);
                    break;

                case "accept":
                    pRequestObj.ClientRequestHeaders.Add("accept", lHeader[1]);
                    break;

                case "referer":
                    pRequestObj.ClientRequestHeaders.Add("referer", lHeader[1]);
                    break;

                case "cookie":
                    pRequestObj.ClientRequestHeaders.Add("cookie", lHeader[1]);
                    break;

                case "proxy-connection":
                case "connection":
                case "keep-alive":
                    //ignore these
                    break;

                case "content-length":
                    int.TryParse(lHeader[1], out lContentLen);
                    pRequestObj.ClientRequestContentLen = lContentLen;
                    pRequestObj.ClientRequestHeaders.Add("content-length", lHeader[1]);
                    break;

                case "content-type":
                    pRequestObj.ClientRequestHeaders.Add("content-type", lHeader[1]);
                    break;

                case "if-modified-since":
                    String[] sb = lHeader[1].Trim().Split(new char[] { ';' });
                    DateTime d;
                    if (DateTime.TryParse(sb[0], out d))
                    {
                        pRequestObj.ClientRequestHeaders.Add("if-modified-since", lHeader[1]);
                    }
                    break;

                default:
                    try
                    {
                        pRequestObj.ClientRequestHeaders.Add(lHeader[0], lHeader[1]);
                    }
                    catch (Exception lEx)
                    {
                        Logging.LogMessage(String.Format("HTTPClientRequest.ReadRequestHeadersFromClient(EXCEPTION) : {0}", lEx.Message), Logging.Level.ERROR, pRequestObj.Counter);
                    }
                    break;
                } // switch (....
            }while (!String.IsNullOrWhiteSpace(lHTTPHeader));
        }
        /*
         *
         *
         */
        public void HandleClientRequest(RequestObj pRequestObj)
        {
            String lHTTPRequestString = pRequestObj.ClientStreamReader.ReadLine();

            if (String.IsNullOrEmpty(lHTTPRequestString))
            {
                throw new Exception("Client request stream corrupted.");
            }

            // Read the request headers from the client and copy them to the request settings
            // Set values : METHOD scheme://host/Path
            Logging.LogMessage(String.Format("HTTPClientRequest.HandleClientRequest() : HTTP Request string: \"{0}\"", lHTTPRequestString), Logging.Level.DEBUG, pRequestObj.Counter);
            pRequestObj.parseRequestString(lHTTPRequestString);
            this.ReadRequestHeadersFromClient(pRequestObj);

            pRequestObj.Host   = pRequestObj.ClientRequestHeaders["host"].ToString();
            pRequestObj.Scheme = "http";


            /*
             * Verify if request parameters are correct.
             */
            if (!Regex.Match(pRequestObj.Method.ToLower(), @"^\s*(get|put|post|head|delete|trace|options|connect)\s*$").Success)
            {
                throw new WebException("Client request contains an unsupproted request method");
            }


            String lRequestedURL = String.Format("{0}://{1}{2}", pRequestObj.Scheme, pRequestObj.Host, pRequestObj.Path);



            /*
             *   If HTTP request was redirected to an other URL in a previous request
             *   replace current request with the redirect location
             */
            if (RedirectCache.Instance.NeedsRequestBeMapped(lRequestedURL))
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.HandleClientRequest() : REDIRECT(301/302) from \"{0}\" to \"{1}\"", lRequestedURL, RedirectCache.Instance.GetElement(lRequestedURL).URL), Logging.Level.INFO, pRequestObj.Counter);

                // DO SSL STRIPPING THINGS HERE !!!!
                // Replace the URL by the URL saved in the cache ...
                RedirectHost lTmpHost = RedirectCache.Instance.GetElement(pRequestObj.getRequestedURL());

                pRequestObj.Method = "GET";
                pRequestObj.Scheme = lTmpHost.Scheme;
                pRequestObj.Host   = lTmpHost.Host;
                pRequestObj.Path   = lTmpHost.Path;

                lTmpHost.IncCounter();
            } // if (RedirectCac...


            /*
             * If HTTP request was answered with an HSTS server response header
             * conduct an HTTPS request instead of HTTP
             */
            else if (HSTSCache.Instance.GetElement(pRequestObj.Host) != null)
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.HandleClientRequest() : HSTS protocol replacement : http://{0} -> https://{0} \n", pRequestObj.Host), Logging.Level.DEBUG, pRequestObj.Counter);
                pRequestObj.Scheme = "https";
            } // if (HSTSCache...


            try
            {
                /*
                 * Forward request according to the URL defined
                 * in the command line parameter.
                 */
                if (!String.IsNullOrEmpty(Config.RedirectToURL) && pRequestObj.Method.ToLower() == "get")
                {
                    HTTPRedirect.getInstance().processRequest(pRequestObj.ClientStream, Config.RedirectToURL, pRequestObj.ClientRequestHeaders);
                }
                else
                {
                    this.DoHttpProcessing(pRequestObj);
                }
            }
            catch (WebException lEx)
            {
                /*
                 * 1. Sending server response
                 */
                var lResponse = lEx.Response as HttpWebResponse;
                if (lResponse != null && lResponse.StatusCode != HttpStatusCode.OK)
                {
                    String ErrorCode = String.Format("HTTP/{0} {1} {2}\n", lResponse.ProtocolVersion, (int)lResponse.StatusCode, lResponse.StatusDescription);
                    pRequestObj.ClientStream.Write(Encoding.ASCII.GetBytes(ErrorCode), 0, ErrorCode.Length);
                }
                else
                {
                    String ErrorCode = String.Format("HTTP/1.1 500 Internal server error\n");
                    pRequestObj.ClientStream.Write(Encoding.ASCII.GetBytes(ErrorCode), 0, ErrorCode.Length);
                } // if (lRespon...

                /*
                 * 2. Sending server response headers
                 */
                if (lEx.Response != null && lEx.Response.Headers != null && lEx.Response.Headers.Count > 0)
                {
                    foreach (String la in lEx.Response.Headers.AllKeys)
                    {
                        String lResp = String.Format("{0}: {1}\n", la, lEx.Response.Headers[la]);
                        pRequestObj.ClientStream.Write(Encoding.ASCII.GetBytes(lResp), 0, lResp.Length);
                    } // foreach (Stri...
                }     // if (lEx.Resp ...

                pRequestObj.ClientStream.Write(Encoding.ASCII.GetBytes("\n"), 0, 1);

                /*
                 * 3. Sending server response body
                 */
                try
                {
                    var resp = new StreamReader(lEx.Response.GetResponseStream()).ReadToEnd();
                    pRequestObj.ClientStream.Write(Encoding.ASCII.GetBytes(resp), 0, resp.Length);
                }
                catch (Exception lEx2)
                {
                    Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing(EXCEPTION2) : {0} -> {1} \n{2}", pRequestObj.getRequestedURL(), lEx.Message, lEx.StackTrace), Logging.Level.ERROR, pRequestObj.Counter);
                }
            }
            catch (Exception lEx)
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing(EXCEPTION) : {0} -> {1} \n{2}", pRequestObj.getRequestedURL(), lEx.Message, lEx.StackTrace), Logging.Level.ERROR, pRequestObj.Counter);
            }
            finally
            {
                if (pRequestObj.ClientStreamReader != null)
                {
                    pRequestObj.ClientStreamReader.Close();
                }

                if (pRequestObj.ClientStream != null)
                {
                    pRequestObj.ClientStream.Close();
                }

                if (pRequestObj.ServerWebResponse != null)
                {
                    pRequestObj.ServerWebResponse.Close();
                }
            }
        }
        /*
         *
         *
         */
        public void DoHttpProcessing(RequestObj pRequestObj)
        {
            String lHTTPRequestString = String.Empty;

            Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : Client {0} requested URL : \"{1}\"", pRequestObj.SrcIP, pRequestObj.getRequestedURL()), Logging.Level.INFO, pRequestObj.Counter);


            /*
             * Process HTTP request.
             * 1. Detect HTTP Redirect requests
             * 2. Cache new HTTP Redirect locations
             * 3. Recognize incoming client requests that need to be SSL-Stripped
             * 4. Process reqular HTTP requests
             *
             *
             *
             * 1. Client requests a SSL-Stripping page found in the RedirectCache
             *    The requested URL previously was detected as a "HTTP 301/302 Redirect" to a SSL/TLS protected web site.
             *    Skip the HTTP/Redirect part and directly proxy the data from the SSL/TLS protected website to the user.
             *
             *    Format : SCHEME://HOST
             */



            // 2. Send client request URL to server and parse response headers
            pRequestObj.ServerResponseHeaders.Clear();
            cServerRequestHandler.sendRequestAndParseServerResponseHeader(pRequestObj);

            RedirectType lRedirType = this.DetermineRedirectType(pRequestObj);



            /*
             * The HTTP client request triggers a regular HTML data response.
             * 1. Transfer the server response (Server response string, headers, data)
             */
            if (lRedirType == RedirectType.Http2http2XX)
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Http2http2XX \"{0}\" -> \"-\"", pRequestObj.getRequestedURL()), Logging.Level.DEBUG, pRequestObj.Counter);


                /*
                 * The HTTP client request triggers a request to a HTTP URL
                 * 1. Transfer the server response (Server response string, headers, data)
                 */
            }
            else if (lRedirType == RedirectType.Http2Http3XX)
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Http2Http3XX \"{0}\" -> \"{1}\"", pRequestObj.getRequestedURL(), pRequestObj.ServerWebResponse.GetResponseHeader("Location")), Logging.Level.DEBUG, pRequestObj.Counter);


                /*
                 * The HTTP client request triggers a request to a HTTP URL
                 * 1. Cache the HTTP/HTTPS mapping
                 * 2. Replace the "https" scheme in the redirect location by "http"
                 * 3. Transfer the server response (Server response string, headers, data)
                 */
            }
            else if (lRedirType == RedirectType.Http2Https3XXDifferentURL)
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Http2Http3XXDifferentURL \"{0}\" -> \"{1}\"", pRequestObj.getRequestedURL(), pRequestObj.ServerWebResponse.GetResponseHeader("Location")), Logging.Level.DEBUG, pRequestObj.Counter);
                this.SendRequest2RedirectLocation(pRequestObj);



                /*
                 * 1. Resend the same request again to the same URL but with "https" scheme instead of "http"
                 * 2. Transfer the server response (Server response string, headers, data)
                 */
            }
            else if (lRedirType == RedirectType.Http2Https3XXSameURL)
            {
                // Save redirect information in cache

                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Http2Https3XXSameURL \"{0}\" -> \"{1}\"", pRequestObj.getRequestedURL(), pRequestObj.ServerWebResponse.GetResponseHeader("Location")), Logging.Level.DEBUG, pRequestObj.Counter);
                this.SendRequest2RedirectLocation(pRequestObj);


                /*
                 * The HTTP client request triggers a regular HTML data response.
                 * 1. Transfer the server response (Server response string, headers, data)
                 */
            }
            else if (lRedirType == RedirectType.Https2Http2XX)
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Https2Http2XX"), Logging.Level.DEBUG, pRequestObj.Counter);



                /*
                 * This should never happen!!
                 * We're lost in an endless loop!
                 */
            }
            else if (lRedirType == RedirectType.Https2Https3XXSameURL)
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Https2HttpsRedirectSameURL\n\n\n\nHOOOOONK\n\n\n"), Logging.Level.DEBUG, pRequestObj.Counter);

                String lLogData = String.Format("HTTPClientRequest.DoHttpProcessing() : \"{0}\" -> \"{1}\"", pRequestObj.getRequestedURL(), pRequestObj.ServerResponseHeaders.Find(item => item.Item1 == "Location"));

                Logging.LogMessage(lLogData, Logging.Level.DEBUG);
            }
            else if (lRedirType == RedirectType.Https2Https3XXDifferentURL)
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Https2HttpsRedirectDiffrentURL"), Logging.Level.DEBUG, pRequestObj.Counter);

                /*
                 * The HTTP client request triggers a request to a HTTP URL
                 * 1. Cache the HTTP/HTTPS mapping
                 * 2. Replace the "https" scheme in the redirect location by "http"
                 * 3. Transfer the server response (Server response string, headers, data)
                 */
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE Https2Https3XXDifferentURL \"{0}\" -> \"{1}\"", pRequestObj.getRequestedURL(), pRequestObj.ServerWebResponse.GetResponseHeader("Location")), Logging.Level.DEBUG, pRequestObj.Counter);
                this.SendRequest2RedirectLocation(pRequestObj);


                /*
                 * This should never happen!!
                 * No clue what to do at this point!
                 */
            }
            else
            {
                Logging.LogMessage(String.Format("HTTPClientRequest.DoHttpProcessing() : TYPE definition error for URL \"{0}\" ", pRequestObj.getRequestedURL()), Logging.Level.DEBUG, pRequestObj.Counter);
            }

            cServerRequestHandler.sendServerResponse2Client(pRequestObj);

            String lPipeData = lPipeData = String.Format("HTTPClientRequest.DoHttpProcessing() : TCP||{0}||{1}||{2}||{3}||{4}||{5}\r\n", pRequestObj.SrcMAC, pRequestObj.SrcIP, pRequestObj.SrcPort, Config.RemoteHostIP, Config.RemoteHostPort, pRequestObj.HTTPLogData);

            Program.WriteToPipe(lPipeData);
        }
Пример #7
0
        /*
         *
         *
         */
        public void sendRequestAndParseServerResponseHeader(RequestObj pRequestObj)
        {
            char[]       lPostBuffer;
            int          lPOSTBytesRead  = 0;
            int          lTotalBytesRead = 0;
            StreamWriter lSW             = null;
            String       lTmpStr         = String.Empty;
            String       lTmpBuf         = String.Empty;
            String       lPOSTData       = String.Empty;

            Logging.LogMessage(String.Format("HTTPClientRequest.sendRequestAndParseServerResponseHeader() : Requesting URL \"{0}\"", pRequestObj.getRequestedURL()), Logging.Level.DEBUG, pRequestObj.Counter);


            /*
             * Setup the http request to send on behalf of the actual client.
             * Neutralize the server certificate validation.
             */
            ServicePointManager.ServerCertificateValidationCallback = delegate { return(true); };

            pRequestObj.ServerWebRequest                        = (HttpWebRequest)HttpWebRequest.Create(pRequestObj.getRequestedURL());
            pRequestObj.ServerWebRequest.Method                 = pRequestObj.Method;
            pRequestObj.ServerWebRequest.ProtocolVersion        = System.Net.HttpVersion.Version10;
            pRequestObj.ServerWebRequest.Timeout                = 10000;
            pRequestObj.ServerWebRequest.Proxy                  = null;
            pRequestObj.ServerWebRequest.KeepAlive              = false;
            pRequestObj.ServerWebRequest.AllowAutoRedirect      = false;
            pRequestObj.ServerWebRequest.AutomaticDecompression = DecompressionMethods.None;

            this.SetClientRequestHTTPHeaders(pRequestObj.ClientRequestHeaders, ref pRequestObj.ServerWebRequest);



            /*
             * Send POST data to remote server
             */
            if (pRequestObj.Method.ToUpper() == "POST")
            {
                lPostBuffer     = new char[pRequestObj.ClientRequestContentLen];
                lTotalBytesRead = 0;
                lSW             = new StreamWriter(pRequestObj.ServerWebRequest.GetRequestStream());

                while (lTotalBytesRead < pRequestObj.ClientRequestContentLen && (lPOSTBytesRead = pRequestObj.ClientStreamReader.ReadBlock(lPostBuffer, 0, pRequestObj.ClientRequestContentLen)) > 0)
                {
                    lTmpStr = new string(lPostBuffer);

                    lTotalBytesRead += lPOSTBytesRead;
                    lSW.Write(lPostBuffer, 0, lPOSTBytesRead);

                    lTmpBuf += lTmpStr;
                } // while (lTotalBytes...

                if (lSW != null)
                {
                    lSW.Close();
                }

                if (lTmpBuf != null && lTmpBuf.Length > 0)
                {
                    lPOSTData = lTmpBuf.ToString();
                }
            } // if (lMethod.To...


            // Read and parse server response headers
            // Build HTTP request data string

            pRequestObj.ServerWebResponse = (HttpWebResponse)pRequestObj.ServerWebRequest.GetResponse();
            this.ProcessServerResponseHeaders(pRequestObj);

            // Create Data log string
            pRequestObj.HTTPLogData = String.Empty;
            foreach (String lKey in pRequestObj.ServerWebResponse.Headers.AllKeys)
            {
                pRequestObj.HTTPLogData += String.Format("..{0}: {1}", lKey, pRequestObj.ServerWebRequest.Headers[lKey]);
            }

            pRequestObj.HTTPLogData += String.Format("....{0}", lPOSTData);
        }
Пример #8
0
        /*
         *
         *
         */
        public void sendServerResponse2Client(RequestObj pRequestObj)
        {
            StreamWriter lMyResponseWriter = null;
            Stream       lResponseStream   = null;

            Byte[] lBuffer;
            int    lBytesRead = 0;


            try
            {
                lMyResponseWriter = new StreamWriter(pRequestObj.ClientStream);
                lResponseStream   = pRequestObj.ServerWebResponse.GetResponseStream();

                /*
                 * 1. Send "server response string" to client
                 */
                String lOut          = String.Format("HTTP/1.0 {0} {1}\n", (Int32)pRequestObj.ServerWebResponse.StatusCode, pRequestObj.ServerWebResponse.StatusDescription);
                byte[] lOutByteArray = Encoding.ASCII.GetBytes(lOut);
                pRequestObj.ClientStream.Write(lOutByteArray, 0, lOutByteArray.Length);
                Logging.LogMessage(String.Format("HTTPAccounts.sendServerResponse2Client(2Client) : {0}", lOut), Logging.Level.DEBUG, pRequestObj.Counter);



                /*
                 * 2. Send "server response headers" to client
                 */

                foreach (Tuple <String, String> lHeaderTmp in pRequestObj.ServerResponseHeaders)
                {
                    byte[] lTmp = Encoding.ASCII.GetBytes(String.Format("{0}: {1}\n", lHeaderTmp.Item1, lHeaderTmp.Item2));
                    pRequestObj.ClientStream.Write(lTmp, 0, lTmp.Length);
                    Logging.LogMessage(String.Format("HTTPAccounts.sendServerResponse2Client(2Client:HEADER) : {0}: {1}", lHeaderTmp.Item1, lHeaderTmp.Item2), Logging.Level.DEBUG, pRequestObj.Counter);
                }

                pRequestObj.ClientStream.Write(Encoding.ASCII.GetBytes("\n"), 0, 1);

                if (pRequestObj.ServerWebResponse.ContentLength > 0)
                {
                    lBuffer = new Byte[pRequestObj.ServerWebResponse.ContentLength];
                }
                else
                {
                    lBuffer = new Byte[BUFFER_SIZE];
                }


                /*
                 * 3. Send "server response data section" to client
                 */
                int lDataVolume = 0;
                while ((lBytesRead = lResponseStream.Read(lBuffer, 0, lBuffer.Length)) > 0)
                {
                    Logging.LogMessage(String.Format("HTTPAccounts.sendServerResponse2Client(DATA) : Sending data from ... Server -> Client ({0} bytes)", lBytesRead), Logging.Level.DEBUG, pRequestObj.Counter);
                    lDataVolume += lBytesRead;
                    pRequestObj.ClientStream.Write(lBuffer, 0, lBytesRead);
                } // while ((lByte...


                Logging.LogMessage(String.Format("HTTPAccounts.sendServerResponse2Client(DATA) : Total data sent from    Server -> Client : {0}", lDataVolume), Logging.Level.DEBUG, pRequestObj.Counter);

                lResponseStream.Close();
                pRequestObj.ClientStream.Flush();
            }
            catch (Exception lEx)
            {
                Logging.LogMessage(String.Format("HTTPAccounts.sendServerResponse2Client(EXCEPTION) : {0}\n{1}", lEx.Message, lEx.StackTrace), Logging.Level.ERROR, pRequestObj.Counter);
            }
            finally
            {
                if (lResponseStream != null)
                {
                    lResponseStream.Close();
                }

                if (lMyResponseWriter != null)
                {
                    lMyResponseWriter.Close();
                }
            }
        }