예제 #1
0
        /// <summary>
        /// Dummy logic loop, for test purposes
        /// </summary>
        override public bool LogicLoop()
        {
            uint r = SocketBP.ReadBinary();

            if (r == 0)
            {
                // Connection closed
                return(false);
            }

            string s = System.Text.ASCIIEncoding.ASCII.GetString(
                SocketBP.Buffer, 0, (int)r);

            if (bPrintEchoPrefix)
            {
                SocketBP.WriteBinary(System.Text.ASCIIEncoding.
                                     ASCII.GetBytes("Echo: "));
            }
            SocketBP.WriteBinary(SocketBP.Buffer, r);

            if (s.StartsWith("x"))
            {
                return(false);
            }
            return(true);
        }
예제 #2
0
        protected override void OnReceiveRequest()
        {
            if (InternetReports.BlockSites)
            {
                for (int i = 0; i < InternetReports.WebBlock.Count; i++)
                {
                    if (RequestLine.URI.Contains(InternetReports.WebBlock[i]))
                    {
                        SocketBP.Send403();
                        State.NextStep = AbortRequest;
                    }
                }
            }

            if (InternetReports.BlockSocialSites)
            {
                if (RequestLine.URI.Contains("facebook.com") || RequestLine.URI.Contains("twitter.com") ||
                    RequestLine.URI.Contains("instagram.com") || RequestLine.URI.Contains("myspace.com") ||
                    RequestLine.URI.Contains("plus.google.com"))
                {
                    SocketBP.Send403();
                    State.NextStep = AbortRequest;
                }
            }


            if (!string.IsNullOrWhiteSpace(RequestHeaders.Referer))
            {
                txt = RequestHeaders.Referer;
            }
            else
            {
                //myUri = new Uri(RequestLine.URI);
                //txt = myUri.Host;
                txt = RequestLine.URI;
                if (txt.Contains("localhost"))
                {
                    txt = "";
                }
            }


            if (!string.IsNullOrWhiteSpace(txt))
            {
                //Debug.WriteLine("txt: "+txt+"  Last: "+InternetReports.Last);

                if (!txt.Equals(InternetReports.Last) && !txt.Equals(InternetReports.Last2) && !txt.Equals(InternetReports.Last3) && !txt.Equals("localhost"))
                {
                    InternetReports.save.WriteLine(DateTime.Now.Hour.ToString("00") + ":" + DateTime.Now.Minute.ToString("00") + " : " + txt);
                    InternetReports.Last3 = InternetReports.Last2;
                    InternetReports.Last2 = InternetReports.Last;
                    InternetReports.Last  = txt;
                    InternetReports.save.Flush();
                }
            }
        }
예제 #3
0
            protected override void OnReceiveRequest(HttpRequestLine e)
            {
#if DEBUG
                Console.ForegroundColor = ConsoleColor.DarkBlue;
                Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId + " -> " + RequestLine
                                  + (RequestHeaders.Referer != null ? ", Referer: " + RequestHeaders.Referer : "")
                                  );
                Console.ForegroundColor = ConsoleColor.Gray;
#endif
                requestUri = RequestLine.Uri;                   // NOTE: used by ReceiveResponse
                if (blacklistHosts.Contains(requestUri?.Host))
                {
                    SocketBP.CloseSocket();
                }

                var method = e.Method.ToUpper();
                if (method != "CONNECT")
                {
                    timer = new System.Threading.Timer(new System.Threading.TimerCallback(OnExpire), null, 300 * 1000, System.Threading.Timeout.Infinite);
                }
                if ((method == "POST" || method == "PUT" || method == "PATCH"))
                {
                    if (skipHosts.Contains(e.Uri.Host))
                    {
                        return;
                    }

                    // Typical requests endpoint:
                    //http://summonerswar-gb.qpyou.cn/api/gateway_c2.php
                    if (e.Uri.AbsoluteUri.Contains("summonerswar") && e.Uri.AbsoluteUri.Contains("/api/gateway"))
                    {
                        string bodyString = Encoding.ASCII.GetString(SocketBP.Buffer, 0, Array.IndexOf(SocketBP.Buffer, (byte)0));
                        bodyString = bodyString.Substring(bodyString.IndexOf("\r\n\r\n"));                                      // TODO: FIXME: this needs to match first \r?\n\r?\n

                        decRequest = decryptRequest(bodyString, e.Uri.AbsolutePath.Contains("_c2.php") ? 2 : 1);
                        try {
                            req = JsonConvert.DeserializeObject <JObject>(decRequest);
                            if (!Directory.Exists("Json"))
                            {
                                Directory.CreateDirectory("Json");
                            }
                            File.WriteAllText($"Json\\{req["command"]}" +
#if DEBUG
                                              $"_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}" +
#endif
                                              ".req.json", JsonConvert.SerializeObject(req, Formatting.Indented));
                            Console.ForegroundColor = ConsoleColor.DarkGray;
                            Console.WriteLine($">{req["command"]}");
                            Console.ForegroundColor = ConsoleColor.Gray;
                        }
                        catch { };
                    }
                }
            }
