La réponse du Fiddler (FiddlerCore) fonctionne lentement lors de l'insertion du script

fiddler fiddlercore html-agility-pack proxy

Question

J'essaie de créer un serveur proxy avec fiddlercore et lorsque j'utilise le code d'événement BeforeResponse, je travaille très lentement. Ce que je tente de faire est d’insérer un script en haut de la page actuellement consultée.

Pourquoi le code ci-dessous est-il si lent? Faut-il insérer un type de filtre ou quoi?

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);
        };

Voici le code complet:

    /*
    * 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;
            }

             */
        }
    }

Réponse acceptée

Votre code actuel décompresse chaque réponse HTTP et essaie de le traiter comme un document HTML. Ce sera évidemment lent et échouera pour tout ce qui n'est pas HTML (images, etc.).

Au lieu de cela, vous ne devriez effectuer votre traitement que if oS.oResponse.headers.ExistsAndContains("text/html") . Vous n'avez pas besoin d'appeler manuellement utilDecodeResponse car GetResponseBodyAsString se GetResponseBodyAsString de cela. Et plutôt que d'utiliser ce que HtmlDocument est, vous pourriez envisager de remplacer une chaîne, par exemple, en remplaçant </head> par <script src=whatever.js /></head> .



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi