Не только на питоне это делается ProxyAutoConfig.cpp - mozsearch
Я вижу несколько вариантов:
- разбить скрипт на несколько скриптов: отдельный скрипт для .ru зоны, отдельный для .com, отдельный для .org и т.д. Подгружать динамически в зависимости от запрашиваемого домена
- хранить в файле хеши в бинарном виде
- хранить в файле бинарный бор:
Если в списке домены “aaa”, “aab”, “aba”, “caa” то нужно хранить структуру вида
{“a”: {“a”: {“a”: true, “b”: true}, “b”: {“a”: true} }, “c”: {“a”: {“a”: true} } } - сжать список алгоритмом хаффмана (вариация бора когда преждевременно анализируем потенциально самые частоиспользуемые ребра)
Плюсы подхода 3 и 4 это то что мы явно не храним весь список и нам не нужно его полностью восстанавливать для проверки на вхождение. При этом не возможны коллизии.
Немного оффтоп. Но с чем связаны такие строгие ограничения на IE7 и Windows XP?
Казалось бы сами заблокирвоанные сайты не очень умеют с ним работать.
Для таких старых устройств есть смысл делать обход блокировки средствами роутера или гейтвея или через операционную систему, не через браузер
Такой возможности нет, PAC-файлы не могут загружать сторонние ресурсы.
Только ASCII 7-бит, не все браузеры поддерживают не-однобитные кодировки.
Сервисом до сих пор пользуются со старых компьютеров, не хотелось бы ломать доступ без сильной на то необходимости.
Но даже если ориентироваться на Windows 7 и его версию IE, там тоже не получится использовать современные технологии.
Я не знаю насколько моё мнение важно, но
Мне кажется что если выбирать между
- поддерживать для 99% пользователей (а есть ли статистика?) браузер которых выпущен в последние 2 года
- не поддерживать из-за 1% пользователей которые пользуются морально устаревшими технологиями
всегда нужно выбирать первое
В текущем виде выглядит расточительно, нужно придумывать алгоритм паковки данных.
Я думал для сжатия IP-адресов реализовать Elias gamma coding.
Пользователи, добавляющие PAC-файл в ОС, начинают использовать его в браузере ОС (старые версии IE и wininet, основанный на нём).
Как насчёт взять GitHub - LZMA-JS/LZMA-JS: A JavaScript implementation of the Lempel-Ziv-Markov (LZMA) chain compression algorithm (декомпрессор весит 6.8 КБ) и зипануть все домены?
кстати, а если выделить в общую кучу Cloudflare, по идее его может быть довольно много (из-за казино), и заменить общим правилом “если адрес ресолвится в клаудфлер, то проксировать”
Нельзя ли на сервере проверять домены по тому же фильтру?
Здесь уместен вопрос. Дергается ли прокси пак каждый раз при обращении к URL или есть какое-то кэширование результатов ? Может в разных броузерах по разному ?
Если на каждое обращение, то будет тяжеловато, особенно на старых компах.
lzma 1 мб в нативном варианте разжимается около 50 мсек даже на 12700K
JS - сразу в несколько раз минуc. Если вызов идет при каждом дергании URL, на селероне 15 летней давности будете ждать секунды, если не 10+ секунд, а ноут будет выть
Сюда же в копилку гораздо более слабая оптимизация JS на старых броузерах типа iE
Потому есть предложение дифференцировать размер proxy.pac в зависимости от user-agent. Если броузер не налагает жестких ограничений, использовать лайтовую версию
Скрипт исполняется целиком при инициализации контекста js (на каждый поток/процесс, полагаю), в это время можно однократно выполнить какую-то затратную по CPU/RAM операцию. Затем на каждый запрос вызывается функция, которая возвращает результат необходимости проксирования.
По мере прочтения темы, появилось несколько мыслей:
-
Если проблема ограничения размера pac-файла в 1 MB касается только браузеров на основе Chrome, можно ли автоматически собирать отдельную неурезанную версию pac-файла для свежих Firefox, где таких ограничений нет?
-
Не совсем понятно, зачем привязываться к ограничениям в Windows 7 и её версии IE, если сам IE не способен нормально отобразить современные сайты?
Изобретать способ уменьшения размера pac-файла для браузера, который не может отобразить большую часть разблокированных сайтов, выглядит нелогичной тратой людских ресурсов, которые могли бы быть использованы в других вопросах касательно обхода блокировок.
Там еще вроде бы есть ограничения на RAM. Разжать и все хранить в виде JS переменных может быть тоже проблемно
Я ранее предлагал эту идею насчет дифференциации размера в зависимости user-agent.Но думаю не взлетит из-за излишней нагрузки на сервер.Здесь важно понимание того до какого верхнего предела по кол-ву записей можно достигнуть.Если их сейчас 1,7, то на следующий год может оказаться в три раза выше.Рост в геометрической прогрессии( хуже в экспоненциальной)
Нагрузка ложится на прокси, и она не особо зависит от размера proxy.pac
Она зависит от количества значимых доменов. Всякий мусор типа проституток новосибирска практически никому не интересен, а он как раз и составляет основу.
Сам веб сервер, выдающий прокси пак, вообще минимален по нагрузке. Статическая выдача или простейший скрипт - разницы почти нет
У меня есть вариант, который конкретно домены жмет лучше, чем текущий. Получается около 870 KиБ данных в самом proxy.pac (считая код, нужный для распаковки). Я не пробовал включить в него IP-адреса, и не проверял, сколько он потребляет памяти; буду благодарен, если кто-то с этим поможет.
Сам код сжатия работает в Node.js (почти любой версии). Он ожидает в файле src.txt
в текущей директории список доменов, и выдает готовый out.pac
.
Алгоритм основан на трех идеях:
- хосты для матчинга переворачиваются, т.е. с последнего по первый символ
- на перевернутых хостах строится, фактически, бор, но упаковывается в RegExp
- сам RegExp затем сжимается заменой диграмм, примерно так, как сжимаются хосты в текущем репо
compress.js (2.2 KB)
Если в качестве входных данных беру result/hostlist_zones.txt
из репо, то out.pac
имеет размер 875 КиБ. Прикрепляю также его, чтобы легче было тестировать потребление памяти - буду рад, если кто-то с этим поможет. На саму правильность матчинга я тестировал, но в Node.js (т.е. без учета ограничений PAC-файлов).
out.pac (874.2 KB)
Подход интересный, но regexp — точно не самое быстрое решение.
Там основная стоимость на компиляцию при первом запуске скрипта. Потом, когда функция вызывается - она дешёвая; линейная относительно длины host, если прямо заморачиваться асимптотикой.
Не знаю, насколько это приемлемо, плюс не измерял по абсолютным цифрам.
Учитывая, что сам регексп получается без бектрекинга - можно накидать простой алгоритм, который будет матчить его без именно использования RegExp. Попробую в ближайшие дни сделать.
Идея на подумать:
Произвольно руками посмотрел на cloudfront в списке, его есть смысл пытаться резолвить и выкидывать строки не резолвящиеся в какой-либо IP. Одного этого уже может быть достаточно на какое-то время
А есть какой-то сакральный смысл в том, чтобы использовать исключительно один только PAC-файл? Если добавить в инструкцию для пользователей, кроме пункта “укажите в настройках URL PAC-файла” второй пункт “а в другом месте настроек укажите адрес нашего DoH-сервера” - дальше можно реализовать ту же самую подмену IP, как и в VPN-версии, а весь PAC-файл при этом сведётся к нескольким строчкам кода, проверяющим попадание отресолвленного IP для домена в наш подменный диапазон.