예제 #4
0
        protected override void OnReceiveResponse()
        {
            if (ResponseStatusLine.StatusCode != HttpStatus.OK || !ResponseHeaders.Headers.ContainsKey("content-type"))
            {
                return;
            }
            if (RequestLine.Method != "POST" || !_requestUri.AbsoluteUri.Contains("api/gateway_c2"))
            {
                return;
            }

            var response = GetContent();

            State.NextStep = null;

            string content;

            using (var sr = new StreamReader(GetResponseMessageStream(response)))
            {
                content = sr.ReadToEnd();
            }

            SendResponseStatusAndHeaders();
            SocketBP.TunnelDataTo(TunnelBP, response);

            if (SocketBP != null)
            {
                SocketBP.CloseSocket();
                SocketBP = null;
            }
            if (SocketPS != null)
            {
                SocketPS.CloseSocket();
                SocketPS = null;
            }
            State.bPersistConnectionBP = false;
            State.bPersistConnectionPS = false;

            var stringResponse = Decrypt.DecryptResponse(content);
            var json           = JObject.Parse(stringResponse);

            MainWindow.Instance.HandleNewPacket(json);

            // Temp. saving all commands content to file
            using (var file = new StreamWriter($@"D:/SW-Commands/{json["command"].ToString()}.txt"))
            {
                file.WriteLine(json);
                file.Close();
            }
            Debug.WriteLine($"Proxy Command: {json["command"].ToString()}");
            Debug.WriteLine($"ts: {json["ts_val"].ToString()} / {Ut3()}");
        }
예제 #5
0
        protected override void OnReceiveRequest()
        {
            // Make your thesis more interesting by upgrading
            // your primary source of information
            int i = RequestLine.URI.IndexOf("wikipedia.org");

            if (i > -1)
            {
                ChangeRequestURI("http://uncyclopedia.org/" +
                                 RequestLine.URI.Substring(i + 14));
                return;
            }

            // Make yourself more productive
            if (RequestLine.URI.Contains("facebook.com"))
            {
                SocketBP.Send403();
                State.NextStep = AbortRequest;
            }
        }
예제 #6
0
            private void OnExpire(object state)
            {
#if DEBUG
                Console.ForegroundColor = ConsoleColor.DarkBlue;
                Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId + " -- " + this.requestUri.Host + " Expired");
                Console.ForegroundColor = ConsoleColor.Gray;
#endif
                if (SocketBP != null)
                {
                    SocketBP.CloseSocket();
                    SocketBP = null;
                }
                if (SocketPS != null)
                {
                    SocketPS.CloseSocket();
                    SocketPS = null;
                }
                State.bPersistConnectionBP = false;
                State.bPersistConnectionPS = false;
                State.NextStep             = null;
            }
예제 #7
0
 protected override void OnReceiveRequest()
 {
     //store complete request uri first, it will parsed and the host will be removed later
     FullRequestUri    = RequestLine.URI;
     DomainName        = GetDomain.GetDomainFromUrl(RequestLine.URI);
     DomainType        = PornDB.GetDomainType(DomainName);
     _autoDomainStatus = PornDB.GetAutoDomainStatus(DomainName);
     log.Debug(GetDomain.GetDomainFromUrl(RequestLine.URI));
     //DomainType == PornDatabase.DomainType.Black ||
     if (DomainType != PornDatabase.DomainType.White &&
         _autoDomainStatus == PornDatabase.ForbiddenItemStatus.Normal &&
         Properties.Settings.Default.IsPornWebsiteProtectionTurnOn)
     {
         PornDB.InsertBlockedPage(FullRequestUri);
         //SocketBP.Send403();
         //SocketBP.SendMasaHttpForbidden("I Love You!");
         SocketBP.SendMasaHttpForbidden(Properties.Settings.Default.forbiddenRedirectUrl, "<h1>该网页包含不良信息,已被" + Properties.Resources.ProductionName + "屏蔽!</h1>");
         //SocketBP.SendHttpError();
         State.NextStep = AbortRequest;
         log.Info("Block request in tmp black list: " + RequestLine.URI);
     }
 }
