插入腳本時,Fiddler(FiddlerCore)響應工作很慢

fiddler fiddlercore html-agility-pack proxy

我嘗試使用fiddlercore創建代理服務器,當我使用事件BeforeResponse代碼工作非常慢。我試圖做的是在當前瀏覽頁面的頂部插入腳本。

為什麼下面的代碼這麼慢是需要插入某種過濾器還是什麼?

Fiddler.FiddlerApplication.BeforeResponse += delegate(Fiddler.Session oS)
        {
            Console.WriteLine("{0}:HTTP {1} for {2}", oS.id, oS.responseCode, oS.fullUrl);

            oS.utilDecodeResponse(); 
            string HTML = oS.GetResponseBodyAsString();

            HtmlDocument htmlDoc = new HtmlDocument();
            try
            {
                htmlDoc.LoadHtml(HTML);
                HtmlNode node = htmlDoc.CreateElement("script");
                node.SetAttributeValue("src", "https://somesite.com");
                HtmlNode Head = htmlDoc.DocumentNode.SelectSingleNode("//Head");

                if (Head != null)
                {
                    Head.AppendChild(node);
                    oS.utilSetResponseBody(htmlDoc.DocumentNode.OuterHtml);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }

            Console.WriteLine("URL: {0}", oS.url);
        };

這是完整的代碼:

    /*
    * This demo program shows how to use the FiddlerCore library.
    *
    * Before compiling, ensure that the project's REFERENCES list points to the 
    * copy of FiddlerCore.dll included in this package.
    *
    * By default, the project is compiled without support for the SAZ File format.
    * If you want to add SAZ support, define the token SAZ_SUPPORT in the list of
    * Conditional Compilation symbols on the project's BUILD tab. You will also
    * need to add Ionic.Zip.Reduced.dll to your project's references.
    */

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Threading;
    using Fiddler;
    using System.Diagnostics;
    using HtmlAgilityPack;
    using System.Security.Cryptography.X509Certificates;
    using System.Text.RegularExpressions;

    namespace Demo
    {
        class Program
        {
            static Proxy oSecureEndpoint;
            static string sSecureEndpointHostname = "localhost";
            static int iSecureEndpointPort = 7777;

            public static void WriteCommandResponse(string s)
            {
                ConsoleColor oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(s);
                Console.ForegroundColor = oldColor;
            }

            public static void DoQuit()
            {
                WriteCommandResponse("Shutting down...");
                //  UninstallCertificate();
                //  Console.Write("\ncert: {0}", CertMaker.rootCertExists()); Console.ReadLine();
                //  if (null != oSecureEndpoint) oSecureEndpoint.Dispose();
                Fiddler.FiddlerApplication.Shutdown();

                Thread.Sleep(500);
            }
            private static string Ellipsize(string s, int iLen)
            {
                if (s.Length <= iLen) return s;
                return s.Substring(0, iLen - 3) + "...";
            }

    #if SAZ_SUPPORT
            private static void ReadSessions(List<Fiddler.Session> oAllSessions)
            {
                Session[] oLoaded = Utilities.ReadSessionArchive(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) 
                                                               + Path.DirectorySeparatorChar + "ToLoad.saz", false);

                if ((oLoaded != null) && (oLoaded.Length > 0))
                {
                    oAllSessions.AddRange(oLoaded);
                    WriteCommandResponse("Loaded: " + oLoaded.Length + " sessions.");
                }
            }

            private static void SaveSessionsToDesktop(List<Fiddler.Session> oAllSessions)
            {
                bool bSuccess = false;
                string sFilename = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
                                 + Path.DirectorySeparatorChar + DateTime.Now.ToString("hh-mm-ss") + ".saz";
                try
                {
                    try
                    {
                        Monitor.Enter(oAllSessions);

                        string sPassword = null;
                        Console.WriteLine("Password Protect this Archive (Y/N)?");
                        ConsoleKeyInfo oCKI = Console.ReadKey();
                        if ((oCKI.KeyChar == 'y') || (oCKI.KeyChar == 'Y'))
                        {
                            Console.WriteLine("\nEnter the password:");
                            sPassword = Console.ReadLine();
                            Console.WriteLine(String.Format("\nEncrypting with Password: '{0}'", sPassword));
                        }
                        Console.WriteLine();

                        bSuccess = Utilities.WriteSessionArchive(sFilename, oAllSessions.ToArray(), sPassword, false);
                    }
                    finally
                    {
                        Monitor.Exit(oAllSessions);
                    }

                    WriteCommandResponse( bSuccess ? ("Wrote: " + sFilename) : ("Failed to save: " + sFilename) );
                }
                catch (Exception eX)
                {
                    Console.WriteLine("Save failed: " + eX.Message);
                }
            }
    #endif
            public static bool InstallCertificate()
            {
                if (!CertMaker.rootCertExists())
                {
                    if (!CertMaker.createRootCert())
                        return false;

                    if (!CertMaker.trustRootCert())
                        return false;
                }

                return true;
            }

            public static bool UninstallCertificate()
            {
                if (CertMaker.rootCertExists())
                {
                    if (!CertMaker.removeFiddlerGeneratedCerts(true))
                        return false;
                }
                return true;
            }

            private static void WriteSessionList(List<Fiddler.Session> oAllSessions)
            {
                ConsoleColor oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.White;
                Console.WriteLine("Session list contains...");
                try
                {
                    Monitor.Enter(oAllSessions);
                    foreach (Session oS in oAllSessions)
                    {
                        Console.Write(String.Format("{0} {1} {2}\n{3} {4}\n\n", oS.id, oS.oRequest.headers.HTTPMethod, Ellipsize(oS.fullUrl, 60), oS.responseCode, oS.oResponse.MIMEType));
                    }
                }
                finally
                {
                    Monitor.Exit(oAllSessions);
                }
                Console.WriteLine();
                Console.ForegroundColor = oldColor;
            }

            private static bool setMachineTrust(X509Certificate2 oRootCert)
            {
                try
                {
                    // X509Certificate2 cert = X509Certificate2("C:\Path\my.pfx", "password");

                    X509Store certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
                    certStore.Open(OpenFlags.ReadWrite);

                    try
                    {
                        certStore.Add(oRootCert);
                    }
                    finally
                    {
                        certStore.Close();
                    }
                    return true;
                }
                catch (Exception eX)
                {
                    return false;
                }
            }

            static void Main(string[] args)
            {
                List<Fiddler.Session> oAllSessions = new List<Fiddler.Session>();

                // <-- Personalize for your Application, 64 chars or fewer
                Fiddler.FiddlerApplication.SetAppDisplayName("FiddlerCoreDemoApp");
                #region AttachEventListeners

                // Simply echo notifications to the console.  Because Fiddler.CONFIG.QuietMode=true 
                // by default, we must handle notifying the user ourselves.
                Fiddler.FiddlerApplication.OnNotification += delegate(object sender, NotificationEventArgs oNEA) { Console.WriteLine("** NotifyUser: " + oNEA.NotifyString); };
                Fiddler.FiddlerApplication.Log.OnLogString += delegate(object sender, LogEventArgs oLEA) { Console.WriteLine("** LogString: " + oLEA.LogString); };

                Fiddler.FiddlerApplication.BeforeRequest += delegate(Fiddler.Session oS)
                {
                    oS.bBufferResponse = true;

                    //Monitor.Enter(oAllSessions);
                    //oAllSessions.Add(oS);
                    //Monitor.Exit(oAllSessions);
                    //oS["X-AutoAuth"] = "(default)";

                    //if ((oS.oRequest.pipeClient.LocalPort == iSecureEndpointPort) && (oS.hostname == sSecureEndpointHostname))
                    {
                        // oSession.oRequest["NewHeaderName"] = "New header value";
                        // oS.oResponse.headers.Add("headerName", "\nThis is new header!!!\n").ToString()

                        //oS.utilCreateResponseAndBypassServer();
                        //oS.oResponse.headers.Add("headerName", "This is new header!!!\n");

                        //oS.oResponse.headers.SetStatus(200, "Ok");
                        //oS.oResponse["Content-Type"] = "text/html; charset=UTF-8";
                        //oS.oResponse["Cache-Control"] = "private, max-age=0";

                        // oS.utilSetResponseBody("fazlija ");

                        //oS.utilSetResponseBody("<html><body>Response for https://" + sSecureEndpointHostname + ":" + iSecureEndpointPort.ToString() + " received. Your response was:<br /><plaintext>" + oS.oRequest.headers.ToString());
                        // oS.oResponse["NewHeaderName"] = "\nNew header value";
                        // oSession.oResponse.headers.Remove("Set-Cookie");
                    //}
                };

                // Fiddler.FiddlerApplication.OnReadResponseBuffer += new EventHandler<RawReadEventArgs>(FiddlerApplication_OnReadResponseBuffer);
                Fiddler.FiddlerApplication.BeforeResponse += delegate(Fiddler.Session oS)
                {
                    Console.WriteLine("{0}:HTTP {1} for {2}", oS.id, oS.responseCode, oS.fullUrl);
                     oS.utilDecodeResponse(); oS.utilReplaceInResponse("Amazon", "Something");
                };

                Fiddler.FiddlerApplication.AfterSessionComplete += delegate(Fiddler.Session oS)
                {
                    //Console.WriteLine("Finished session:\t" + oS.fullUrl); 
                    Console.Title = ("Session list contains: " + oAllSessions.Count.ToString() + " sessions");
                };

                Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
                #endregion AttachEventListeners

                string sSAZInfo = "NoSAZ";

                Console.WriteLine(String.Format("Starting {0} ({1})...", Fiddler.FiddlerApplication.GetVersionString(), sSAZInfo));

                Fiddler.CONFIG.IgnoreServerCertErrors = false;

                FiddlerApplication.Prefs.SetBoolPref("fiddler.network.streaming.abortifclientaborts", true);

                // For forward-compatibility with updated FiddlerCore libraries, it is strongly recommended that you 
                // start with the DEFAULT options and manually disable specific unwanted options.
                FiddlerCoreStartupFlags oFCSF = FiddlerCoreStartupFlags.Default;

                // NOTE: In the next line, you can pass 0 for the port (instead of 8877) to have FiddlerCore auto-select an available port
                int iPort = 8879;
                Fiddler.FiddlerApplication.Startup(iPort, oFCSF);

                FiddlerApplication.Log.LogFormat("Created endpoint listening on port {0}", iPort);

                FiddlerApplication.Log.LogFormat("Starting with settings: [{0}]", oFCSF);
                FiddlerApplication.Log.LogFormat("Gateway: {0}", CONFIG.UpstreamGateway.ToString());

                Console.WriteLine("Hit CTRL+C to end session.");

                // We'll also create a HTTPS listener, useful for when FiddlerCore is masquerading as a HTTPS server
                // instead of acting as a normal CERN-style proxy server.
                oSecureEndpoint = FiddlerApplication.CreateProxyEndpoint(iSecureEndpointPort, true, sSecureEndpointHostname);
                if (null != oSecureEndpoint)
                {
                    FiddlerApplication.Log.LogFormat("Created secure endpoint listening on port {0}, using a HTTPS certificate for '{1}'", iSecureEndpointPort, sSecureEndpointHostname);
                }

                bool bDone = false;
                do
                {

                } while (!bDone);
            }


            /// <summary>
            /// This callback allows your code to evaluate the certificate for a site and optionally override default validation behavior for that certificate.
            /// You should not implement this method unless you understand why it is a security risk.
            /// </summary>
            static void CheckCert(object sender, ValidateServerCertificateEventArgs e)
            {
                if (null != e.ServerCertificate)
                {
                    Console.WriteLine("Certificate for " + e.ExpectedCN + " was for site " + e.ServerCertificate.Subject + " and errors were " + e.CertificatePolicyErrors.ToString());

                    if (e.ServerCertificate.Subject.Contains("fiddler2.com"))
                    {
                        Console.WriteLine("Got a certificate for fiddler2.com. We'll say this is also good for any other site, like https://fiddlertool.com.");
                        e.ValidityState = CertificateValidity.ForceValid;
                    }
                }
            }


            /*
            // This event handler is called on every socket read for the HTTP Response. You almost certainly don't want
            // to add a handler for this event, but the code below shows how you can use it to mess up your HTTP traffic.
            static void FiddlerApplication_OnReadResponseBuffer(object sender, RawReadEventArgs e)
            {
                // NOTE: arrDataBuffer is a fixed-size array. Only bytes 0 to iCountOfBytes should be read/manipulated.
                //
                // Just for kicks, lowercase every byte. Note that this will obviously break any binary content.
                for (int i = 0; i < e.iCountOfBytes; i++)
                {
                    if ((e.arrDataBuffer[i] > 0x40) && (e.arrDataBuffer[i] < 0x5b))
                    {
                        e.arrDataBuffer[i] = (byte)(e.arrDataBuffer[i] + (byte)0x20);
                    }
                }
                Console.WriteLine(String.Format("Read {0} response bytes for session {1}", e.iCountOfBytes, e.sessionOwner.id));
            }
            */

            /// <summary>
            /// When the user hits CTRL+C, this event fires.  We use this to shut down and unregister our FiddlerCore.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
            {
                DoQuit();
            }

            /*
            public static bool InstallCertificate()
            {
                if (!CertMaker.rootCertExists())
                {
                    if (!CertMaker.createRootCert())
                        return false;

                    if (!CertMaker.trustRootCert())
                        return false;



                    App.Configuration.UrlCapture.Cert =
                        FiddlerApplication.Prefs.GetStringPref("fiddler.certmaker.bc.cert", null);
                    App.Configuration.UrlCapture.Key =
                        FiddlerApplication.Prefs.GetStringPref("fiddler.certmaker.bc.key", null);
                }

                return true;
            }
            public static bool UninstallCertificate()
            {
                if (CertMaker.rootCertExists())
                {
                    if (!CertMaker.removeFiddlerGeneratedCerts(true))
                        return false;
                }
                App.Configuration.UrlCapture.Cert = null;
                App.Configuration.UrlCapture.Key = null;
                return true;
            }

             */
        }
    }

一般承認的答案

您當前的代碼正在解壓縮每個HTTP響應並嘗試將其視為HTML文檔。對於一切不是HTML(圖像等)的東西來說,這顯然會很慢而且會失敗。

相反, if oS.oResponse.headers.ExistsAndContains("text/html") ,您應該只進行處理。您無需手動調用utilDecodeResponse,因為GetResponseBodyAsString將為您處理。而非使用任何HtmlDocument是,您可能會改為考慮執行字符串替換,例如更換</head><script src=whatever.js /></head>



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因