一、使用.NET代码扩展Fiddler
使用Fiddler的可扩展性机制添加到Fiddler的UI,自动修改请求或响应,并创建自定义检查器,以启用特定于方案的显示和手动修改请求和响应。
要求
- Visual Studio .NET 2005+或免费的.NET Framework v2命令行编译器
- Fiddler的最新版本
- 对于Visual Studio 2010或更高版本:将项目更改为以.NET2.0 / 3.5框架为目标。
- 如果以.NET Framework 3.5为目标:确保用户已安装.NET Framework 3.5。
- 如果扩展64位Fiddler:Target AnyCPU。
调试
- 为了确保异常和其他扩展相关的错误不默默地抓住:设置在fiddler.debug.extensions.showerrors偏好真。
- 为了输出信息记录到日志标签:设置在fiddler.debug.extensions.verbose
直接Fiddler加载扩展程序集
-
要使扩展可供计算机上的所有用户使用,请将扩展程序集DLL安装到:
%Program Files%\Fiddler2\Scripts
-
要使扩展仅对当前用户可用,请将扩展程序集DLL安装到:
%USERPROFILE%\My Documents\Fiddler2\Scripts
-
在AssemblyInfo.cs文件(或代码中的其他位置)中设置Fiddler.RequiredVersion属性,如下所示:
using Fiddler; // Extension requires Fiddler 2.2.8.6+ because it uses types introduced in v2.2.8... [assembly: Fiddler.RequiredVersion("2.2.8.6")]
示例扩展:一步一步
-
启动Visual Studio 2005或更高版本。
-
创建一个Visual C#类库类型的新项目。
-
在解决方案资源管理器中右键单击项目的References文件夹。
-
单击“ 浏览”选项卡,然后在C:\ Program Files \ Fiddler2文件夹中选择Fiddler.exe。
-
单击“ 确定”以添加引用。
-
如果您的扩展程序修改了Fiddler的UI:
- 再次右键单击解决方案资源管理器中项目的References文件夹
- 在.NET选项卡上,选择System.Windows.Forms。
- 单击“确定”以添加引用。
- 在解决方案资源管理器中,右键单击该项目。选择属性。
-
在“构建事件”选项卡上,将以下内容添加到“构建后事件”命令行:
复制“$(TargetPath)”“%userprofile%\ My Documents \ Fiddler2 \ Scripts \ $(TargetFilename)”
修改项目中的默认class1.cs(或创建一个新类),如下所示:
using System; using System.Windows.Forms; using Fiddler; [assembly: Fiddler.RequiredVersion("2.3.5.0")] public class Violin : IAutoTamper // Ensure class is public, or Fiddler won't see it! { string sUserAgent = ""; public Violin(){ /* NOTE: It's possible that Fiddler UI isn't fully loaded yet, so don't add any UI in the constructor. But it's also possible that AutoTamper* methods are called before onl oad (below), so be sure any needed data structures are initialized to safe values here in this constructor */ sUserAgent = "Violin"; } public void onl oad(){ /* Load your UI here */ } public void OnBeforeUnload() { } public void AutoTamperRequestBefore(Session oSession){ oSession.oRequest["User-Agent"] = sUserAgent; } public void AutoTamperRequestAfter(Session oSession){} public void AutoTamperResponseBefore(Session oSession){} public void AutoTamperResponseAfter(Session oSession){} public void OnBeforeReturningError(Session oSession){} }
二、
实现Fiddler接口
在Fiddler执行期间实现Fiddler接口以加载程序集。
启动期间的负载扩展
实现IFiddlerExtension接口的程序集中的公共类将在启动期间由Fiddler加载。
public interface IFiddlerExtension { // Called when Fiddler User Interface is fully available void onl oad(); // Called when Fiddler is shutting down void OnBeforeUnload(); }
-
该的OnLoad当小提琴手加载完成其UI是完全可用的功能将被调用。此时,您可以安全地将菜单项,选项卡式页面或其他元素添加到Fiddler UI。
-
该OnBeforeUnload函数将被调用时,提琴手被关闭和卸载所有扩展。
每个Web请求的呼叫扩展
-
为每个HTTP / HTTPS请求和响应调用实现IAutoTamper接口(扩展IFiddlerExtension)的扩展,从而启用修改,日志记录或其他操作。
警告:此接口中的函数在后台非UI线程上调用。要更新UI,请使用 Invoke或 BeginInvoke更新UI。另请注意,可以在调用 OnLoad事件之前调用IAutoTamper :: *函数 -Fiddler允许流量在UI完全可用之前流动。
public interface IAutoTamper : IFiddlerExtension { // Called before the user can edit a request using the Fiddler Inspectors void AutoTamperRequestBefore(Session oSession); // Called after the user has had the chance to edit the request using the Fiddler Inspectors, but before the request is sent void AutoTamperRequestAfter(Session oSession); // Called before the user can edit a response using the Fiddler Inspectors, unless streaming. void AutoTamperResponseBefore(Session oSession); // Called after the user edited a response using the Fiddler Inspectors. Not called when streaming. void AutoTamperResponseAfter(Session oSession); // Called Fiddler returns a self-generated HTTP error (for instance DNS lookup failed, etc) void OnBeforeReturningError(Session oSession); }
-
当响应头可用时,将调用实现IAutoTamper2接口(扩展IAutoTamper)的扩展。
/// <summary> /// Interface for AutoTamper extensions that want to "peek" at response headers /// </summary> public interface IAutoTamper2 : IAutoTamper { /// <summary> /// Called when the response headers become available /// </summary> /// <param name="oSession">The Session object for which the response headers are available</param> void OnPeekAtResponseHeaders(Session oSession); }
-
当请求标头可用时,将调用实现IAutoTamper3接口(扩展IAutoTamper2)的扩展。
/// <summary> /// Interface for AutoTamper extensions that want to "peek" at request headers /// </summary> public interface IAutoTamper3 : IAutoTamper2 { /// <summary> /// Called when the request headers become available /// </summary> /// <param name="oSession">The Session object for which the request headers are available</param> void OnPeekAtRequestHeaders(Session oSession); }
用户进入QuickExec命令时调用扩展
-
当用户在QuickExec框中输入命令时,将调用实现IHandleExecAction接口的扩展。要对命令作出反应(并防止其他扩展和Fiddler本身进一步处理),请从此方法返回true。
public interface IHandleExecAction { // return TRUE if handled. bool OnExecAction(string sCommand); }
-
Fiddler.Utilities类包含一个辅助函数Parameterize(),它有助于解释sCommand参数。
[CodeDescription("Tokenize a string into tokens. Delimits on whitespace; Quotation marks are dropped unless preceded by a \ character.")] public static string[] Parameterize(string sCommand)
三、创建Fiddler扩展项目
按照以下步骤创建示例Fiddler扩展,修改所有出站请求的User-Agent字符串:
添加对Fiddler的引用
-
启动Visual Studio 2005或更高版本。
-
创建一个Visual C#类库类型的新项目。
-
在解决方案资源管理器中右键单击项目的References文件夹。
-
单击“ 浏览”选项卡,然后在C:\ Program Files \ Fiddler2文件夹中选择Fiddler.exe。
-
单击“ 确定”以添加引用。
添加对System.Windows.Forms的引用
如果您的扩展程序修改了Fiddler的UI:
-
再次右键单击解决方案资源管理器中项目的References文件夹。
-
在.NET选项卡上,选择System.Windows.Forms。
-
单击“ 确定”以添加引用。
添加构建事件
-
在解决方案资源管理器中,右键单击该项目。
-
单击属性。
-
单击“ 构建事件”选项卡。
-
将以下内容添加到Post-build事件命令行:
copy "$(TargetPath)" "%userprofile%\My Documents\Fiddler2\Scripts\$(TargetFilename)"
实现Fiddler接口
修改项目中的默认class1.cs(或创建一个新类),如下所示:
using System; using System.Windows.Forms; using Fiddler; [assembly: Fiddler.RequiredVersion("2.3.5.0")] public class Violin : IAutoTamper // Ensure class is public, or Fiddler won't see it! { string sUserAgent = ""; public Violin(){ /* NOTE: It's possible that Fiddler UI isn't fully loaded yet, so don't add any UI in the constructor. But it's also possible that AutoTamper* methods are called before onl oad (below), so be sure any needed data structures are initialized to safe values here in this constructor */ sUserAgent = "Violin"; } public void onl oad(){ /* Load your UI here */ } public void OnBeforeUnload() { } public void AutoTamperRequestBefore(Session oSession){ oSession.oRequest["User-Agent"] = sUserAgent; } public void AutoTamperRequestAfter(Session oSession){} public void AutoTamperResponseBefore(Session oSession){} public void AutoTamperResponseAfter(Session oSession){} public void OnBeforeReturningError(Session oSession){} }
请参阅Fiddler接口。
编译和加载扩展
四、在扩展程序选项卡中添加一个图标
使用现有图标
设置.ImageIndex属性,如下所示:
public void onl oad() { oPage = new TabPage("Timeline"); oPage.ImageIndex = (int)Fiddler.SessionIcons.Timeline; oView = new TimelineView(); oPage.Controls.Add(oView); oView.Dock = DockStyle.Fill; FiddlerApplication.UI.tabsViews.TabPages.Add(oPage); }
添加自定义图像
-
将图像添加到imglSessionIcons。
-
设置.ImageIndex属性,如下所示:
public void onl oad() { oPage = new TabPage("Timeline"); oPage.ImageIndex = (int)Fiddler.SessionIcons.Timeline; oView = new TimelineView(); oPage.Controls.Add(oView); oView.Dock = DockStyle.Fill; FiddlerApplication.UI.tabsViews.TabPages.Add(oPage); }
五、在Fiddler中加载扩展
-
编译您的项目。
-
将程序集.DLL复制到正确的Scripts文件夹:
-
使用\ My Documents \ Fiddler2 \ Scripts使扩展可供当前用户使用。
-
使用\ Program Files \ Fiddler2 \ Scripts使扩展可供计算机上的所有用户使用。
-
-
重启Fiddler。
六、构建自定义检查器
-
创建一个Fiddler扩展项目。
-
更改代码以从Inspector2类派生并实现IResponseInspector2或IRequestInspector2。
using Fiddler; [assembly: Fiddler.RequiredVersion("2.3.0.0")] public class WebViewer: Inspector2, IResponseInspector2 { public Viewers() { // // TODO: Add constructor logic here // } }
-
在课堂内,创建一个新方法。通过键入公共覆盖,您将获得需要编写的方法的自动完成列表。
-
在解决方案资源管理器中,右键单击项目,然后单击添加>用户控件。
-
使用工具箱将控件添加到用户控件。这些将显示有关正在检查的HTTP消息的数据。
-
在body {set}和headers {set}属性中,您应该更新控件的请求或响应的可视化表示。
七、导入器和导出器接口
线程安全和FiddlerCore
-
目前,在MAIN UI线程上调用ISessionImporter和ISessionExporter接口。这几乎肯定会在将来发生变化,因此您应该确保您的类是线程安全的,并且他们不会尝试直接操作Fiddler UI。
-
对Fiddler UI的操纵还是不明智的,因为Fiddler本身可能无法加载; FiddlerCore可能直接托管您的进口商/出口商。为了支持FiddlerCore,建议您在dictOptions参数中支持Filename键(具有完全限定路径的字符串值),并考虑支持Silent键(值为boolean)。
ISessionImporter接口
当用户使用“ 文件”>“导入”菜单选项时,将调用实现ISessionImporter接口(实现IDisposable接口)的扩展。
public interface ISessionImporter : IDisposable { Session[] ImportSessions(string sImportFormat, Dictionary<string, object> dictOptions, EventHandler<ProgressCallbackEventArgs> evtProgressNotifications); }
该方法返回从导入数据创建的Session对象数组。
所述dictOptions字典可以为空,也可以含有一组字符串键控对象。大多数进口商都支持文件名的规范。例如:
dictOptions["Filename"] = "C:\\test.file"
ISessionExporter接口
此类由Fiddler定义,允许您报告导入或导出操作的进度。
如果无法确定完成率,只需传递0或0到1.0之间的“猜测”。
如果在传递给evtProgressNotifications回调后在ProgressCallbackEventArgs对象上设置了Cancel标志,则导入或导出应该尽快正常终止。
public class ProgressCallbackEventArgs: EventArgs { public ProgressCallbackEventArgs(float flCompletionRatio, string sProgressText) public string ProgressText { get; } public string PercentComplete { get; } public bool Cancel { get; set; } }
八、
构建自定义导入程序或导出程序
样本扩展
-
创建一个Fiddler扩展项目。
-
修改项目中的默认class1.cs(或创建一个新类),如下所示:
using System; using System.IO; using System.Text; using System.Windows.Forms; using Fiddler; using System.Diagnostics; using System.Reflection; [assembly: AssemblyVersion("1.0.0.0")] [assembly: Fiddler.RequiredVersion("2.4.0.0")] [ProfferFormat("TAB-Separated Values", "Session List in Tab-Delimited Format")] [ProfferFormat("Comma-Separated Values", "Session List in Comma-Delimited Format; import into Excel or other tools")] public class CSVTranscoder: ISessionExporter // Ensure class is public, or Fiddler won't see it! { public bool ExportSessions(string sFormat, Session[] oSessions, Dictionary<string, object> dictOptions, EventHandler<ProgressCallbackEventArgs> evtProgressNotifications) { bool bResult = false; string chSplit; // Determine if we already have a filename from the dictOptions collection string sFilename = null; if (null != dictOptions && dictOptions.ContainsKey("Filename")) { sFilename = dictOptions["Filename"] as string; } if (sFormat == "Comma-Separated Values") { chSplit = ","; if (string.IsNullOrEmpty(sFilename)) sFilename = Fiddler.Utilities.ObtainSaveFilename("Export As " + sFormat, "CSV Files (*.csv)|*.csv"); } else { chSplit = "\t"; if (string.IsNullOrEmpty(sFilename)) sFilename = Fiddler.Utilities.ObtainSaveFilename("Export As " + sFormat, "TSV Files (*.tsv)|*.tsv"); } if (String.IsNullOrEmpty(sFilename)) return false; try { StreamWriter swOutput = new StreamWriter(sFilename, false, Encoding.UTF8); int iCount = 0; int iMax = oSessions.Length; #region WriteColHeaders bool bFirstCol = true; foreach (ColumnHeader oLVCol in FiddlerApplication.UI.lvSessions.Columns) { if (!bFirstCol) { swOutput.Write(chSplit); } else { bFirstCol = false; } swOutput.Write(oLVCol.Text.Replace(chSplit, "")); } swOutput.WriteLine(); #endregion WriteColHeaders #region WriteEachSession foreach (Session oS in oSessions) { iCount++; if (null != oS.ViewItem) { bFirstCol = true; ListViewItem oLVI = (oS.ViewItem as ListViewItem); if (null == oLVI) continue; foreach (ListViewItem.ListViewSubItem oLVC in oLVI.SubItems) { if (!bFirstCol) { swOutput.Write(chSplit); } else { bFirstCol = false; } swOutput.Write(oLVC.Text.Replace(chSplit,""));} swOutput.WriteLine();}if(null!= evtProgressNotifications){ evtProgressNotifications(null,newProgressCallbackEventArgs(,));ProgressCallbackEventArgs PCEA =newProgressCallbackEventArgs((iCount/(float)iMax),"wrote "+ iCount.ToString()+" records."); evtProgressNotifications(null, PCEA);if(PCEA.Cancel){ swOutput.Close();returnfalse;}}}#endregion WriteEachSession swOutput.Close(); bResult =true;}catch(Exception eX){MessageBox.Show(eX.Message,"Failed to export"); bResult =false;}}return bResult;}publicvoidDispose(){}}
也可以看看
九、将参数传递给Importer或Exporter Extension
-
转码器(实现导入器或导出器接口的对象)可以在字典对象中传递参数。例如,FiddlerScript可以调用HTTPArchive转码器,传递文件名字符串和最大响应大小整数,如下所示:
var oSessions = FiddlerApplication.UI.GetAllSessions(); var oExportOptions = FiddlerObject.createDictionary(); oExportOptions.Add("Filename", "C:\\users\\ericlaw\\desktop\\out1.har"); oExportOptions.Add("MaxTextBodyLength", 1024); oExportOptions.Add("MaxBinaryBodyLength", 16384); FiddlerApplication.DoExport("HTTPArchive v1.2", oSessions, oExportOptions, null);
-
代码转换器扩展可以按如下方式收集这些选项:
public bool ExportSessions(string sFormat, Session[] oSessions, Dictionary<string, object> dictOptions, EventHandler<ProgressCallbackEventArgs> evtProgressNotifications) { //... if (null != dictOptions) { if (dictOptions.ContainsKey("Filename")) { sFilename = dictOptions["Filename"] as string; } if (dictOptions.ContainsKey("MaxTextBodyLength")) { iMaxTextBodyLength = (int)dictOptions["MaxTextBodyLength"]; } if (dictOptions.ContainsKey("MaxBinaryBodyLength")) { iMaxBinaryBodyLength = (int)dictOptions["MaxBinaryBodyLength"]; } }
十、为Fiddler v2和v4构建扩展程序集
-
如果您希望扩展程序集在Fiddler2和Fiddler4中运行,请为.NET Framework v2构建它,并避免对在更高版本的Framework中删除或移动的任何类具有任何依赖性。(我所知道的唯一一个实例是Microsoft JScript.NET代码编译器,其类移动了一下)。
您还需要确保如果使用任何不推荐使用的方法(例如,使用带有Evidence参数的重载调用Assembly.LoadFrom),则只能有条件地执行此操作。例如:
if (CONFIG.bRunningOnCLRv4) { a = Assembly.LoadFrom(oFile.FullName); } else { a = Assembly.LoadFrom(oFile.FullName, evidenceFiddler); }
来自Fiddler网站的所有扩展都是针对Fiddler v2编译的。
-
或者,您可以简单地构建两个版本的DLL,一个版本针对.NET Framework v4,另一个针对.NET Framework v2。
这就是Fiddler本身的构建方式。基本上,只需将v2目标项目的“克隆”版本添加到同一解决方案中。使用“ 添加”>“现有项”上下文菜单将.CS文件从以v2为目标的项目添加到以v4为目标的项目,但在选择文件时,请务必使用文件选取器对话框中的拆分按钮,然后选择“ 添加为”。链接。在v4项目的“ 属性”>“构建”选项卡上,添加像DOTNET4这样的条件编译符号。然后,您可以将任何特定于.NETv4的代码置于条件编译之后:
#if DOTNET4 // ... code targeting .NETv4 #else // ... code targeting .NETv2 #endif
您的扩展程序可能会根据在其中找到的InstalledVersion注册表项的内容安装适当目标的版本:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fiddler2
.NET2版的Fiddler目前比.NETv4版本更受欢迎。当.NET Framework v4.5发布时,我可能会将v4项目移到v4.5。除此之外,这将允许我在后面的框架中利用新的内置.ZIP类。
-
RequiredVersion属性怎么样?
Fiddler v4是“聪明的” - 如果您的扩展指定
[assembly: Fiddler.RequiredVersion("2.1.0.1")]
当Fiddler v4加载它时,它将需要4.3.9.9或更高版本。
十一、
示例扩展
要查看一些示例扩展,请查看Fiddler Add-Ons页面或Privacy Scanner Add-On代码。
十二、向Fiddler添加规则
自定义规则
要将自定义列添加到Fiddler UI,修改请求或响应,测试应用程序性能以及各种其他自定义任务,请在FiddlerScript中向Fiddler的JScript.NET CustomRules.js文件添加规则。
-
按此规则>自定义规则...。
-
在相应的函数内输入FiddlerScript代码。
-
保存文件。
Fiddler会自动重新加载规则。
使用其他.NET程序集
要在脚本中使用其他.NET程序集:
-
单击工具>提琴选项。
-
单击“ 扩展”选项卡。
-
编辑参考列表。
-
或者:
-
在GAC中注册程序集; 要么
-
将程序集复制到包含Fiddler.exe的文件夹。
-
要在不完全限定它们的情况下使用新程序集的函数,请更新脚本顶部的#import子句。
更改从“ 规则”菜单启动的JScript编辑器
-
单击工具>提琴选项。
-
编辑编辑器字符串。
恢复默认规则
-
删除〜/ Documents / Fiddler2 / Scripts中的CustomRules.js文件。
-
重启Fiddler。
注意:Fiddler的默认规则存储在〜/ Program Files / Fiddler2 / Scripts / SampleRules.js中。
十三、添加菜单项
要将菜单操作添加到“ 工具”菜单或上下文菜单,或者将选项添加到“ 规则”菜单:
-
创建并执行.REG文件,如下所示:
[HKEY_CURRENT_USER\Software\Microsoft\Fiddler2\MenuExt\&YourMenuItemName] "Command"="YourExeName.exe" "Parameters"="Your Parameters To Pass To The EXE"
-
重启Fiddler。
十四、在FiddlerScript中使用.NET程序集
要使用.NET插件(对于此示例,修改用户代理字符串的C#插件):
添加参考
-
关闭提琴手。
-
保存.NET文件(例如,此文件名为UASimulator.cs):
using System; using System.Windows.Forms; using Fiddler; namespace FiddlerUtility{ public class UASimulator { string m_sUAString; public UASimulator(string s_UAString){ m_sUAString = s_UAString; } public bool OverwriteUA(Session oSession){ oSession.oRequest["User-Agent"] = m_sUAString; return true; } } }
-
在VS命令提示符下,转到找到.CS文件的文件夹。
-
输入命令以在VS命令提示符中创建DLL。例如:
csc /target:library /out:c:\UASim.dll UASimulator.cs /reference:"C:\program files\fiddler2\fiddler.exe"
-
在Fiddler中,单击工具> Fiddler选项。
-
单击“ 扩展”选项卡。
-
在“ 引用”字段中,输入DLL的位置。例如:
C:\UASim.dll
更新提琴手规则
向Fiddler添加规则以更新脚本。例如:
import System; import System.Windows.Forms; import Fiddler; import FiddlerUtility; class Handlers{ static var UASim = new UASimulator("Mozilla/12.0"); static function OnBeforeRequest(oSession:Fiddler.Session){ UASim.OverwriteUA(oSession); } static function Main(){ var today: Date = new Date(); FiddlerObject.StatusText = " CustomRules.js was loaded at: " + today; } }
十五、
构建Cookie扫描扩展
以下是Fiddler Privacy Scanner插件的代码。
using System; using System.Collections; using System.Globalization; using System.Collections.Generic; using System.Windows.Forms; using System.Text; using Fiddler; using System.IO; using System.Diagnostics; using Microsoft.Win32; using System.Reflection; using System.Text.RegularExpressions; [assembly: Fiddler.RequiredVersion("2.3.9.0")] [assembly: AssemblyVersion("1.0.1.0")] [assembly: AssemblyTitle("PrivacyScanner")] [assembly: AssemblyDescription("Scans for Cookies and P3P")] [assembly: AssemblyCompany("Eric Lawrence")] [assembly: AssemblyProduct("PrivacyScanner")] public class TagCookies : IAutoTamper2 { private bool bEnabled = false; private bool bEnforceP3PValidity = false; private bool bCreatedColumn = false; private System.Windows.Forms.MenuItem miEnabled; private System.Windows.Forms.MenuItem miEnforceP3PValidity; private System.Windows.Forms.MenuItem mnuCookieTag; public void onl oad() { /* * NB: You might not get called here until ~after~ one of the AutoTamper methods was called. * This is okay for us, because we created our mnuContentBlock in the constructor and its simply not * visible anywhere until this method is called and we merge it onto the Fiddler Main menu. */ FiddlerApplication.UI.mnuMain.MenuItems.Add(mnuCookieTag); } public void OnBeforeUnload() { /*noop*/ } private void InitializeMenu() { this.miEnabled = new System.Windows.Forms.MenuItem("&Enabled"); this.miEnforceP3PValidity = new System.Windows.Forms.MenuItem("&Rename P3P header if invalid"); this.miEnabled.Index = 0; this.miEnforceP3PValidity.Index = 1; this.mnuCookieTag = new System.Windows.Forms.MenuItem(); this.mnuCookieTag.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { this.miEnabled, this.miEnforceP3PValidity }); this.mnuCookieTag.Text = "Privacy"; this.miEnabled.Click += new System.EventHandler(this.miEnabled_Click); this.miEnabled.Checked = bEnabled; this.miEnforceP3PValidity.Click += new System.EventHandler(this.miEnforceP3PValidity_Click); this.miEnforceP3PValidity.Checked = bEnforceP3PValidity; } public void miEnabled_Click(object sender, EventArgs e) { miEnabled.Checked = !miEnabled.Checked; bEnabled = miEnabled.Checked; this.miEnforceP3PValidity.Enabled = bEnabled; if (bEnabled) { EnsureColumn(); } FiddlerApplication.Prefs.SetBoolPref("extensions.tagcookies.enabled", bEnabled); }publicvoid miEnforceP3PValidity_Click(object sender,EventArgs e){ miEnforceP3PValidity.Checked=!miEnforceP3PValidity.Checked; bEnforceP3PValidity = miEnforceP3PValidity.Checked;FiddlerApplication.Prefs.SetBoolPref("extensions.tagcookies.EnforceP3PValidity", bEnforceP3PValidity);}privatevoidEnsureColumn(){if(bCreatedColumn)return;FiddlerApplication.UI.lvSessions.AddBoundColumn("Privacy Info",1,120,"X-Privacy"); bCreatedColumn =true;}publicTagCookies(){this.bEnabled =FiddlerApplication.Prefs.GetBoolPref("extensions.tagcookies.enabled",false);this.bEnforceP3PValidity =FiddlerApplication.Prefs.GetBoolPref("extensions.tagcookies.EnforceP3PValidity",true);InitializeMenu();if(bEnabled){EnsureColumn();}else{this.miEnforceP3PValidity.Enabled=false;}}privatevoidSetP3PStateFromHeader(string sValue,ref P3PState oP3PState){if(string.IsNullOrEmpty(sValue)){return;}string sUnsatCat =String.Empty;string sUnsatPurpose =String.Empty; sValue = sValue.Replace('\'','"');string sCP =null;Regex r =newRegex("CP\\s?=\\s?[\"]?(?<TokenValue>[^\";]*)");Match m = r.Match(sValue);if(m.Success&&(null!= m.Groups["TokenValue"])){ sCP = m.Groups["TokenValue"].Value;}if(String.IsNullOrEmpty(sCP)){return;}// Okay, we've got a compact policy token. oP3PState = P3PState.P3POk;string[] sTokens = sCP.Split(newchar[]{' '},StringSplitOptions.RemoveEmptyEntries);foreach(string sToken in sTokens){// Reject clearly invalid tokens...if((sToken.Length<3)||(sToken.Length>4)){ oP3PState = P3PState.P3PMalformed;return;}if(",PHY,ONL,GOV,FIN,".IndexOf(","+ sToken +",",StringComparison.OrdinalIgnoreCase)>-1){ sUnsatCat +=(sToken +" ");continue;}if(",SAM,OTR,UNR,PUB,IVA,IVD,CON,TEL,OTP,".IndexOf(","+ sToken +",",StringComparison.OrdinalIgnoreCase)>-1){ sUnsatPurpose +=(sToken +" ");continue;}// TODO: Look up the token in the complete collection and check validity}// If a cookie contains an unsatisfactory purpose and an unsatisfactory category, mark it// https://msdn.microsoft.com/en-us/library/ie/ms537343(v=vs.85).aspx#unsatisfactory_cookiesif((sUnsatCat.Length>0)&&(sUnsatPurpose.Length>0)){if(oP3PState == P3PState.P3POk){ oP3PState = P3PState.P3PUnsatisfactory;}}}privateenum P3PState {NoCookies,NoP3PAndSetsCookies, P3POk, P3PUnsatisfactory, P3PMalformed }publicvoidOnPeekAtResponseHeaders(Session oSession){if(!bEnabled)return; P3PState oP3PState = P3PState.NoCookies;if(!oSession.oResponse.headers.Exists("Set-Cookie")){return;} oP3PState = P3PState.NoP3PAndSetsCookies;if(oSession.oResponse.headers.Exists("P3P")){SetP3PStateFromHeader(oSession.oResponse.headers["P3P"],ref oP3PState);}switch(oP3PState){case P3PState.P3POk: oSession["ui-backcolor"]="#ACDC85"; oSession["X-Privacy"]="Sets cookies & P3P";break;case P3PState.NoP3PAndSetsCookies: oSession["ui-backcolor"]="#FAFDA4"; oSession["X-Privacy"]="Sets cookies without P3P";break;case P3PState.P3PUnsatisfactory: oSession["ui-backcolor"]="#EC921A"; oSession["X-Privacy"]="Sets cookies; P3P unsatisfactory for 3rd-party use";break;case P3PState.P3PMalformed: oSession["ui-backcolor"]="#E90A05";if(bEnforceP3PValidity){ oSession.oResponse.headers["MALFORMED-P3P"]= oSession.oResponse.headers["P3P"]; oSession["X-Privacy"]="MALFORMED P3P: "+ oSession.oResponse.headers["P3P"]; oSession.oResponse.headers.Remove("P3P");}break;}}publicvoidAutoTamperRequestBefore(Session oSession){}publicvoidAutoTamperRequestAfter(Session oSession){/*noop*/}publicvoidAutoTamperResponseAfter(Session oSession){/*noop*/}publicvoidAutoTamperResponseBefore(Session oSession){/*noop*/}publicvoidOnBeforeReturningError(Session oSession){/*noop*/}}