예제 #8
0
        protected override void OnReceiveResponse()
        {
            // Use the content-type field of the response headers to
            // Determine which HTTP content we want to modify.
            bool bModifyContent = false;

            if (ResponseHeaders.Headers.ContainsKey("content-type"))
            {
                bModifyContent = ResponseHeaders.Headers["content-type"].
                                 Contains("text/html");
            }

            // Rewriting may also depend on the user agent.
#if false
            if (RequestHeaders.Headers.ContainsKey("user-agent"))
            {
                if (RequestHeaders.Headers["user-agent"].ToLower().Contains("msie"))
                {
                    // ...
                }
            }
#endif

            // Do not rewrite anything unless we got a 200 status code.
            if (ResponseStatusLine.StatusCode != 200)
            {
                bModifyContent = false;
            }

            if (!bModifyContent)
            {
                // Propagate the content without modifying it.
                return;
            }

            // Let's assume we need to retrieve the entire file before
            // we can do the rewriting. This is usually the case if the
            // content has been compressed by the remote server, or if we
            // want to build a DOM tree.
            byte[] response = GetContent();

            // From now on, the default State.NextStep ( == SendResponse()
            // at this point) must not be called, since we already read
            // the response.
            State.NextStep = null;

            // Decompress the message stream, if necessary
            Stream   stream       = GetResponseMessageStream(response);
            byte[]   content      = ReadEverything(stream);
            Encoding fileEncoding = GetFileEncoding(content);

            if (fileEncoding == null)
            {
                // We could not guess the file encoding, so it's better not
                // to modify anything.
                SendResponseStatusAndHeaders();
                SocketBP.TunnelDataTo(TunnelBP, response);
                return;
            }

            string text;
            using (stream = new MemoryStream(content))
                using (var sr = new StreamReader(stream, fileEncoding))
                    text = sr.ReadToEnd();

            // We are now in a position to rewrite stuff.
            text = ModifyHTML(text);

            // Tell the browser not to cache our modified version.
            ResponseHeaders.CacheControl = "no-cache, no-store, must-revalidate";
            ResponseHeaders.Expires      = "Fri, 01 Jan 1990 00:00:00 GMT";
            ResponseHeaders.Pragma       = "no-cache";

            // Even if the response was originally transferred
            // by chunks, we are going to send it unchunked.
            // (We could send it chunked, though, by calling
            // TunnelChunkedDataTo, instead of TunnelDataTo.)
            ResponseHeaders.TransferEncoding = null;

            // Encode the modified content, and recompress it, as necessary.
            byte[] output = EncodeStringResponse(text, fileEncoding);
            ResponseHeaders.ContentLength = (uint)output.Length;

            // Finally, send the result.
            SendResponseStatusAndHeaders();
            SocketBP.TunnelDataTo(TunnelBP, output);

            // We are done with the request.
            // Note that State.NextStep has been set to null earlier.
        }
예제 #9
0
            protected override void OnReceiveResponse()
            {
#if DEBUG
                Console.ForegroundColor = ConsoleColor.DarkBlue;
                Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId + " <- " + ResponseStatusLine + ", " + requestUri.AbsoluteUri
                                  + (ResponseHeaders.ContentLength != null ? " Content-Length: " + ResponseHeaders.ContentLength.ToString() : "")
                                  );
                Console.ForegroundColor = ConsoleColor.Gray;
