La respuesta de Fiddler (FiddlerCore) funciona de forma lenta al insertar un script

fiddler fiddlercore html-agility-pack proxy

Pregunta

Intento crear un servidor proxy con fiddlercore y cuando uso el evento BeforeResponse, el código funciona muy lento. Lo que intento hacer es insertar una secuencia de comandos en la parte superior de la página actual.

¿Por qué el código debajo del código es tan lento si se debe insertar algún tipo de filtro o qué?

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

Aquí está el código completo:

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

             */
        }
    }

Respuesta aceptada

Su código actual está descomprimiendo cada respuesta HTTP y tratando de tratarlo como un documento HTML. Eso obviamente será lento y fallará para todo lo que no sea HTML (imágenes, etc.).

En su lugar, solo debe hacer su procesamiento if oS.oResponse.headers.ExistsAndContains("text/html") . No es necesario que llame manualmente a utilDecodeResponse ya que GetResponseBodyAsString se encargará de eso por usted. Y en lugar de usar lo que sea HtmlDocument , puede considerar realizar un reemplazo de cadena, por ejemplo, reemplazar </head> con <script src=whatever.js /></head> .




Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué