На Хабре уже неоднократно рассказывали о таком мощном и удобном средстве мониторинга HTTP-трафика, как Fiddler. Все имеющиеся статьи, однако, рассказывают о встроенных фичах программы, не акцентируя внимания на возможностях её расширения, которых существует целых две: с помощью встроенного языка FiddlerScript и с помощью написания .NET-плагинов. В этой статье мы рассмотрим и то, и другое, а чтобы было интереснее — используем их для решения вполне практической задачи, о которой я писал в своей прошлой статье (подмене битых ссылок на картинки в статьях на Хабре на рабочие).
Итак, давайте вспомним для начала, чем закончилась прошлая статья: мы получили список нерабочих ссылок на картинки и соответствующих им рабочих ссылок на веб-архиве. Теперь нужно отдать их браузеру и для этого мы напишем расширения к Fiddler (одно на FiddlerScript и одно на .NET). Обратите внимание на удобства полученного решения: да, нам нужно будет запустить Fiddler, но зато битые ссылки будут подменяться на рабочие независимо от домена статьи (хабр, гиктаймс или мегамозг), независимо от используемого браузера (лишь бы имел поддержку прокси) и даже мобильные устройства можно будет настроить на использование установленного на компьютере Fiddler в качестве прокси.
FiddlerScript
FiddlerScript — это встроенный в Fiddler язык программирования, основанный на JScript.NET, позволяющий анализировать и изменять входящий и исходящий траффик, расширять функциональность самого Fiddler, модифицировать его интерфейс.
Пара ссылок по теме:
- Хорошая вводная статья о FiddlerScript
- FiddlerScript Editor — редактор кода на FiddlerScript с подсветкой синтаксиса, автодополнением, браузером классов
Писать код нужно в файл, который открывается по клику в меню на Rules->Customize Rules. Если вдруг запорете его — просто удалите, Fiddler пересоздаст его из резервной копии.
Простейшая подмена одной ссылки на другую на FiddlerScript будет выглядеть как добавление в обработчик OnBeforeRequest вот такого кода:
static function OnBeforeRequest(oSession: Session) {
...
if (oSession.url=="www.example.com/bad_url.jpg") {
oSession.url = "www.example.com/good_url.jpg";
}
}
Нам нужно подменить 13863 ссылки. Писать такое лес «ифов» — малопродуктивно. Вспомним, что FiddlerScript основан на JScript.NET, JScript.NET — это .NET, а в .NET есть весьма производительные структуры данных для хранения набора строк и быстрого поиска по нему, в основе которого лежат хеш-таблицы. Да-да, я о StringDictionary.
Возьмём наши исходные данные и парой нехитрых операций по автозамене в любом текстовом редакторе с поддержкой регулярных выражений приведём его к виду:
myDict.Add("img224.imageshack.us/img224/410/yandexmoney7mg.gif", "web.archive.org/web/20060723135036/http://img224.imageshack.us:80/img224/410/yandexmoney7mg.gif");
myDict.Add("blaugh.com/wp-content/themes/blaugh/images/cartoon-gd_01.gif", "web.archive.org/web/20070703010741/http://blaugh.com/wp-content/themes/blaugh/images/cartoon-gd_01.gif");
myDict.Add("blaugh.com/cartoons/060712_google_life.gif", "web.archive.org/web/20120112151300/http://blaugh.com/cartoons/060712_google_life.gif");
...
Инициализировать словарь нужнов всего однажды (например, в обработчике OnBoot, а использовать при поиске его мы можем в каждом вызове OnBeforeRequest:
static var myDict: StringDictionary = null;
static function OnBoot() {
myDict = new StringDictionary();
myDict.Add("img224.imageshack.us/img224/410/yandexmoney7mg.gif", "web.archive.org/web/20060723135036/http://img224.imageshack.us:80/img224/410/yandexmoney7mg.gif");
myDict.Add("blaugh.com/wp-content/themes/blaugh/images/cartoon-gd_01.gif", "http://web.archive.org/web/20070703010741/http://blaugh.com/wp-content/themes/blaugh/images/cartoon-gd_01.gif");
myDict.Add("blaugh.com/cartoons/060712_google_life.gif", "http://web.archive.org/web/20120112151300/http://blaugh.com/cartoons/060712_google_life.gif");
....
}
...
static function OnBeforeRequest(oSession: Session) {
...
if (null != myDict && myDict.ContainsKey(oSession.url)) {
oSession.url = myDict[oSession.url];
}
}
Сохраняем, проверяем открытием статьи с битой ссылкой на картинку, видим картинку, которая без этой подмены была недоступна — ура, всё работает!
Написание .NET-плагина к Fiddler
Если вам не сильно понравилось писать код на странном языке JScript.NET в странном редакторе и запускать его странным способом копипасты в конфиг-файл, ожидая при этом по 30 сек, пока распарсится и скомпилируеся написанный нами скрипт — к вашим услугам вся мощь C#, .NET, Visual Studio и прочих радостей жизни!
Коротко о создании проекта:
1. Запускаем Visual Studio, создаём новый .NET-проект типа «Библиотека классов».
2. Если пишете под Fiddler 4 — выбирайте в свойствах проекта .NET версии 4, если под Fiddler 2 — .NET версии 3.5
3. Добавляйте в зависимости сам Fiddler (экзешник Fiddler.exe, лежащий в своей папке в Program Files).
4. В коде нужно указать, какую минимальную версию Fiddler вы поддерживаете:
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")]
5. Вам нужно написать класс, реализовывающий интерфейс IAutoTamper. События у него, в общем-то те же, что и были в нашем коде на FiddlerScript, поэтому вот он схематически:
using System;
using Fiddler;
using System.Collections.Specialized;
[assembly: Fiddler.RequiredVersion("2.3.5.0")]
public class HabraFixer : IAutoTamper // Ensure class is public, or Fiddler won't see it!
{
public HabraFixer()
{
}
public void OnLoad()
{
myDict = new StringDictionary();
myDict.Add("img224.imageshack.us/img224/410/yandexmoney7mg.gif", "web.archive.org/web/20060723135036/http://img224.imageshack.us:80/img224/410/yandexmoney7mg.gif");
myDict.Add("blaugh.com/wp-content/themes/blaugh/images/cartoon-gd_01.gif", "web.archive.org/web/20070703010741/http://blaugh.com/wp-content/themes/blaugh/images/cartoon-gd_01.gif");
myDict.Add("blaugh.com/cartoons/060712_google_life.gif", "web.archive.org/web/20120112151300/http://blaugh.com/cartoons/060712_google_life.gif");
...
}
public void OnBeforeUnload() { }
public void AutoTamperRequestBefore(Session oSession)
{
if (null != myDict && myDict.ContainsKey(oSession.url)) {
oSession.url = myDict[oSession.url];
}
}
public void AutoTamperRequestAfter(Session oSession) { }
public void AutoTamperResponseBefore(Session oSession) { }
public void AutoTamperResponseAfter(Session oSession) { }
public void OnBeforeReturningError(Session oSession) { }
private StringDictionary myDict;
}
Билдим, подкладываем сборку в %Program Files%Fiddler2Scripts (для всех пользователей) или в %USERPROFILE%My DocumentsFiddler2Scripts (только для текущего), запускаем Fiddler, проверяем — всё работает!
Вот так мы научились писать расширения для Fiddler.
Автор: tangro