#endif
                if (ResponseStatusLine.StatusCode == HttpStatus.OK && ResponseHeaders.Headers.ContainsKey("content-type"))
                {
                    if (skipHosts.Contains(requestUri.Host))
                    {
                        return;
                    }

                    if (requestUri.AbsoluteUri.Contains("summonerswar") && requestUri.AbsoluteUri.Contains("/api/gateway"))
                    {
                        if (RequestLine.Method == "GET" || RequestLine.Method == "POST")
                        {
                            byte[] response = GetContent();

                            // From now on, the default State.NextStep ( == SendResponse()
                            // at this point) must not be called, since we already read
                            // the response.
                            State.NextStep = null;

                            // Decompress the message stream, if necessary
                            Stream stream = GetResponseMessageStream(response);
                            string body;
                            using (var sr = new StreamReader(stream)) {
                                body = sr.ReadToEnd();
                            }
                            SendResponseStatusAndHeaders();
                            SocketBP.TunnelDataTo(TunnelBP, response);

                            var decResponse = decryptResponse(body, requestUri.AbsolutePath.Contains("_c2.php") ? 2 : 1);

                            try {
                                var resp = JsonConvert.DeserializeObject <JObject>(decResponse);
                                if (!Directory.Exists("Json"))
                                {
                                    Directory.CreateDirectory("Json");
                                }
                                File.WriteAllText($"Json\\{resp["command"]}" +
#if DEBUG
                                                  $"_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}" +
#endif
                                                  ".resp.json", JsonConvert.SerializeObject(resp, Formatting.Indented));
                                Console.ForegroundColor = ConsoleColor.DarkGray;
                                Console.WriteLine($"<{resp["command"]}");
                                Console.ForegroundColor = ConsoleColor.Gray;

                                // only mangle my wizards who want it, don't crash others.
                                if (resp["command"].ToString() == "GetNoticeChat" && whitelistDebugWizards.Contains((ulong)req["wizard_id"]))
                                {
                                    var version = Assembly.GetExecutingAssembly().GetName().Version;
                                    var jobj    = new JObject();
                                    // Add the proxy version number to chat notices to remind people.
                                    jobj["message"] = "Proxy version: " + version;
                                    ///(json["notice_list"] as JArray).Add(jobj);
                                    resp["tzone"] = resp["tzone"].ToString().Replace("/", @"\/");

                                    var ver = requestUri.AbsolutePath.Contains("_c2.php") ? 2 : 1;

                                    var inMsg   = Convert.FromBase64String(body);
                                    var outMsg  = decryptMessage(inMsg, ver);
                                    var decData = zlibDecompressData(outMsg);

                                    var fix = JsonConvert.SerializeObject(resp);
                                    fix = fix.Replace(@"\\", "\\");
                                    var bytes = zlibCompressData(fix);
                                    var str   = encryptMessage(bytes, ver);
                                    var send  = Convert.ToBase64String(str);

                                    Console.WriteLine("str:" + (fix == decData));
                                    Console.WriteLine("b64:" + (inMsg.SequenceEqual(str)));
                                    Console.WriteLine("cry:" + (outMsg.SequenceEqual(bytes)));
                                    Console.WriteLine("bytes:" + (body.SequenceEqual(send)));

                                    //encryptResponse(fix, ver);
                                    //if (body.SequenceEqual(send))
                                    //	await e.SetResponseBodyString(send);
                                }
                            }
                            catch { };


                            if (decRequest != null)
                            {
                                System.Threading.Thread thr = new System.Threading.Thread(() =>
                                {
                                    SWEventArgs args = null;
                                    try
                                    {
                                        args = new SWEventArgs(decRequest, decResponse);
                                        Plugins?.Invoke(this, args);
                                    }
                                    catch (Exception ex)
                                    {
                                        Console.WriteLine($"Failed triggering plugin {ex.Source} with {ex.GetType().Name}: {ex.Message}");
#if DEBUG
                                        Console.WriteLine(ex.StackTrace);
#endif
                                    }
                                });
                                thr.Start();
                            }
                        }
                    }
                    else if (RequestHeaders.Headers.ContainsKey("accept-encoding"))
                    {
                        if (!ResponseHeaders.Headers.ContainsKey("content-encoding") && !ResponseHeaders.Headers.ContainsKey("transfer-encoding"))
                        {
                            // read response data
                            // compress
                            // add content-encoding header
                            // add Vary: Accept-Encoding
                            // (re)set content-length header
                        }
                    }
                }
            }
예제 #10
0
        protected void ProcessHtml()
        {
            log.Info("Process HTML: " + RequestLine.URI);
            // Let's assume we need to retrieve the entire file before
            // we can do the rewriting. This is usually the case if the
            // content has been compressed by the remote server, or if we
            // want to build a DOM tree.
            byte[] response = GetContent();

            // From now on, the default State.NextStep ( == SendResponse()
            // at this point) must not be called, since we already read
            // the response.
            State.NextStep = null;

            // Decompress the message stream, if necessary
            //byte[] content = ReadEverything(stream);
            Encoding fileEncoding = GetFileEncoding();

            bool bNoFileEncoding = false;

            if (fileEncoding == null)
            {
                bNoFileEncoding = true;
                fileEncoding    = Encoding.UTF8;
                // We could not guess the file encoding, so it's better not
                // to modify anything.
                //ResponseHeaders.TransferEncoding = null;
                //ResponseHeaders.ContentLength = (uint)response.Length;
                //SendResponseStatusAndHeaders();
                //SocketBP.TunnelDataTo(TunnelBP, response);
                //return;
            }

            //load html document
            Stream       stream  = GetResponseMessageStream(response);
            HtmlDocument htmlDoc = new HtmlDocument();

            htmlDoc.Load(stream, fileEncoding);
            // We are now in a position to get image src
            // if the white list does not contain the domain name
            if (DomainType != PornDatabase.DomainType.White)
            {
                HtmlNodeCollection nc = htmlDoc.DocumentNode.SelectNodes("//img[@src]");
                if (nc != null)
                {
                    log.Info("Images of page url: " + FullRequestUri);
                    lock (SyncObject)
                    {
                        HashSet <String> currentSet = GetPornSet(FullRequestUri);
                        foreach (HtmlNode imgsrc in nc)
                        {
                            HtmlAttribute src  = imgsrc.Attributes["src"];
                            String        asrc = ToAbsoluteUrl(src.Value);
                            currentSet.Add(asrc.ToLower());
                            log.Info("items: " + asrc.ToLower());
                        }
                    }
                }
            }
            //add p to body
            if (!bNoFileEncoding)
            {
                //var head = htmlDoc.DocumentNode.SelectSingleNode("//head");
                //var body = htmlDoc.DocumentNode.SelectSingleNode("//body");
                //if (head != null && body != null)
                //{
                //    HtmlNode pcss = htmlDoc.CreateElement("style");
                //    pcss.SetAttributeValue("type", "text/css");
                //    pcss.InnerHtml = HtmlDocument.HtmlEncode("#masatek-tag{color:green; background-color: gray; padding:5px; text-align:center; font-size: 150%;}");
                //    head.PrependChild(pcss);

                //    HtmlNode pMasaTag = htmlDoc.CreateElement("p");
                //    pMasaTag.SetAttributeValue("id", "masatek-tag");
                //    pMasaTag.InnerHtml = HtmlDocument.HtmlEncode("Powered by Masatek");
                //    body.PrependChild(pMasaTag);
                //}
            }


            // Even if the response was originally transferred
            // by chunks, we are going to send it unchunked.
            // (We could send it chunked, though, by calling
            // TunnelChunkedDataTo, instead of TunnelDataTo.)
            ResponseHeaders.TransferEncoding = null;

            // Encode the modified content, and recompress it, as necessary.
            //String text = htmlDoc.Save()
            //htmlDoc.Save(HttpUtility.UrlEncode(RequestLine.URI));
            if (!bNoFileEncoding)
            {
                //MemoryStream mstr = new MemoryStream();
                //htmlDoc.Save(mstr, fileEncoding);
                //response = CompressResponse(mstr.GetBuffer());
            }

            ResponseHeaders.ContentLength = (uint)response.Length;
            // Finally, send the result.
            SendResponseStatusAndHeaders();
            SocketBP.TunnelDataTo(TunnelBP, response);

            // We are done with the request.
            // Note that State.NextStep has been set to null earlier.
        }
