├── DWF-SampleCode ├── ReadMe.txt ├── Pg226-Installer.nsi ├── Pg228-BuildInstaller.bat ├── pg240-SampleExtension.cs ├── pg251-SampleTranscoder.cs ├── Pg87-App.exe.config.txt ├── TranscoderSnippets.cs ├── Pg185-DrivingFiddlerUsingPostMessage.txt ├── InspectorSnippets.cs ├── ExtensionSnippets.cs ├── FiddlerCoreSnippets.cs └── ScriptSnippets.txt ├── .gitignore ├── README.md ├── LICENSE └── CustomRules.js /DWF-SampleCode/ReadMe.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/FiddlerUseScript/HEAD/DWF-SampleCode/ReadMe.txt -------------------------------------------------------------------------------- /DWF-SampleCode/Pg226-Installer.nsi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/FiddlerUseScript/HEAD/DWF-SampleCode/Pg226-Installer.nsi -------------------------------------------------------------------------------- /DWF-SampleCode/Pg228-BuildInstaller.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/FiddlerUseScript/HEAD/DWF-SampleCode/Pg228-BuildInstaller.bat -------------------------------------------------------------------------------- /DWF-SampleCode/pg240-SampleExtension.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/FiddlerUseScript/HEAD/DWF-SampleCode/pg240-SampleExtension.cs -------------------------------------------------------------------------------- /DWF-SampleCode/pg251-SampleTranscoder.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/FiddlerUseScript/HEAD/DWF-SampleCode/pg251-SampleTranscoder.cs -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | -------------------------------------------------------------------------------- /DWF-SampleCode/Pg87-App.exe.config.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /DWF-SampleCode/TranscoderSnippets.cs: -------------------------------------------------------------------------------- 1 | // Page 246 2 | // Transcoders require methods introduced in v2.3.9.0... 3 | [assembly: Fiddler.RequiredVersion("2.3.9.0")] 4 | 5 | // Page 246 6 | [ProfferFormat("HTTPArchive v1.1", "A lossy JSON-based HTTP traffic 7 | archive format. Standard is documented @ http://groups.google.com/group/http- 8 | archive-specification/web/har-1-1-spec")] 9 | 10 | [ProfferFormat("HTTPArchive v1.2", "A lossy JSON-based HTTP traffic 11 | archive format. Standard is documented @ http://groups.google.com/group/http- 12 | archive-specification/web/har-1-2-spec")] 13 | 14 | public class HTTPArchiveFormatExport: ISessionExporter 15 | { 16 | ///... 17 | 18 | // Page 248 19 | public bool ExportSessions(string sFormat, Session[] oSessions, 20 | Dictionary dictOptions, 21 | EventHandler evtProgressNotifications) 22 | { 23 | 24 | //... 25 | string sFilename = null; 26 | int iMaxTextBodyLength = DEFAULT_MAX_TEXT_BYTECOUNT; 27 | int iMaxBinaryBodyLength = DEFAULT_MAX_BINARY_BYTECOUNT; 28 | 29 | if (null != dictOptions) 30 | { 31 | if (dictOptions.ContainsKey("Filename")) 32 | { 33 | sFilename = dictOptions["Filename"] as string; 34 | } 35 | 36 | if (dictOptions.ContainsKey("MaxTextBodyLength")) 37 | { 38 | iMaxTextBodyLength = (int)dictOptions["MaxTextBodyLength"]; 39 | } 40 | 41 | if (dictOptions.ContainsKey("MaxBinaryBodyLength")) 42 | { 43 | iMaxBinaryBodyLength = (int)dictOptions["MaxBinaryBodyLength"]; 44 | } 45 | } 46 | 47 | //... 48 | 49 | -------------------------------------------------------------------------------- /DWF-SampleCode/Pg185-DrivingFiddlerUsingPostMessage.txt: -------------------------------------------------------------------------------- 1 | // Page 184 2 | #include "stdafx.h" 3 | int _tmain(int argc, _TCHAR* argv[]) 4 | { 5 | HWND hWndControl = FindWindow(NULL, L"Fiddler - HTTP Debugging Proxy"); 6 | 7 | if (NULL == hWndControl) 8 | { 9 | printf("ERROR: Fiddler window was not found.\n"); 10 | return 2; 11 | } 12 | 13 | tagCOPYDATASTRUCT oCDS; 14 | 15 | oCDS.dwData = 61181; // Use 61180 for ANSI; 61181 for Unicode 16 | oCDS.cbData = lstrlen(argv[1]) * sizeof(WCHAR); 17 | oCDS.lpData = argv[1]; 18 | 19 | SendMessage(hWndControl, WM_COPYDATA, NULL, (WPARAM) wParam, (LPARAM) &oCDS); 20 | return 0; 21 | } 22 | 23 | // Page 185 24 | internal const int WM_COPYDATA = 0x4A; 25 | 26 | [DllImport("user32.dll", EntryPoint = "SendMessage")] 27 | internal static extern IntPtr SendWMCopyMessage(IntPtr hWnd, int Msg, 28 | IntPtr wParam, ref SendDataStruct lParam); 29 | 30 | [DllImport("user32.dll")] 31 | internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 32 | 33 | [StructLayout(LayoutKind.Sequential)] 34 | internal struct SendDataStruct 35 | { 36 | public IntPtr dwData; 37 | public int cbData; 38 | public string strData; 39 | } 40 | 41 | // Page 185 42 | SendDataStruct oStruct = new Utilities.SendDataStruct(); 43 | oStruct.dwData = (IntPtr) 61181; 44 | oStruct.strData = "TheString"; 45 | oStruct.cbData = Encoding.Unicode.GetBytes(oStruct.strData).Length; 46 | IntPtr hWnd = FindWindow(null, "Fiddler - HTTP Debugging Proxy"); 47 | SendWMCopyMessage(hWnd, Utilities.WM_COPYDATA, IntPtr.Zero, ref oStruct); 48 | -------------------------------------------------------------------------------- /DWF-SampleCode/InspectorSnippets.cs: -------------------------------------------------------------------------------- 1 | // Page 229 2 | public override void AddToTab(TabPage oPage) 3 | { 4 | // Title my tab 5 | o.Text = "Raw"; 6 | 7 | // Create my UserControl and add it to my tab 8 | myControl = new RawView(this); 9 | oPage.Controls.Add(myControl); 10 | oPage.Controls[0].Dock = DockStyle.Fill; 11 | } 12 | 13 | // Page 230 14 | static byte[] arr_WOFF_MAGIC = 15 | new byte[4] {(byte)'w', (byte)'O', (byte)'F', (byte)'F'}; 16 | 17 | public override int ScoreForSession(Session oS) 18 | { 19 | // Check for WOFF Magic Bytes 20 | if (Utilities.HasMagicBytes(oS.responseBodyBytes, arr_WOFF_MAGIC)) { 21 | return 60; 22 | } 23 | 24 | // If not found, consult at the response's Content-Type 25 | return ScoreForContentType(oS.oResponse.MIMEType); 26 | } 27 | 28 | // Page 231 29 | public override int ScoreForContentType(string sMIMEType) 30 | { 31 | if (sMIMEType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase)) { 32 | return 60; 33 | } 34 | 35 | if (sMIMEType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) { 36 | return 60; 37 | } 38 | 39 | // Just in case a site sent a malformed MP3 type, check the whole string 40 | if (sMIMEType.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) > -1) 41 | return 60; 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | // Page 233 48 | public override void AssignSession(Session oSession) 49 | { 50 | if ((null == oSession) || !oSession.bHasResponse) 51 | { 52 | Clear(); 53 | return; 54 | } 55 | 56 | UpdateUIFromHeaders(oSession.oResponse.headers); 57 | UpdateUIFromBody(oSession.responseBodyBytes); 58 | bool bIsReadOnly = ((oSession.state != SessionStates.HandTamperResponse) 59 | && !oSession.oFlags.ContainsKey("x-Unlocked")); 60 | 61 | UpdateReadOnlyState(bIsReadOnly); 62 | } 63 | 64 | // Page 234 65 | public virtual void AssignSession(Session oS) 66 | { 67 | if (this is IRequestInspector2) 68 | { 69 | IRequestInspector2 oRI = (this as IRequestInspector2); 70 | oRI.headers = oS.oRequest.headers; 71 | oRI.body = oS.requestBodyBytes; 72 | oRI.bReadOnly = ((oS.state != SessionStates.HandTamperRequest) 73 | && !oS.oFlags.ContainsKey("x-Unlocked")); 74 | return; 75 | } 76 | 77 | if (this is IResponseInspector2) 78 | //... 79 | 80 | 81 | // Page 235 82 | if (oHeaders.Exists("Transfer-Encoding") || oHeaders.Exists("Content-Encoding")) 83 | { 84 | lblDisplayMyEncodingWarning.Visible = true; 85 | return; 86 | } 87 | 88 | // Page 235 89 | if (null != oHeaders) 90 | { 91 | // Check for no body 92 | if ((null == value) || (value.Length < 1)) return; 93 | 94 | if (!oHeaders.ExistsAndContains("Content-Type", "application/json") 95 | && !oHeaders.ExistsAndContains("Content-Type", "javascript")) 96 | { 97 | // Not JSON 98 | return; 99 | } 100 | 101 | if (oHeaders.Exists("Transfer-Encoding") || oHeaders.Exists("Content-Encoding")) 102 | { 103 | // Create a copy of the body to avoid corrupting the original 104 | byte[] arrCopy = (byte[])value.Clone(); 105 | try 106 | { 107 | // Decode. Warning: Will throw if value cannot be decoded 108 | Utilities.utilDecodeHTTPBody(oHeaders, ref arrCopy); 109 | value = arrCopy; 110 | } 111 | catch 112 | { 113 | // Leave value alone. 114 | } 115 | } 116 | } 117 | 118 | // Okay, now the body stored in "value" is unchunked 119 | // and uncompressed. We need to convert it to a string, 120 | // keeping in mind that the HTTP response might have 121 | // been in a non-Unicode codepage. 122 | 123 | oEncoding = Utilities.getEntityBodyEncoding(oHeaders, value); 124 | sJSON = Utilities.GetStringFromArrayRemovingBOM(value, oEncoding); 125 | myControl.SetJSON(sJSON); 126 | 127 | //... 128 | 129 | // Page 236 130 | string sRequestBody = oSession.GetRequestBodyAsString(); 131 | string sResponseBody = oSession.GetResponseBodyAsString(); 132 | 133 | // Page 237 134 | // Inspector requires methods introduced in v2.3.9.0... 135 | [assembly: Fiddler.RequiredVersion("2.3.9.0")] 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /DWF-SampleCode/ExtensionSnippets.cs: -------------------------------------------------------------------------------- 1 | // Page 208 2 | public void AutoTamperRequestBefore(Session oSession) 3 | { 4 | // Return immediately if no rule is enabled 5 | if (!bBlockerEnabled) return; 6 | // ... 7 | 8 | // Page 208 9 | public void AutoTamperRequestBefore(Session oSession) 10 | { 11 | // Return immediately if no rule is enabled 12 | if (!bBlockerEnabled) return; 13 | // ... 14 | 15 | // Page 209 16 | public void OnLoad() 17 | { 18 | myPage = new TabPage("FiddlerScript"); 19 | myPage.ImageIndex = (int)Fiddler.SessionIcons.Script; 20 | this.lblLoading = new System.Windows.Forms.Label(); 21 | this.lblLoading.Text = "Loading..."; 22 | myPage.Controls.Add(lblLoading); 23 | FiddlerApplication.UI.tabsViews.TabPages.Add(myPage); 24 | 25 | TabControlEventHandler evtTCEH = null; 26 | evtTCEH = delegate(object s, TabControlEventArgs e) { 27 | if (e.TabPage == myTabPage) 28 | { 29 | // Create heavyweight components used to display UI 30 | EnsureReady(); 31 | 32 | // Remove the unneeded event handler. 33 | FiddlerApplication.UI.tabsViews.Selected -= evtTCEH; 34 | } 35 | }; 36 | 37 | // Subscribe to tab-change events 38 | FiddlerApplication.UI.tabsViews.Selected += evtTCEH; 39 | } 40 | 41 | // Page 209 42 | private void EnsureReady() 43 | { 44 | if (null != oEditor) return; // Exit if we've already been made ready 45 | 46 | lblLoading.Refresh(); // Force repaint of "Loading..." label 47 | 48 | // Create the extension's UI (slow) 49 | oEditor = new RulesEditor(myPage); 50 | lblLoading.Visible = false; // Remove the "Loading..." label 51 | } 52 | 53 | // Page 211 54 | void UpdateStatsTab(Session[] _arrSessions) 55 | { 56 | // If we're not showing the Stats tab right now, bail out. 57 | if (FiddlerApplication.UI.tabsViews.SelectedTab != 58 | FiddlerApplication.UI.pageStatistics) 59 | { 60 | return; 61 | } 62 | 63 | try 64 | { 65 | if (_arrSessions.Length < 1) 66 | { 67 | ClearStatsTab(); 68 | return; 69 | } 70 | 71 | Dictionary dictResponseSizeByContentType; 72 | long cBytesRecv; 73 | string sStats = BasicAnalysis.ComputeBasicStatistics( 74 | _arrSessions, true, out dictResponseSizeByContentType, out cBytesRecv); 75 | 76 | txtReport.Text = String.Format("{0}\r\n, sStats); 77 | } 78 | catch (Exception eX) 79 | { 80 | Debug.Assert(false, eX.Message); 81 | } 82 | } 83 | 84 | // Page 212 85 | FiddlerApplication.UI.actSelectSessionsMatchingCriteria( 86 | delegate(Session oS) 87 | { 88 | return oS.HTTPMethodIs("POST"); 89 | }); 90 | 91 | // Page 212 92 | FiddlerApplication.UI.actSelectSessionsMatchingCriteria( 93 | delegate(Session oS) 94 | { 95 | return (200 == oS.responseCode); 96 | }); 97 | 98 | // Page 214 99 | oSession.oRequest["HeaderName"] == oSession.oRequest.headers["HeaderName"] 100 | == oSession["REQUEST", "HeaderName"]; 101 | 102 | oSession.oResponse["HeaderName"] == oSession.oResponse.headers["HeaderName"] 103 | == oSession["RESPONSE", "HeaderName"]; 104 | 105 | // Page 215 106 | oSession.oFlags["FlagName"] == oSession["FlagName"] 107 | == oSession["SESSION", "FlagName"]; 108 | 109 | // Page 215 110 | if (!oSession.oFlags.ContainsKey("SomeKey") 111 | { 112 | Debug.Assert(oSession["SomeKey"] == null); 113 | Debug.Assert(oSession.oFlags["SomeKey"] == null); 114 | Debug.Assert(oSession["Session", "SomeKey"] == String.Empty); 115 | } 116 | 117 | 118 | // Page 219 119 | bool bHadAnyHTTPErrors = 120 | oSession.isAnyFlagSet(SessionFlags.ProtocolViolationInRequest 121 | | SessionFlags.ProtocolViolationInResponse); 122 | 123 | bool bReusedBothConnections = 124 | oSession.isFlagSet(SessionFlags.ClientPipeReused 125 | | SessionFlags.ServerPipeReused); 126 | 127 | // Page 224 128 | FiddlerApplication.Prefs.SetStringPref("example.str", "Remember me!"); 129 | FiddlerApplication.Prefs.SetBoolPref("example.bool", true); 130 | FiddlerApplication.Prefs.SetInt32Pref("example.int", 5); 131 | 132 | // Page 224 133 | FiddlerApplication.Prefs["example.str"] = "value"; 134 | 135 | // Page 224 136 | // These three lines are equivalent 137 | FiddlerApplication.Prefs.RemovePref("NameToRemove"); 138 | FiddlerApplication.Prefs.SetStringPref("NameToRemove", null); 139 | FiddlerApplication.Prefs["NameToRemove"] = null; 140 | 141 | // Page 224 142 | string sStr = FiddlerApplication.Prefs.GetStringPref("example.str", "demo"); 143 | bool bBool = FiddlerApplication.Prefs.GetBoolPref("example.bool", false); 144 | int iNum = FiddlerApplication.Prefs.GetInt32Pref("example.int", 0); 145 | 146 | // Page 224 147 | string sStr = FiddlerApplication.Prefs["example.str"]; 148 | 149 | // Page 240 150 | // See pg240-SampleExtension.cs file 151 | 152 | // Page 245 153 | public void OnLoad() 154 | { 155 | oPage = new TabPage("Timeline"); 156 | oPage.ImageIndex = (int)Fiddler.SessionIcons.Timeline; 157 | FiddlerApplication.UI.tabsViews.TabPages.Add(oPage); 158 | } 159 | 160 | // Page 245 161 | // Extension requires methods introduced in v2.3.9.0... 162 | [assembly: Fiddler.RequiredVersion("2.3.9.0")] 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /DWF-SampleCode/FiddlerCoreSnippets.cs: -------------------------------------------------------------------------------- 1 | // Page 101 2 | FiddlerApplication.ResponseHeadersAvailable += delegate(Fiddler.Session oS) 3 | { 4 | // This block enables streaming for files larger than 5mb 5 | if (oS.oResponse.headers.Exists("Content-Length")) 6 | { 7 | int iLen = 0; 8 | if (int.TryParse(oS.oResponse["Content-Length"], out iLen)) 9 | { 10 | // File larger than 5mb? Don't save its content 11 | if (iLen > 5000000) 12 | { 13 | oS.bBufferResponse = false; 14 | oS["log-drop-response-body"] = "save memory"; 15 | } 16 | } 17 | } 18 | }; 19 | 20 | // Page 259 21 | FiddlerApplication.OnNotification += delegate(object s, 22 | NotificationEventArgs oNEA) 23 | { 24 | Console.WriteLine("** NotifyUser: " + oNEA.NotifyString); 25 | }; 26 | 27 | FiddlerApplication.Log.OnLogString += delegate(object s, LogEventArgs oLEA) 28 | { 29 | Console.WriteLine("** LogString: " + oLEA.LogString); 30 | }; 31 | 32 | // Page 259 33 | FiddlerApplication.BeforeRequest += delegate(Session oS) 34 | { 35 | // Buffer response to allow response tampering 36 | oS.bBufferResponse = true; 37 | 38 | // Use a thread-safe mechanism to update my List 39 | Monitor.Enter(oAllSessions); 40 | oAllSessions.Add(oS); 41 | Monitor.Exit(oAllSessions); 42 | }; 43 | 44 | // Page 259 45 | FiddlerApplication.BeforeResponse += delegate(Fiddler.Session oS) 46 | { 47 | oS.utilDecodeResponse(); 48 | // Note: This change only takes effect properly if 49 | // oS.bBufferResponse was set to true earlier! 50 | oS.utilReplaceInResponse("", "<title>INJECTED!!"); 51 | }; 52 | 53 | // Page 259 54 | // The default flags are your best bet 55 | FiddlerCoreStartupFlags oFCSF = FiddlerCoreStartupFlags.Default; 56 | 57 | // ...but if, say, we don't want FiddlerCore to Decrypt 58 | // HTTPS traffic, we can unset that flag at this point 59 | oFCSF = (oFCSF & ~FiddlerCoreStartupFlags.DecryptSSL); 60 | 61 | // Page 260 62 | // Start listening on port 8877 63 | FiddlerApplication.Startup(8877, oFCSF); 64 | 65 | // Page 261 66 | FiddlerCoreStartupFlags oFlags = 67 | (FiddlerCoreStartupFlags.Default & ~FiddlerCoreStartupFlags.DecryptSSL); 68 | 69 | // Page 262 70 | FiddlerApplication.OnValidateServerCertificate += new 71 | System.EventHandler<ValidateServerCertificateEventArgs>(CheckCert); 72 | 73 | void CheckCert(object sender, ValidateServerCertificateEventArgs e) 74 | { 75 | // If there's an obvious issue with the presented certificate, 76 | // it will be rejected unless overridden here. 77 | if (SslPolicyErrors.None != e.CertificatePolicyErrors) 78 | { 79 | return; // Certificate will be rejected 80 | } 81 | 82 | // Check if the Convergence Certificate Notary services have 83 | // an opinion about this certificate chain. 84 | bool bNotariesAffirm = GetNotaryConsensus(e.Session, 85 | e.ServerCertificate, e.ServerCertificateChain); 86 | 87 | FiddlerApplication.Log.LogFormat("Notaries have indicated that the " 88 | + "certificate presented for {0} is {1}", e.ExpectedCN, 89 | bNotariesAffirm ? "VALID" : "INVALID"); 90 | 91 | if (!bNotariesAffirm) 92 | { 93 | e.ValidityState = CertificateValidity.ForceInvalid; 94 | return; 95 | } 96 | 97 | e.ValidityState = CertificateValidity.ForceValid; 98 | } 99 | 100 | // Page 263 101 | FiddlerApplication.OnReadResponseBuffer += new 102 | EventHandler<RawReadEventArgs>(OnRead); 103 | 104 | static void OnRead(object sender, RawReadEventArgs e) 105 | { 106 | Console.WriteLine(String.Format("Read {0} response bytes for session {1}", 107 | e.iCountOfBytes, e.sessionOwner.id)); 108 | 109 | // NOTE: arrDataBuffer is a fixed-size array. Only bytes 0 to 110 | // iCountOfBytes should be read/manipulated. 111 | 112 | // Just for kicks, lowercase every ASCII char. Note that this will 113 | // obviously mangle any binary MIME files and break many types of markup 114 | for (int i = 0; i < e.iCountOfBytes; i++) 115 | { 116 | if ((e.arrDataBuffer[i] > 0x40) && (e.arrDataBuffer[i] < 0x5b)) 117 | { 118 | e.arrDataBuffer[i] = (byte)(e.arrDataBuffer[i] + (byte)0x20); 119 | } 120 | } 121 | } 122 | 123 | //pg 263 124 | FiddlerApplication.ResponseHeadersAvailable += delegate(Session oS) 125 | { 126 | // Disable streaming for HTML responses on a target server so that 127 | // we can modify those responses in the BeforeResponse handler 128 | if (oS.HostnameIs("example.com") && oS.oResponse.MIMEType.Contains("text/html")) 129 | { 130 | oS.bBufferResponse = true; 131 | } 132 | }; 133 | 134 | // Page 264 135 | FiddlerApplication.BeforeReturningError += delegate(Session oS) 136 | { 137 | string sErrMsg = oS.GetResponseBodyAsString(); 138 | 139 | oS.utilSetResponseBody("<!doctype html><title>AcmeCorp Error Page" 140 | + "Sorry, this page or service is presently unavailable. Please try" 141 | + " again later.
" + sErrMsg + "
"); 142 | }; 143 | 144 | // Page 265 145 | Proxy oSecureEP = FiddlerApplication.CreateProxyEndpoint(8777, true, "localhost"); 146 | if (null != oSecureEP) 147 | { 148 | FiddlerApplication.Log.LogString("Created secure endpoint listening " 149 | + "on port 8777, which will send a HTTPS certificate for 'localhost'"); 150 | } 151 | 152 | // Page 266 153 | FiddlerApplication.Log.LogFormat("Session {0} received by EndPoint on Port #{1}", 154 | oSession.id, 155 | (null != oSession.oRequest.pipeClient) ? 156 | "n/a" : oSession.oRequest.pipeClient.LocalPort 157 | ); 158 | 159 | // Page 268 160 | // Inside your main object, create a list to hold the Sessions 161 | // The generic list type requires you are #using System.Collections.Generic 162 | List oAllSessions = new List(); 163 | 164 | // Add Sessions to the list as they are captured 165 | Fiddler.FiddlerApplication.BeforeRequest += delegate(Fiddler.Session oS) 166 | { 167 | Monitor.Enter(oAllSessions); 168 | oAllSessions.Add(oS); 169 | Monitor.Exit(oAllSessions); 170 | }; 171 | 172 | // Page 268 173 | Fiddler.URLMonInterop.SetProxyInProcess("127.0.0.1:7777", "<-loopback>"); 174 | 175 | // Page 269 176 | private bool CreateAndTrustRoot() 177 | { 178 | // Ensure root exists 179 | if (!Fiddler.CertMaker.rootCertExists()) 180 | { 181 | bCreatedRootCertificate = Fiddler.CertMaker.createRootCert(); 182 | if (!bCreatedRootCertificate) return false; 183 | } 184 | 185 | // Ensure root is trusted 186 | if (!Fiddler.CertMaker.rootCertIsTrusted()) 187 | { 188 | bTrustedRootCert = Fiddler.CertMaker.trustRootCert(); 189 | if (!bTrustedRootCert) return false; 190 | } 191 | 192 | return true; 193 | } 194 | 195 | // Page 269 196 | private static bool setMachineTrust(X509Certificate2 oRootCert) 197 | { 198 | try 199 | { 200 | X509Store certStore = new X509Store(StoreName.Root, 201 | StoreLocation.LocalMachine); 202 | certStore.Open(OpenFlags.ReadWrite); 203 | try 204 | { 205 | certStore.Add(oRootCert); 206 | } 207 | finally 208 | { 209 | certStore.Close(); 210 | } 211 | return true; 212 | } 213 | catch (Exception eX) 214 | { 215 | return false; 216 | } 217 | } 218 | 219 | // Page 270 220 | Fiddler.FiddlerApplication.BeforeRequest += delegate(Fiddler.Session oS) 221 | { 222 | if (oS.uriContains("replaceme.txt")) 223 | { 224 | oS.utilCreateResponseAndBypassServer(); 225 | oS.responseBodyBytes = SessionIWantToReturn.responseBodyBytes; 226 | oS.oResponse.headers = 227 | (HTTPResponseHeaders) SessionIWantToReturn.oResponse.headers.Clone(); 228 | } 229 | }; 230 | 231 | 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FiddlerUseScript 2 | 3 | ### 简介:抓包工具,调试接口除了已有的功能,还可以使用灵活的脚本来处理一些场景 4 | 5 | ### 欢迎各位朋友 request 自己的经验方案 6 | 7 | ************************************************************************************************************** 8 | ** 官网脚本api示例教程:http://docs.telerik.com/fiddler/KnowledgeBase/FiddlerScript/ModifyRequestOrResponse 9 | 10 | ** Fiddler命令行教程:http://docs.telerik.com/fiddler/knowledgebase/quickexec 11 | 12 | ** FiddlerScript的api:http://fiddlerbook.com/Fiddler/dev/ScriptSamples.asp 13 | 14 | ** jscript.net官网教程:https://msdn.microsoft.com/en-us/library/91td9cas(v=vs.80).aspx 15 | 16 | ** google网上论坛:https://groups.google.com/forum/?fromgroups#%21forum/httpfiddler 17 | ************************************************************************************************************* 18 | 19 | [TOC] 20 | 21 | 22 | ### 该文件在window的文件目录位置:C:\Users\"you_pc_name"\Documents\Fiddler2\Scripts 23 | 24 | # FiddlerScript的场景应用(20180412, 更新:20200817): 25 | 26 | ## +++++++++++++++++beforerequest+++++++++++++++++++++++ 27 | 28 | 1. 在此处【设置代理网络限速】1KB的量 50Kb/s需要delay 160ms
29 | 带宽:mbps kbps (比特流) 网速:KB/s MB/s (字节流)
30 | 修改完记得勾选【simulate modem speeds】[randInt(1,50) 模拟网络抖动]
31 | 32 | ``` 33 | 上传带宽 = 1KB/300ms = (1 * 8/1000) /0.300 ≈ 0.027Mbps 34 | 下载带宽 = 1KB/150ms = (1 * 8/1000) /0.150 ≈ 0.053Mbps 35 | (1MB = 1024 KB ≈ 1000 KB 这里为了运算简便就用了1000的倍数,忽略误差) 36 | ``` 37 | 38 | ``` 39 | static function randInt(min, max) { 40 | return Math.round(Math.random()*(max-min)+min); 41 | } 42 | if (m_SimulateModem) { 43 | // Delay sends by 300ms per KB uploaded. 44 | oSession["request-trickle-delay"] = ""+randInt(1,50); 45 | // Delay receives by 150ms per KB downloaded. 46 | oSession["response-trickle-delay"] = ""+randInt(1,50); 47 | } 48 | ``` 49 | 2. 在此处【过滤并高亮显示host】 50 | ``` 51 | if( oSession.host.IndexOf("host") > -1 || oSession.host.IndexOf("host") > -1){ 52 | oSession["ui-color"] = "green"; 53 | } 54 | ``` 55 | 56 | 3. 在此处【过滤url并高亮显示】 57 | ``` 58 | if(oSession.url.IndexOf("url_path") > -1){ 59 | oSession["ui-color"] = "yellow"; 60 | } 61 | ``` 62 | 4. 在此处【重定向urlplace】host和url的判断 63 | ``` 64 | if(oSession.HostnameIs("host") && oSession.url.IndexOf("url_path") > -1){ 65 | oSession.hostname = "api.mobile.xxx.com" 66 | } 67 | ``` 68 | 5. 在此处【设置请求的header】,测试网络爬虫时候会用, 69 | ``` 70 | // TSET FOR Spider: 根据网站来限定请求 71 | if (oSession.HostnameIs("test.com")) { 72 | // 模拟修改请求的用户端ip,这种情况对独立的网络有效,对于公司级的网络,还是有一些问题,需要借助vpn 73 | oSession.oRequest["X-Forwarded-For"]="16.12.23.16"; 74 | // 修改请求的header 75 | oSession.oRequest["User-Agent"] = "spider Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 SE 2.X MetaSr 1.0"; 76 | 77 | } 78 | ``` 79 | 80 | 81 | 2019.04.26 手机模拟添加cookie(区别于种cookie 在onBeforeResponse里) 82 | 83 | * 删除所有的cookie 84 | `oSession.oRequest.headers.Remove("Cookie");` 85 | 86 | * 新建cookie 87 | `oSession.oRequest.headers.Add("Cookie", "username=testname;testpassword=P@ssword1");` 88 | 89 | 注意: Fiddler script不能直接删除或者编辑单独的一个cookie, 你需要用replace方法或者正则表达式的方法去操作cookie的string 90 | 91 | ``` 92 | if (oSession.HostnameIs("******") && oSession.oRequest.headers.Exists("Cookie") ) { 93 | 94 | var sCookie = oSession.oRequest["Cookie"]; 95 | //用replace方法或者正则表达式的方法去操作cookie的string 96 | //sCookie = sCookie.Replace("cookieName=", "ignoreme="); 97 | sCookie = sCookie + ";tt_spver=1"; 98 | 99 | oSession.oRequest["Cookie"] = sCookie; 100 | } 101 | ``` 102 | 103 | ## +++++++++++++++++beforerespond+++++++++++++++++++++ 104 | 105 | 5. 需要在返回头这里就设置buffer处理,否则,后续无法在onBeforeResponse中修改body(修改的动作不会阻塞原来的返回) 106 | 107 | ``` 108 | static function OnPeekAtResponseHeaders(oSession: Session) { 109 | if (oSession.HostnameIs("cmshow.qq.com") && oSession.oResponse.headers.ExistsAndContains("Content-Type","text/html")){ 110 | oSession.bBufferResponse = true; 111 | } 112 | } 113 | ``` 114 | 6. 在此处修改response的bady内容【使用正则匹配方式】 115 | ``` 116 | if(oSession.HostnameIs("host") && oSession.url.IndexOf("url_path") > -1){ 117 | // 获取response中的body字符串 118 | var strBody=oSession.GetResponseBodyAsString(); 119 | // 用正则表达式或者replace方法去修改string 120 | var regx = '"stream_mode":\d*?' 121 | strBody=strBody.replace(regx,'"stream_mode":0'); 122 | // 弹个对话框检查下修改后的body 123 | FiddlerObject.alert(strBody); 124 | // 将修改后的body,重新写回Request中 125 | oSession.utilSetResponseBody(strBody); 126 | } 127 | ``` 128 | 129 | 7. 在此处修改json中的数据【修改接口字段的值】 130 | ``` 131 | if(oSession.HostnameIs("host") && oSession.url.IndexOf("url_path") > -1){ 132 | // 获取Response Body中JSON字符串 133 | var responseStringOriginal = oSession.GetResponseBodyAsString(); 134 | // 转换为可编辑的JSONObject变量 135 | var responseJSON = Fiddler.WebFormats.JSON.JsonDecode(responseStringOriginal); 136 | // 修改JSONObject变量,修改字段数据 137 | responseJSON.JSONObject["new_core"] = "True"; 138 | responseJSON.JSONObject["stream_mode"] = 5; 139 | // 重新设置Response Body 140 | var responseStringDestinal = Fiddler.WebFormats.JSON.JsonEncode(responseJSON.JSONObject); 141 | oSession.utilSetResponseBody(responseStringDestinal); 142 | } 143 | ``` 144 | 8. 在此处修改json中的数据【增加接口字段=值】 145 | ``` 146 | if(oSession.HostnameIs("host") && oSession.url.IndexOf("url_path") > -1){ 147 | // 获取Response Body中JSON字符串 148 | var responseStringOriginal = oSession.GetResponseBodyAsString(); 149 | // 转换为可编辑的JSONObject变量 150 | var responseJSON = Fiddler.WebFormats.JSON.JsonDecode(responseStringOriginal); 151 | // 修改JSONObject变量,修改字段数据 152 | responseJSON.JSONObject["type_arr"] = ["bullet"]; 153 | // 重新设置Response Body 154 | var responseStringDestinal = Fiddler.WebFormats.JSON.JsonEncode(responseJSON.JSONObject); 155 | oSession.utilSetResponseBody(responseStringDestinal); 156 | } 157 | ``` 158 | 9. 使指定URL支持CORS跨域请求有时候,你调用一个 json 接口,发现跨域了,你需要去找接口的开发人支持跨域,显然傻傻等待后端开发完毕再联调是低效率的, 159 | 这个时候就就要在后台改完之前就自己实现跨域的模拟,此时 fiddler 显然是再好不过的利器。支要持 CORS 跨域, 160 | 就是要为请求的返回头增加 Access-Control-Allow-Origin 属性,因此需要修改 OnBeforeResponse函数,在该函数的末尾添加你的 CORS 逻辑 161 | 162 | ``` 163 | static function OnBeforeResponse(oSession: Session) { 164 | ... 165 | 166 | if(oSession.uriContains("要处理的url")){ 167 | oSession.oResponse["Access-Control-Allow-Origin"] = "允许的域名"; 168 | oSession.oResponse["Access-Control-Allow-Credentials"] = true; 169 | } 170 | } 171 | ``` 172 | 10. 同一域名不同端口或目录转发到不同服务器某些情况下,一个域名部署了多个业务的应用,但有时候你只需要修改自己的应用,这个时候你会使用hosts把该域名指向开发机,但问题来了,该域名下所有的应用都指向了同一个开发机,如何使得其他应用仍然指向正式环境?显然依靠传统的hosts工具无法解决这个问题,这时就需要编写fiddler规则脚本了: 173 | ``` 174 | static function OnBeforeResponse(oSession: Session) { 175 | ... 176 | 177 | if(oSession.host == "www.google.com:80"){ 178 | oSession["x-overrideHost"] = "123.123.123.123"; 179 | } 180 | if(oSession.pathAndQuery.contains("/path1/"){ 181 | oSession["x-overrideHost"] = "124.124.124.124"; 182 | }else if(oSession.pathAndQuery.contains("/path2/"){ 183 | oSession["x-overrideHost"] = "125.125.125.125"; 184 | } 185 | } 186 | ``` 187 | 188 | 11. 场景--同时将接口返回修改成404;这种方式可以解决bpu命令的单个调试的 缺点;全部断点需要操作的步骤太多,浪费时间 189 | ``` 190 | if(oSession.HostnameIs("host1") && oSession.url.IndexOf("url_path1") > -1){ 191 | //说明已经拿到了播放请求接口,将其返回网络状态码修改成:404 192 | oSession.oResponse.headers.HTTPResponseCode = 404; 193 | oSession.oResponse.headers.HTTPResponseStatus = "use fiddler change responed code"; 194 | 195 | } 196 | if(oSession.HostnameIs("host2") && oSession.url.IndexOf("url_path2") > -1){ 197 | //同上 198 | oSession.oResponse.headers.HTTPResponseCode = 404; 199 | oSession.oResponse.headers.HTTPResponseStatus = "use fiddler change responed code"; 200 | } 201 | ``` 202 | 12. 自定义菜单 203 | ``` 204 | //这里是新加的菜单项 205 | RulesString("Override &Allow-Origin", true) //一级菜单名称 206 | RulesStringValue(1,"http://xx", "http://xx.com", true) //指定几个默认的的选项 207 | RulesStringValue(2,"https://xx", "https://xx.com", true) //指定几个默认的的选项 208 | 209 | //RulesStringValue(1,"xx_test", "https://test.xx.com", true) //指定几个默认的的选项 210 | RulesStringValue(3,"&Custom...", "%CUSTOM%") //允许用户自已定义,点击时弹出输入 211 | 212 | //如果加第4个参数为true的话,会把当前规则当作默认规则,每次启动都会生效,如: 213 | //RulesStringValue(5,"菜单项显示内容","菜单项选中对应值",true)//将会默认选中此项 214 | public static var sAllowOriginss: String = null; //定义变量名称 215 | ``` 216 | 217 | 13. 使用自定义得变量(请求跨域操作) 218 | ```angular2html 219 | // 12.自定义菜单得内容里,最后一行 public static var sAllowOriginss: String = null; //定义变量名称 220 | // 对这个sAllowOriginss变量进行使用(在OnBeforeResponse里使用) 221 | if (sAllowOrigin && !oSession.oResponse.headers.Exists("Access-Control-Allow-Origin")) 222 | { 223 | oSession.oResponse.headers.Add("Access-Control-Allow-Credentials", true); 224 | oSession.oResponse.headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 225 | oSession.oResponse.headers.Add("Access-Control-Allow-Origin", sAllowOrigin); 226 | 227 | } 228 | ``` 229 | 230 | 14. 对fiddler里的session按照设备进行过滤 231 | ``` 232 | public static var gs_FilterDevice: boolean = false; // 是否过滤单设备请求标志 233 | public static var gs_FilterClientIP: String = null; // 显示请求的设备的 ClientIP 234 | 235 | static function IsUnMatchClientIP(oS:Session):Boolean { 236 | return (oS.m_clientIP != gs_FilterClientIP); 237 | } 238 | public static ContextAction("开/关过滤单设备请求") 239 | function ToggleDeviceFilter(oSessions: Fiddler.Session[]){ 240 | if (gs_FilterDevice) { 241 | gs_FilterDevice = false; 242 | return; 243 | } 244 | var oS: Session = FiddlerApplication.UI.GetFirstSelectedSession(); 245 | if (null == oS) return; 246 | if (!gs_FilterDevice) { 247 | gs_FilterDevice = true; 248 | } 249 | gs_FilterClientIP = oS.clientIP; 250 | // 删除当前已显示的非所关心设备的请求 251 | FiddlerApplication.UI.actSelectSessionsMatchingCriteria(IsUnMatchClientIP); 252 | FiddlerApplication.UI.actRemoveSelectedSessions(); 253 | } 254 | 255 | Fiddler修改脚本进行对fiddler里的session按照设备进行过滤 256 | ``` 257 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /DWF-SampleCode/ScriptSnippets.txt: -------------------------------------------------------------------------------- 1 | // Page 68 2 | if (oSession.HTTPMethodIs("CONNECT") && oSession.HostnameIs("example.com")) 3 | { 4 | oSession["X-OverrideHost"] ="www.fiddler2.com"; 5 | } 6 | 7 | // Page 68 8 | if (oSession.HTTPMethodIs("CONNECT") && 9 | oSession.HostnameIs("example.com")) 10 | { 11 | oSession["X-OverrideHost"] ="www.fiddler2.com"; 12 | 13 | // Set flag to suppress Fiddler's HTTPS Name Mismatch errors 14 | oSession["X-IgnoreCertCNMismatch"] = "no worries mate"; 15 | } 16 | 17 | // Page 98 18 | if (oSession.HostnameIs("test.example.com")) { 19 | oSession["x-OverrideGateway"] = "127.0.0.1:8111"; 20 | } 21 | 22 | // Page 101 23 | // This block enables streaming for files larger than 5mb 24 | if (oSession.oResponse.headers.Exists("Content-Length")) 25 | { 26 | var sLen = oSession.oResponse["Content-Length"]; 27 | if (!isNaN(sLen)) { 28 | var iLen = parseInt(sLen); 29 | if (iLen > 5000000) { 30 | oSession.bBufferResponse = false; 31 | oSession["ui-color"] = "yellow"; 32 | oSession["log-drop-response-body"] = "save memory"; 33 | } 34 | } 35 | } 36 | 37 | // Page 113 38 | if (oSession.HTTPMethodIs("CONNECT") && 39 | oSession.HostnameIs("buggy.example.com")) 40 | { 41 | oSession["x-OverrideSslProtocols"] = "ssl3.0"; 42 | } 43 | 44 | // Page 117 45 | static function OnBeforeRequest(oSession: Session) 46 | { 47 | // To use the current Fiddler user's credentials: 48 | if (oSession.HostnameIs("ServerThatDemandsCreds")) { 49 | oSession["x-AutoAuth"] = "(default)"; 50 | } 51 | 52 | // or, to use explicit credentials... 53 | if (oSession.HostnameIs("ServerUsingChannelBinding")) { 54 | oSession["x-AutoAuth"] = "redmond\\ericlaw:MyP@$$w0rd"; 55 | } 56 | 57 | //... 58 | 59 | // Page 119 60 | static function OnBeforeRequest(oSession: Session) 61 | { 62 | if (oSession.HTTPMethodIs("CONNECT") { 63 | if (oSession.HostnameIs("exampleA")) { 64 | oSession["https-Client-Certificate"] = "C:\\certs\\CertA.cer"; 65 | } 66 | else 67 | if (oSession.HostnameIs("exampleB")) { 68 | oSession["https-Client-Certificate"] = "C:\\test\\CertB.cer"; 69 | } 70 | } 71 | 72 | //... 73 | 74 | // Page 178 75 | var sMyString: String = "StringValue"; 76 | var bMyBool: boolean = false; 77 | var iMyInt: int = 42; 78 | 79 | 80 | // Page 178 81 | // Call the hidden method using the format Object.add_EventName(handlerFunction) 82 | FiddlerApplication.add_OnClearCache(catchClearCache); 83 | 84 | // Implement the event handler 85 | static function catchClearCache(sender, args:CacheClearEventArgs) { 86 | MessageBox.Show("User cleared the cache."); 87 | } 88 | 89 | // Page 186 90 | // Launch Opera 91 | ToolsAction("Launch Opera") 92 | public static function DoLaunchOpera() 93 | { 94 | System.Diagnostics.Process.Start("opera.exe", String.Empty); 95 | } 96 | 97 | 98 | // Page 186 99 | // Launch Opera to the URL of the first selected session 100 | ToolsAction("Launch Opera to &URL") 101 | public static function DoLaunchOperaToURL(oS: Session[]) 102 | { 103 | if (oS.Length > 0) { 104 | System.Diagnostics.Process.Start("opera.exe", oS[0].fullUrl); 105 | } 106 | } 107 | 108 | // Page 187 109 | RulesOption("Hide 304s") 110 | public static var m_Hide304s: boolean = false; 111 | 112 | // Page 188 113 | if (m_Hide304s && (304 == oSession.responseCode)) { 114 | 115 | oSession["ui-hide"] = "true"; 116 | 117 | // Note: This block could be placed in the OnPeekAtResponseHeaders method, 118 | // since it does not depend upon the availability of the response body. 119 | } 120 | 121 | // Page 187 122 | ContextAction("Decode Selected Sessions") 123 | public static function DoRemoveEncoding(oS: Session[]) 124 | { 125 | for (var x=0; x < oS.Length; x++) { 126 | oS[x].utilDecodeRequest(); 127 | oS[x].utilDecodeResponse(); 128 | } 129 | } 130 | 131 | // Page 187 132 | RulesOption("Hide 304s") 133 | public static var m_Hide304s: boolean = false; 134 | 135 | // Page 188 136 | if (m_Hide304s && (304 == oSession.responseCode)) { 137 | 138 | oSession["ui-hide"] = "true"; 139 | 140 | // Note: This block could be placed in the OnPeekAtResponseHeaders method, 141 | // since it does not depend upon the availability of the response body. 142 | } 143 | 144 | // Page 188 145 | RulesOption("Simulate &Modem Speeds", "Per&formance") 146 | public static var m_SimulateModem: boolean = false; 147 | 148 | RulesOption("&Disable Caching", "Per&formance") 149 | public static var m_DisableCaching: boolean = false; 150 | 151 | RulesOption("&Show Time-to-Last-Byte", "Per&formance") 152 | public static var m_ShowTTLB: boolean = false; 153 | 154 | // Page 188 155 | RulesOption("Option A", "MyMenu", true) 156 | public static var m_OptionA: boolean = true; 157 | 158 | RulesOption("Option B", "MyMenu", true) 159 | public static var m_OptionB: boolean = false; 160 | 161 | RulesOption("Option C", "MyMenu", true, true) // Splitter after option 162 | public static var m_OptionC: boolean = false; 163 | 164 | RulesOption("Some other setting", "MyMenu", false) 165 | public static var m_OtherSetting: boolean = true; 166 | 167 | // Page 189 168 | RulesString("MyStringRule", true) 169 | RulesStringValue("MyMenuText1", "MyValue1") 170 | RulesStringValue("MyMenuText2", "MyValue2") 171 | RulesStringValue("MyMenuText3", "MyValue3") 172 | public static var m_StringRule: String = String.Empty; 173 | 174 | // Page 190 175 | RulesString("MyStringRule", true) 176 | RulesStringValue(1, "First Item", "one") 177 | RulesStringValue(2, "Second Item", "two", true) 178 | RulesStringValue(3, "Third Item", "three") 179 | RulesStringValue(4, "Fourth Item", "four") 180 | RulesStringValue(5, "Ask me...", "%CUSTOM%") 181 | public static var m_StringRule: String = "two"; 182 | 183 | // Page 190 184 | if (null != sUA) { 185 | oSession.oRequest["User-Agent"] = sUA; 186 | } 187 | 188 | // Page 191 189 | QuickLinkMenu("&Links") 190 | QuickLinkItem("IE GeoLoc TestDrive", 191 | "http://ie.microsoft.com/testdrive/HTML5/Geolocation/Default.html") 192 | QuickLinkItem("FiddlerCore", "http://fiddler.wikidot.com/fiddlercore") 193 | public static function DoLinksMenu(sText: String, sAction: String) 194 | { 195 | Utilities.LaunchHyperlink(sAction); 196 | } 197 | 198 | // Page 191 199 | QuickLinkMenu("&Browse") 200 | QuickLinkItem("&IE", "iexplore.exe") 201 | QuickLinkItem("&Firefox", "firefox.exe") 202 | QuickLinkItem("&Opera", "Opera.exe") 203 | QuickLinkItem("&Chrome", "Chrome.exe") 204 | public static function DoBrowsersMenu(sText: String, sAction: String) 205 | { 206 | var oS = FiddlerApplication.UI.GetSelectedSessions(); 207 | var sURL = String.Empty; 208 | 209 | if (oS.Length > 0) { sURL = oS[0].fullUrl; } 210 | 211 | System.Diagnostics.Process.Start(sAction, sURL); 212 | } 213 | 214 | // Page 192 215 | BindUIColumn("Method", 60) 216 | public static function FillMethodColumn(oS: Session) { 217 | if ((oS.oRequest != null) && (oS.oRequest.headers != null)) 218 | { 219 | return oS.oRequest.headers.HTTPMethod; 220 | } 221 | return String.Empty; 222 | } 223 | 224 | // Page 193 225 | BindUIColumn("HasFuzzle", 60) 226 | public static function FillFuzzleColumn(oS: Session) { 227 | 228 | // Check the cache and return the value if we already computed it 229 | if (oS.oFlags.ContainsKey("HasFuzzle")) 230 | { 231 | return oS.oFlags["HasFuzzle"]; 232 | } 233 | 234 | // Exit if we don't yet have a response 235 | if (!oS.bHasResponse) 236 | { 237 | return String.Empty; 238 | } 239 | 240 | // Avoid looking inside binary content 241 | if (Utilities.IsBinaryMIME(oS.oResponse.MIMEType)) 242 | { 243 | oS.oFlags["HasFuzzle"] = "n/a"; 244 | return "n/a"; 245 | } 246 | 247 | var s = oS.GetResponseBodyAsString(); 248 | var i = -1; 249 | 250 | if (s.Length > 0) 251 | { 252 | i = s.IndexOf("fuzzle", StringComparison.OrdinalIgnoreCase); 253 | if (i >= 0) 254 | { 255 | oS.oFlags["HasFuzzle"] = "Yes!"; 256 | return "Yes!"; 257 | } 258 | } 259 | 260 | oS.oFlags["HasFuzzle"] = "Nope"; 261 | return "Nope"; 262 | } 263 | 264 | // Page 194 265 | public BindUIColumn(string sTitle) 266 | public BindUIColumn(string sTitle, bool bSortNumerically) 267 | public BindUIColumn(string sTitle, int iWidth) 268 | public BindUIColumn(string sTitle, int iWidth, int iDisplayOrder) 269 | public BindUIColumn(string sTitle, int iWidth, 270 | int iDisplayOrder, bool bSortColumnNumerically) 271 | 272 | 273 | // Page 194 274 | FiddlerObject.UI.lvSessions.AddBoundColumn("ClientPort", 50, "X-CLIENTPORT"); 275 | FiddlerObject.UI.lvSessions.AddBoundColumn("Server", 50, "@response.Server"); 276 | FiddlerObject.UI.lvSessions.AddBoundColumn("Reason", 50, 277 | "@request.X-Download-Initiator"); 278 | 279 | // Page 195 280 | // Callback function that returns the "Time to first byte" value 281 | static function getTTLB(oS: Session): String 282 | { 283 | var iMS = Math.round((oS.Timers.ServerDoneResponse 284 | - oS.Timers.FiddlerBeginRequest).TotalMilliseconds); 285 | if (iMS > 0) return iMS.ToString(); 286 | return 0; 287 | } 288 | 289 | FiddlerObject.UI.lvSessions.AddBoundColumn("TTLB", 0, 50, true, getTTLB); 290 | 291 | // Page 195 292 | FiddlerObject.UI.lvSessions.AddBoundColumn("4", 0, 50, func4); 293 | FiddlerObject.UI.lvSessions.AddBoundColumn("3", 0, 40, func3); 294 | FiddlerObject.UI.lvSessions.AddBoundColumn("2", 0, 30, func2); 295 | FiddlerObject.UI.lvSessions.AddBoundColumn("1", 0, 20, func1); 296 | 297 | // Page 195 298 | FiddlerApplication.UI.lvSessions.SetColumnOrderAndWidth("Protocol", 0, -1); 299 | 300 | // Page 195 301 | FiddlerApplication.UI.lvSessions.SetColumnOrderAndWidth("#", 0, -1); 302 | FiddlerApplication.UI.lvSessions.SetColumnOrderAndWidth("Result", 1, -1); 303 | FiddlerApplication.UI.lvSessions.SetColumnOrderAndWidth("Protocol", 0, -1); 304 | FiddlerApplication.UI.lvSessions.SetColumnOrderAndWidth("Host", 0, -1); 305 | 306 | // Page 196 307 | static function Main() { 308 | var today: Date = new Date(); 309 | FiddlerObject.StatusText = " CustomRules.js was loaded at: " + today; 310 | } 311 | 312 | // Page 196 313 | static function OnPeekAtResponseHeaders(oSession: Session) { 314 | FiddlerObject.log("_Underlined\t#" + oSession.id.ToString()); 315 | FiddlerObject.log("!Bolded\t" + oSession.fullUrl); 316 | FiddlerObject.log("/Italicized\t" + oSession.oResponse.MIMEType); 317 | } 318 | 319 | // Page 197 320 | var sTagName: String = 321 | FiddlerObject.prompt("Enter a HTML tag name", "
", "Specify Tag"); 322 | 323 | // Page 197 324 | var oSessions = FiddlerApplication.UI.GetAllSessions(); 325 | var oExportOptions = FiddlerObject.createDictionary(); 326 | oExportOptions.Add("Filename", "C:\\users\\ericlaw\\desktop\\out1.har"); 327 | oExportOptions.Add("MaxTextBodyLength", 0); 328 | oExportOptions.Add("MaxBinaryBodyLength", 0); 329 | FiddlerApplication.DoExport("HTTPArchive v1.2", oSessions, oExportOptions, null); 330 | 331 | // Page 198 332 | static function Main() { 333 | FiddlerObject.WatchPreference("fiddler.script", ObservePrefChange); 334 | } 335 | 336 | static function ObservePrefChange(oSender: Object, oPCEA: PrefChangeEventArgs) { 337 | var sMsg: String = oPCEA.PrefName + " changed to " + oPCEA.ValueString; 338 | MessageBox.Show(sMsg, "A pref was changed"); 339 | } 340 | 341 | 342 | // Page 200 343 | oSession.oRequest["HeaderName"] = "New value"; 344 | oSession.oRequest["X-Fiddler-SessionID"] = oSession.id.ToString(); 345 | oSession.oResponse.headers.Remove("Cookie"); 346 | 347 | // Page 200 348 | if (oSession.oRequest.headers.Exists("Cookie")) 349 | { 350 | oSession["ui-color"]="red"; 351 | oSession["ui-customcolumn"] = oSession.oRequest["Cookie"]; 352 | } 353 | 354 | // Page 200 355 | if (!oSession.isHTTPS && !oSession.HTTPMethodIs("CONNECT") && 356 | oSession.HostnameIs("myServer")) 357 | { 358 | oSession.oRequest.headers.UriScheme = "https"; 359 | } 360 | 361 | // Page 201 362 | if (oSession.BitFlags & SessionFlags.ProtocolViolationInRequest) { 363 | var sOverride = oSession["X-Original-Host"]; 364 | if (!String.IsNullOrEmpty(sOverride)) { 365 | oSession["X-overrideHost"] = sOverride; 366 | oSession["ui-backcolor"] = "yellow"; 367 | 368 | // Be sure to bypass the gateway, otherwise overrideHost doesn't work 369 | oSession.bypassGateway = true; 370 | } 371 | } 372 | 373 | // Page 201 374 | if (oSession.uriContains("DropIt") && (null != oS.oRequest.pipeClient)) { 375 | 376 | // Use this to close the connection using TCP/IP RST 377 | oS.oRequest.pipeClient.EndWithRST(); 378 | 379 | // or use this to close the connection using TCP/IP FIN 380 | // oS.oRequest.pipeClient.End(); 381 | 382 | // So that the UI shows what we did, create a placeholder 383 | // response for display purposes: 384 | if (this.state < SessionStates.SendingRequest) { 385 | oS.utilCreateResponseAndBypassServer(); 386 | } 387 | 388 | oS.oResponse.headers.HTTPResponseCode = 0; 389 | oS.oResponse.headers.HTTPResponseStatus = "0 Connection dropped by script"; 390 | oS.responseBodyBytes = new byte[0]; 391 | oS.state = SessionStates.Aborted; 392 | return; 393 | } 394 | 395 | // Page 201 396 | if (oSession.HostnameIs("myServer") && oSession.uriContains(".aspx")) 397 | { 398 | oSession.bBufferResponse = true; 399 | } 400 | 401 | // Page 202 402 | if (oSession.oResponse.MIMEType.Contains("image")) 403 | { 404 | oSession["ui-hide"] = "Script hiding images"; 405 | } 406 | 407 | // Page 202 408 | if ((oSession.responseCode > 299) && (oSession.responseCode < 400)) { 409 | 410 | oSession["ui-customcolumn"] = oSession.oResponse["Location"]; 411 | oSession["ui-bold"] = "redirect"; 412 | } 413 | 414 | // Page 202 415 | if ( !Utilities.IsBinaryMIME(oSession.oResponse.MIMEType) ) 416 | { 417 | oSession.utilDecodeResponse(); 418 | oSession.utilReplaceInResponse("-moz-", "-ms-"); 419 | oSession.utilReplaceInResponse("-webkit-", "-ms-"); 420 | } 421 | 422 | // Page 202 423 | // Use regular expressions to modify the response body: 424 | if (oSession.oResponse.MIMEType.Contains("html")) { 425 | var oBody = oSession.GetResponseBodyAsString(); 426 | 427 | // Replace all content of DIV tags with an empty string. 428 | // WARNING: Doesn't work well with nested DIVs. 429 | var oRegEx = /]*>(.*?)<\/div>/gi; 430 | oBody = oBody.replace(oRegEx, ""); 431 | 432 | // Set the response body to the div-less string 433 | oSession.utilSetResponseBody(oBody); 434 | } 435 | 436 | // Page 225 437 | // This callback function is called on Pref changes 438 | // under the branch we specified. 439 | static function FnChange(o: Object, pceA: PrefChangeEventArgs) { 440 | if (null != pceA) { 441 | MessageBox.Show(pceA.PrefName + " changed to: " + pceA.ValueString); 442 | } 443 | else { 444 | MessageBox.Show("Unexpected."); 445 | } 446 | } 447 | 448 | static function Main() { 449 | // Attach a callback to the preference change 450 | FiddlerObject.WatchPreference("fiddler.", FnChange); 451 | } 452 | 453 | // Page 248 454 | var oSessions = FiddlerApplication.UI.GetAllSessions(); 455 | var oExportOptions = FiddlerObject.createDictionary(); 456 | oExportOptions.Add("Filename", "C:\\users\\ericlaw\\desktop\\out1.har"); 457 | oExportOptions.Add("MaxTextBodyLength", 1024); 458 | oExportOptions.Add("MaxBinaryBodyLength", 16384); 459 | 460 | FiddlerApplication.DoExport("HTTPArchive v1.2", oSessions, oExportOptions, null); 461 | 462 | // Page 281 463 | oSession["ui-hide"] = "hidden by Hide Images rule"; 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | -------------------------------------------------------------------------------- /CustomRules.js: -------------------------------------------------------------------------------- 1 | import System; 2 | import System.Windows.Forms; 3 | import Fiddler; 4 | 5 | // INTRODUCTION 6 | // 7 | // Well, hello there! 8 | // 9 | // Don't be scared! :-) 10 | // 11 | // This is the FiddlerScript Rules file, which creates some of the menu commands and 12 | // other features of Fiddler. You can edit this file to modify or add new commands. 13 | // 14 | // The original version of this file is named SampleRules.js and it is in the 15 | // \Program Files\Fiddler\ folder. When Fiddler first runs, it creates a copy named 16 | // CustomRules.js inside your \Documents\Fiddler2\Scripts folder. If you make a 17 | // mistake in editing this file, simply delete the CustomRules.js file and restart 18 | // Fiddler. A fresh copy of the default rules will be created from the original 19 | // sample rules file. 20 | 21 | // The best way to edit this file is to install the FiddlerScript Editor, part of 22 | // the free SyntaxEditing addons. Get it here: http://fiddler2.com/r/?SYNTAXVIEWINSTALL 23 | 24 | // GLOBALIZATION NOTE: Save this file using UTF-8 Encoding. 25 | 26 | // JScript.NET Reference 27 | // http://fiddler2.com/r/?msdnjsnet 28 | // 29 | // FiddlerScript Reference 30 | // http://fiddler2.com/r/?fiddlerscriptcookbook 31 | 32 | class Handlers 33 | { 34 | // ***************** 35 | // 36 | // This is the Handlers class. Pretty much everything you ever add to FiddlerScript 37 | // belongs right inside here, or inside one of the already-existing functions below. 38 | // 39 | // ***************** 40 | 41 | // The following snippet demonstrates a custom-bound column for the Web Sessions list. 42 | // See http://fiddler2.com/r/?fiddlercolumns for more info 43 | /* 44 | public static BindUIColumn("Method", 60) 45 | function FillMethodColumn(oS: Session): String { 46 | return oS.RequestMethod; 47 | } 48 | */ 49 | 50 | // The following snippet demonstrates how to create a custom tab that shows simple text 51 | /* 52 | public BindUITab("Flags") 53 | static function FlagsReport(arrSess: Session[]):String { 54 | var oSB: System.Text.StringBuilder = new System.Text.StringBuilder(); 55 | for (var i:int = 0; i-1)) { // Case sensitive 169 | oSession.url = oSession.url.Replace(gs_ReplaceToken, gs_ReplaceTokenWith); 170 | } 171 | if ((null != gs_OverridenHost) && (oSession.host.toLowerCase() == gs_OverridenHost)) { 172 | oSession["x-overridehost"] = gs_OverrideHostWith; 173 | } 174 | 175 | if ((null!=bpRequestURI) && oSession.uriContains(bpRequestURI)) { 176 | oSession["x-breakrequest"]="uri"; 177 | } 178 | 179 | if ((null!=bpMethod) && (oSession.HTTPMethodIs(bpMethod))) { 180 | oSession["x-breakrequest"]="method"; 181 | } 182 | 183 | if ((null!=uiBoldURI) && oSession.uriContains(uiBoldURI)) { 184 | oSession["ui-bold"]="QuickExec"; 185 | } 186 | //1.在此处【设置代理网络限速】1KB的量 50Kb/s需要delay 160ms 187 | //带宽:mbps kbps (比特流) 网速:KB/s MB/s (字节流) 188 | //修改完记得勾选【simulate modem speeds】[调用这个方法randInt(1,50) 模拟网络抖动] 189 | if (m_SimulateModem) { 190 | // Delay sends by 300ms per KB uploaded. 191 | oSession["request-trickle-delay"] = "1000"; 192 | // Delay receives by 150ms per KB downloaded. 193 | oSession["response-trickle-delay"] = "1000"; 194 | } 195 | //2.在此处【过滤并高亮显示host】 196 | if( oSession.host.IndexOf("i-play.mobile.youku.com") > -1 || oSession.host.IndexOf("a-dxk.play.api.3g.youku.com") > -1){ 197 | oSession["ui-color"] = "green"; 198 | 199 | } 200 | //3.在此处【过滤url并高亮显示】 201 | //if(oSession.url.IndexOf("/player/domain_name") > -1){ 202 | // oSession["ui-color"] = "yellow"; 203 | // } 204 | 205 | //4.在此处【重定向urlplace】host和url的判断 http:// http:// 206 | if(oSession.HostnameIs("test.api.mobile.youku.com") && oSession.url.IndexOf("/openapi-wireless/initial") > -1){ 207 | oSession.hostname = "api.mobile.youku.com" 208 | } 209 | 210 | if (m_DisableCaching) { 211 | oSession.oRequest.headers.Remove("If-None-Match"); 212 | oSession.oRequest.headers.Remove("If-Modified-Since"); 213 | oSession.oRequest["Pragma"] = "no-cache"; 214 | } 215 | 216 | //5:修改请求版本检验的接口中的header 217 | if(oSession.HostnameIs("host") && oSession.url.IndexOf("/getAppVersionInfo")>-1) 218 | { 219 | oSession.oRequest["version"] = "1.0.0" 220 | } 221 | 222 | // User-Agent Overrides 223 | if (null != sUA) { 224 | oSession.oRequest["User-Agent"] = sUA; 225 | } 226 | 227 | if (m_Japanese) { 228 | oSession.oRequest["Accept-Language"] = "ja"; 229 | } 230 | 231 | if (m_AutoAuth) { 232 | // Automatically respond to any authentication challenges using the 233 | // current Fiddler user's credentials. You can change (default) 234 | // to a domain\\username:password string if preferred. 235 | // 236 | // WARNING: This setting poses a security risk if remote 237 | // connections are permitted! 238 | oSession["X-AutoAuth"] = "(default)"; 239 | } 240 | 241 | if (m_AlwaysFresh && (oSession.oRequest.headers.Exists("If-Modified-Since") || oSession.oRequest.headers.Exists("If-None-Match"))) 242 | { 243 | oSession.utilCreateResponseAndBypassServer(); 244 | oSession.responseCode = 304; 245 | oSession["ui-backcolor"] = "Lavender"; 246 | } 247 | } 248 | 249 | // This function is called immediately after a set of request headers has 250 | // been read from the client. This is typically too early to do much useful 251 | // work, since the body hasn't yet been read, but sometimes it may be useful. 252 | // 253 | // For instance, see 254 | // http://blogs.msdn.com/b/fiddler/archive/2011/11/05/http-expect-continue-delays-transmitting-post-bodies-by-up-to-350-milliseconds.aspx 255 | // for one useful thing you can do with this handler. 256 | // 257 | // Note: oSession.requestBodyBytes is not available within this function! 258 | /* 259 | static function OnPeekAtRequestHeaders(oSession: Session) { 260 | var sProc = ("" + oSession["x-ProcessInfo"]).ToLower(); 261 | if (!sProc.StartsWith("mylowercaseappname")) oSession["ui-hide"] = "NotMyApp"; 262 | } 263 | */ 264 | 265 | // 266 | // If a given session has response streaming enabled, then the OnBeforeResponse function 267 | // is actually called AFTER the response was returned to the client. 268 | // 269 | // In contrast, this OnPeekAtResponseHeaders function is called before the response headers are 270 | // sent to the client (and before the body is read from the server). Hence this is an opportune time 271 | // to disable streaming (oSession.bBufferResponse = true) if there is something in the response headers 272 | // which suggests that tampering with the response body is necessary. 273 | // 274 | // Note: oSession.responseBodyBytes is not available within this function! 275 | // 276 | static function OnPeekAtResponseHeaders(oSession: Session) { 277 | //FiddlerApplication.Log.LogFormat("Session {0}: Response header peek shows status is {1}", oSession.id, oSession.responseCode); 278 | if (m_DisableCaching) { 279 | oSession.oResponse.headers.Remove("Expires"); 280 | oSession.oResponse["Cache-Control"] = "no-cache"; 281 | } 282 | 283 | if ((bpStatus>0) && (oSession.responseCode == bpStatus)) { 284 | oSession["x-breakresponse"]="status"; 285 | oSession.bBufferResponse = true; 286 | } 287 | 288 | if ((null!=bpResponseURI) && oSession.uriContains(bpResponseURI)) { 289 | oSession["x-breakresponse"]="uri"; 290 | oSession.bBufferResponse = true; 291 | } 292 | 293 | } 294 | 295 | static function OnBeforeResponse(oSession: Session) { 296 | if (m_Hide304s && oSession.responseCode == 304) { 297 | oSession["ui-hide"] = "true"; 298 | } 299 | /* 300 | //5.在此处修改response的bady内容 301 | if(oSession.HostnameIs("com") && oSession.url.IndexOf("/common/v5/play") > -1){ 302 | // 获取response中的body字符串 303 | var strBody=oSession.GetResponseBodyAsString(); 304 | 305 | // 用正则表达式或者replace方法去修改string 306 | var regx = '"stream_mode":\d*?' 307 | strBody=strBody.replace(regx,'"stream_mode":0'); 308 | // 弹个对话框检查下修改后的body 309 | FiddlerObject.alert(strBody); 310 | // 将修改后的body,重新写回Request中 311 | oSession.utilSetResponseBody(strBody); 312 | } 313 | */ 314 | 315 | /* 316 | //6.在此处修改json中的数据【修改接口字段的值】 317 | if(oSession.HostnameIs("i-play.mobile.youku.com") && oSession.url.IndexOf("/common/v5/play") > -1){ 318 | // 获取Response Body中JSON字符串 319 | var responseStringOriginal = oSession.GetResponseBodyAsString(); 320 | // 转换为可编辑的JSONObject变量 321 | var responseJSON = Fiddler.WebFormats.JSON.JsonDecode(responseStringOriginal); 322 | // 修改JSONObject变量,修改字段数据 323 | responseJSON.JSONObject["new_core"] = "True"; 324 | responseJSON.JSONObject["stream_mode"] = 5; 325 | // 重新设置Response Body 326 | var responseStringDestinal = Fiddler.WebFormats.JSON.JsonEncode(responseJSON.JSONObject); 327 | oSession.utilSetResponseBody(responseStringDestinal); 328 | } 329 | */ 330 | 331 | 332 | 333 | //7.在此处修改json中的数据【增加接口字段=值】 334 | if(oSession.HostnameIs("i-play.mobile.youku.com") && oSession.url.IndexOf("/common/v5/play") > -1){ 335 | // 获取Response Body中JSON字符串 336 | var responseStringOriginal = oSession.GetResponseBodyAsString(); 337 | // 转换为可编辑的JSONObject变量 338 | var responseJSON = Fiddler.WebFormats.JSON.JsonDecode(responseStringOriginal); 339 | // 修改JSONObject变量,修改字段数据 340 | responseJSON.JSONObject["type_arr"] = ["bullet"]; 341 | // 重新设置Response Body 342 | var responseStringDestinal = Fiddler.WebFormats.JSON.JsonEncode(responseJSON.JSONObject); 343 | oSession.utilSetResponseBody(responseStringDestinal); 344 | } 345 | 346 | /* 347 | //8.修改系统弹幕的跳转方式【http://dmapp.youku.com/common/danmu/sysdmlist 】 348 | if(oSession.HostnameIs("dmapp.youku.com") && oSession.url.IndexOf("common/danmu/sysdmlist") > -1){ 349 | // 获取Response Body中JSON字符串 350 | var responseStringOriginal = oSession.GetResponseBodyAsString(); 351 | // 转换为可编辑的JSONObject变量 352 | var responseJSON = Fiddler.WebFormats.JSON.JsonDecode(responseStringOriginal); 353 | // 修改JSONObject变量,修改字段数据 354 | responseJSON.JSONObject["data"]["results"][0]["displayMethod"] = 2; 355 | // 重新设置Response Body 356 | var responseStringDestinal = Fiddler.WebFormats.JSON.JsonEncode(responseJSON.JSONObject); 357 | oSession.utilSetResponseBody(responseStringDestinal); 358 | }*/ 359 | /* 360 | 361 | //脚本9:该方法进行修改pdl首页状态显示内容 362 | if(oSession.HostnameIs("10.150.20.82:8092") && oSession.url.IndexOf("/userAccount/mainPage")>-1){ 363 | 364 | var res = oSession.GetResponseBodyAsString(); 365 | var resJson = Fiddler.WebFormats.JSON.JsonDecode(res); 366 | //借款状态:1未申请,2审核中,3审核通过,4审核被拒,6借款申请失败,7借款申请成功(待签约),8签 367 | var rand = randInt(1,8); 368 | if (rand == 5){ 369 | rand=1; 370 | } 371 | 372 | resJson.JSONObject['data']['loanStatus'] = rand; 373 | 374 | var newRes = Fiddler.WebFormats.JSON.JsonEncode(resJson.JSONObject); 375 | oSession.utilSetResponseBody(newRes); 376 | 377 | //FiddlerObject.alert(rand); 378 | 379 | } 380 | */ 381 | /* 382 | //脚本10:该方法进行修改pdl我的页面状态显示内容 383 | if(oSession.HostnameIs("hoat") && oSession.url.IndexOf("/userAccount/findCreditAmount")>-1){ 384 | var res = oSession.GetResponseBodyAsString(); 385 | var resJson = Fiddler.WebFormats.JSON.JsonDecode(res); 386 | //前端按钮显示类型(0:立即验证身份,获取额度;1:立即借款;2:立即还款;3:在途) 387 | var rand = randInt(0,3); 388 | if(rand == 2){ 389 | //FiddlerObject.alert(rand); 390 | rand = 3; 391 | } 392 | resJson.JSONObject['data']['showType'] = rand; 393 | var newRes = Fiddler.WebFormats.JSON.JsonEncode(resJson.JSONObject); 394 | oSession.utilSetResponseBody(newRes); 395 | 396 | }*/ 397 | 398 | /* 399 | //脚本11:主要验证版本升级接口对应客户端的功能 400 | if(oSession.HostnameIs("host") && oSession.url.IndexOf("/getAppVersionInfo")>-1){ 401 | //var res = oSession.GetResponseBodyAsString(); 402 | 403 | var jsondata = '{"data": {"newestUrl": "url","newestVersion": "1.0.1","upgradeContent": "测试描述:版本升级","upgradeType": "1"},"message": "操作成功","status": "000000"}'; 404 | var resJson = Fiddler.WebFormats.JSON.JsonDecode(jsondata); 405 | var newRes = Fiddler.WebFormats.JSON.JsonEncode(resJson.JSONObject); 406 | 407 | oSession.utilSetResponseBody(newRes); 408 | 409 | }*/ 410 | 411 | } 412 | 413 | /* 414 | // This function executes just before Fiddler returns an error that it has 415 | // itself generated (e.g. "DNS Lookup failure") to the client application. 416 | // These responses will not run through the OnBeforeResponse function above. 417 | static function OnReturningError(oSession: Session) { 418 | } 419 | */ 420 | /* 421 | // This function executes after Fiddler finishes processing a Session, regardless 422 | // of whether it succeeded or failed. Note that this typically runs AFTER the last 423 | // update of the Web Sessions UI listitem, so you must manually refresh the Session's 424 | // UI if you intend to change it. 425 | static function OnDone(oSession: Session) { 426 | } 427 | */ 428 | 429 | /* 430 | static function OnBoot() { 431 | MessageBox.Show("Fiddler has finished booting"); 432 | System.Diagnostics.Process.Start("iexplore.exe"); 433 | 434 | UI.ActivateRequestInspector("HEADERS"); 435 | UI.ActivateResponseInspector("HEADERS"); 436 | } 437 | */ 438 | 439 | /* 440 | static function OnBeforeShutdown(): Boolean { 441 | // Return false to cancel shutdown. 442 | return ((0 == FiddlerApplication.UI.lvSessions.TotalItemCount()) || 443 | (DialogResult.Yes == MessageBox.Show("Allow Fiddler to exit?", "Go Bye-bye?", 444 | MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2))); 445 | } 446 | */ 447 | 448 | /* 449 | static function OnShutdown() { 450 | MessageBox.Show("Fiddler has shutdown"); 451 | } 452 | */ 453 | 454 | /* 455 | static function OnAttach() { 456 | MessageBox.Show("Fiddler is now the system proxy"); 457 | } 458 | */ 459 | 460 | /* 461 | static function OnDetach() { 462 | MessageBox.Show("Fiddler is no longer the system proxy"); 463 | } 464 | */ 465 | 466 | // The Main() function runs everytime your FiddlerScript compiles 467 | static function Main() { 468 | var today: Date = new Date(); 469 | FiddlerObject.StatusText = " CustomRules.js was loaded at: " + today; 470 | 471 | // Uncomment to add a "Server" column containing the response "Server" header, if present 472 | // UI.lvSessions.AddBoundColumn("Server", 50, "@response.server"); 473 | 474 | // Uncomment to add a global hotkey (Win+G) that invokes the ExecAction method below... 475 | // UI.RegisterCustomHotkey(HotkeyModifiers.Windows, Keys.G, "screenshot"); 476 | } 477 | 478 | // These static variables are used for simple breakpointing & other QuickExec rules 479 | BindPref("fiddlerscript.ephemeral.bpRequestURI") 480 | public static var bpRequestURI:String = null; 481 | 482 | BindPref("fiddlerscript.ephemeral.bpResponseURI") 483 | public static var bpResponseURI:String = null; 484 | 485 | BindPref("fiddlerscript.ephemeral.bpMethod") 486 | public static var bpMethod: String = null; 487 | 488 | static var bpStatus:int = -1; 489 | static var uiBoldURI: String = null; 490 | static var gs_ReplaceToken: String = null; 491 | static var gs_ReplaceTokenWith: String = null; 492 | static var gs_OverridenHost: String = null; 493 | static var gs_OverrideHostWith: String = null; 494 | 495 | // The OnExecAction function is called by either the QuickExec box in the Fiddler window, 496 | // or by the ExecAction.exe command line utility. 497 | static function OnExecAction(sParams: String[]): Boolean { 498 | 499 | FiddlerObject.StatusText = "ExecAction: " + sParams[0]; 500 | 501 | var sAction = sParams[0].toLowerCase(); 502 | switch (sAction) { 503 | case "bold": 504 | if (sParams.Length<2) {uiBoldURI=null; FiddlerObject.StatusText="Bolding cleared"; return false;} 505 | uiBoldURI = sParams[1]; FiddlerObject.StatusText="Bolding requests for " + uiBoldURI; 506 | return true; 507 | case "bp": 508 | FiddlerObject.alert("bpu = breakpoint request for uri\nbpm = breakpoint request method\nbps=breakpoint response status\nbpafter = breakpoint response for URI"); 509 | return true; 510 | case "bps": 511 | if (sParams.Length<2) {bpStatus=-1; FiddlerObject.StatusText="Response Status breakpoint cleared"; return false;} 512 | bpStatus = parseInt(sParams[1]); FiddlerObject.StatusText="Response status breakpoint for " + sParams[1]; 513 | return true; 514 | case "bpv": 515 | case "bpm": 516 | if (sParams.Length<2) {bpMethod=null; FiddlerObject.StatusText="Request Method breakpoint cleared"; return false;} 517 | bpMethod = sParams[1].toUpperCase(); FiddlerObject.StatusText="Request Method breakpoint for " + bpMethod; 518 | return true; 519 | case "bpu": 520 | if (sParams.Length<2) {bpRequestURI=null; FiddlerObject.StatusText="RequestURI breakpoint cleared"; return false;} 521 | bpRequestURI = sParams[1]; 522 | FiddlerObject.StatusText="RequestURI breakpoint for "+sParams[1]; 523 | return true; 524 | case "bpa": 525 | case "bpafter": 526 | if (sParams.Length<2) {bpResponseURI=null; FiddlerObject.StatusText="ResponseURI breakpoint cleared"; return false;} 527 | bpResponseURI = sParams[1]; 528 | FiddlerObject.StatusText="ResponseURI breakpoint for "+sParams[1]; 529 | return true; 530 | case "overridehost": 531 | if (sParams.Length<3) {gs_OverridenHost=null; FiddlerObject.StatusText="Host Override cleared"; return false;} 532 | gs_OverridenHost = sParams[1].toLowerCase(); 533 | gs_OverrideHostWith = sParams[2]; 534 | FiddlerObject.StatusText="Connecting to [" + gs_OverrideHostWith + "] for requests to [" + gs_OverridenHost + "]"; 535 | return true; 536 | case "urlreplace": 537 | if (sParams.Length<3) {gs_ReplaceToken=null; FiddlerObject.StatusText="URL Replacement cleared"; return false;} 538 | gs_ReplaceToken = sParams[1]; 539 | gs_ReplaceTokenWith = sParams[2].Replace(" ", "%20"); // Simple helper 540 | FiddlerObject.StatusText="Replacing [" + gs_ReplaceToken + "] in URIs with [" + gs_ReplaceTokenWith + "]"; 541 | return true; 542 | case "allbut": 543 | case "keeponly": 544 | if (sParams.Length<2) { FiddlerObject.StatusText="Please specify Content-Type to retain during wipe."; return false;} 545 | UI.actSelectSessionsWithResponseHeaderValue("Content-Type", sParams[1]); 546 | UI.actRemoveUnselectedSessions(); 547 | UI.lvSessions.SelectedItems.Clear(); 548 | FiddlerObject.StatusText="Removed all but Content-Type: " + sParams[1]; 549 | return true; 550 | case "stop": 551 | UI.actDetachProxy(); 552 | return true; 553 | case "start": 554 | UI.actAttachProxy(); 555 | return true; 556 | case "cls": 557 | case "clear": 558 | UI.actRemoveAllSessions(); 559 | return true; 560 | case "g": 561 | case "go": 562 | UI.actResumeAllSessions(); 563 | return true; 564 | case "goto": 565 | if (sParams.Length != 2) return false; 566 | Utilities.LaunchHyperlink("http://www.google.com/search?hl=en&btnI=I%27m+Feeling+Lucky&q=" + Utilities.UrlEncode(sParams[1])); 567 | return true; 568 | case "help": 569 | Utilities.LaunchHyperlink("http://fiddler2.com/r/?quickexec"); 570 | return true; 571 | case "hide": 572 | UI.actMinimizeToTray(); 573 | return true; 574 | case "log": 575 | FiddlerApplication.Log.LogString((sParams.Length<2) ? "User couldn't think of anything to say..." : sParams[1]); 576 | return true; 577 | case "nuke": 578 | UI.actClearWinINETCache(); 579 | UI.actClearWinINETCookies(); 580 | return true; 581 | case "screenshot": 582 | UI.actCaptureScreenshot(false); 583 | return true; 584 | case "show": 585 | UI.actRestoreWindow(); 586 | return true; 587 | case "tail": 588 | if (sParams.Length<2) { FiddlerObject.StatusText="Please specify # of sessions to trim the session list to."; return false;} 589 | UI.TrimSessionList(int.Parse(sParams[1])); 590 | return true; 591 | case "quit": 592 | UI.actExit(); 593 | return true; 594 | case "dump": 595 | UI.actSelectAll(); 596 | UI.actSaveSessionsToZip(CONFIG.GetPath("Captures") + "dump.saz"); 597 | UI.actRemoveAllSessions(); 598 | FiddlerObject.StatusText = "Dumped all sessions to " + CONFIG.GetPath("Captures") + "dump.saz"; 599 | return true; 600 | 601 | default: 602 | if (sAction.StartsWith("http") || sAction.StartsWith("www.")) { 603 | System.Diagnostics.Process.Start(sParams[0]); 604 | return true; 605 | } 606 | else 607 | { 608 | FiddlerObject.StatusText = "Requested ExecAction: '" + sAction + "' not found. Type HELP to learn more."; 609 | return false; 610 | } 611 | } 612 | } 613 | } --------------------------------------------------------------------------------