예제 #11
0
        protected void ProcessImage()
        {
            log.Info("Process Image: " + RequestLine.URI);
            byte[] response = GetContent();

            // From now on, the default State.NextStep ( == SendResponse()
            // at this point) must not be called, since we already read
            // the response.
            State.NextStep = null;

            // Decompress the message stream, if necessary
            using (Stream stream = GetResponseMessageStream(response))
            {
                using (Bitmap bm = new Bitmap(stream))
                {
                    PornClassifier.ImageType imgType         = PornClassifier.Instance.Classify(bm);
                    IProgress <PornDatabase.PornItemType> ip = MainForm.Instance.TargetProcessedProgress as IProgress <PornDatabase.PornItemType>;
                    bool isImageBad = false;
                    if (imgType == PornClassifier.ImageType.P**n)
                    {
                        isImageBad = true;
                        //添加到不良网页中,以进行不良网站检查,只针对色情图片进行处理
                        //只在启用了色情网站侦测时才处理,但实际上由于未启用色情网站侦测时
                        //html不处理,这里其实即使处理也无法hit
                        if (Properties.Settings.Default.IsPornWebsiteProtectionTurnOn)
                        {
                            AddPorn();
                        }
                    }
                    else if (imgType == PornClassifier.ImageType.Disguise &&
                             Properties.Settings.Default.IsStrongNetworkImageFilter)
                    {
                        isImageBad = true;
                    }
                    else
                    {
                        ip.Report(PornDatabase.PornItemType.Undefined);
                    }

                    //if (p != null)
                    //只在图片过滤功能开启时才将色情图片加入数据库,并替换图片
                    Bitmap nbm = null;
                    if (isImageBad && Properties.Settings.Default.IsNetworkImageTurnOn)
                    {
                        //只有色情图片才加入数据库,防止将性感图片加入以后带来不好的感觉
                        if (imgType == PornClassifier.ImageType.P**n)
                        {
                            //先保存图片,在插入数据库,否则第一项会导致没有图片可以显示
                            bm.Save(Program.AppLocalDir + Properties.Settings.Default.imagesDir + "\\" + HttpUtility.UrlEncode(FullRequestUri));
                            PornDB.InsertPornPic(FullRequestUri, PornClassifier.ImageType.P**n);
                            log.Debug("After PornPicInserted");
                            ip.Report(PornDatabase.PornItemType.NetworkImage);
                        }

                        //此处如果图像为带索引格式,则会引发异常,无法创建graphics对象
                        //这使得网页上一个图片总是无法加载
                        nbm = new Bitmap(bm.Width, bm.Height);
                        //using (Graphics g = Graphics.FromImage(bm))
                        using (Graphics g = Graphics.FromImage(nbm))
                        {
                            //SolidBrush solidBrush = new SolidBrush(Color.Red);
                            SolidBrush solidBrush = new SolidBrush(Color.Azure);
                            g.FillRectangle(solidBrush, 0, 0, bm.Width, bm.Height);
                            SolidBrush stringBrush = new SolidBrush(Color.CadetBlue);
                            g.DrawString(Properties.Resources.ProductionName, new Font("微软雅黑", bm.Width / 10, GraphicsUnit.Pixel), stringBrush, new Point(0, 0));
                            g.Flush();
                        }
                    }

                    // Even if the response was originally transferred
                    // by chunks, we are going to send it unchunked.
                    // (We could send it chunked, though, by calling
                    // TunnelChunkedDataTo, instead of TunnelDataTo.)
                    ResponseHeaders.TransferEncoding = null;

                    // Encode the modified content, and recompress it, as necessary.
                    //String text = htmlDoc.Save()
                    //htmlDoc.Save(HttpUtility.UrlEncode(RequestLine.URI));
                    MemoryStream mstr = new MemoryStream();
                    if (nbm != null)
                    {
                        nbm.Save(mstr, bm.RawFormat);

                        //这里使用toArray就可以得到和实际内容长度相同的数据
                        byte[] output = CompressResponse(mstr.ToArray());
                        //这里必须使用mstr.Length,而不能使用output.Length
                        //因为前者表示真实长度,后者表示总缓存长度,比实际长度要长
                        //如果前面是使用ToArray,而不是GetBuffer则没问题
                        ResponseHeaders.ContentLength = (uint)output.Length;
                        SendResponseStatusAndHeaders();
                        SocketBP.TunnelDataTo(TunnelBP, output);

                        nbm.Dispose();
                    }
                    else
                    {
                        //用于测试,即使图片不替换,也重新保存
                        //bm.Save(mstr, bm.RawFormat);
                        //byte[] output = CompressResponse(mstr.ToArray());
                        //ResponseHeaders.ContentLength = (uint)output.Length;

                        SendResponseStatusAndHeaders();
                        SocketBP.TunnelDataTo(TunnelBP, response);
                    }

                    //debug code
                    //bm.Save(mstr, bm.RawFormat);
                    //这里使用toArray就可以得到和实际内容长度相同的数据
                    //byte[] output = CompressResponse(mstr.ToArray());
                    //byte[] output = CompressResponse(mstr.GetBuffer());
                    //这里必须使用mstr.Length,而不能使用output.Length
                    //因为前者表示真实长度,后者表示总缓存长度,比实际长度要长
                    //如果前面是使用ToArray,而不是GetBuffer则没问题
                    //ResponseHeaders.ContentLength = (uint)output.Length;
                    //SendResponseStatusAndHeaders();
                    //SocketBP.TunnelDataTo(TunnelBP, output);

                    //byte[] output = CompressResponse(mstr.GetBuffer());
                    //ResponseHeaders.ContentLength = (uint)output.Length;

                    // Finally, send the result.
                    //SendResponseStatusAndHeaders();
                    //SocketBP.TunnelDataTo(TunnelBP, output);
                    // We are done with the request.
                    // Note that State.NextStep has been set to null earlier.
                }
            }
        }