Недавно Роскомнадзор предпринял попытку блокировки Википедии. Попытка провалилась, и самое время перейти в контрнаступление. В статье под катом я покажу, что, если пользователь Х зашёл на сайт А, то сайт А может определить, заблокирован ли для пользователя другой сайт Б.
А дальше, по намечающейся традиции, изложение пойдёт в вопросно-ответной форме.
При обсуждении блокировки Википедии сообщество заметило два обстоятельства, которые весьма выгодны цензуре.
Во-первых, Википедия использует HTTPS и, более того, HSTS. Это означает, что заблокирована энциклопедия может быть только целиком (с точностью до домена), но при этом перенаправить на пресловутую страницу с сообщением о блокировке нельзя. Вместо этого высвечивается сообщение об ошибке установления соединения. Это выглядит как внутренняя проблема Википедии и смягчает недовольство пользователя действиями Роскомнадзора; в то же время для развития правового государства необходима обратная связь.
Во-вторых, даже если пользователи узнают о блокировке, многие из них просто не будут знать, что делать. Вешать перманентную плашку "Если заблокировали Википедию - качайте Tor Browser!" на неравнодушных сайтах как минимум странно; в то же время, оповещение пользователей о блокировке Википедии и способах её обхода необходимо. Решение поставленной проблемы и пытается дать настоящая статья.
Создаётся невидимый блок HTML-кода, содержащий два изображения: одно контрольное - с заведомо несуществующего URL, второе сигнальное - любое изображение с проверяемого сайта. Если их размеры через некоторое время совпадают - значит, изображение с проверяемого сайта не загрузилось, то есть он либо "лежит" настолько, что не может отдавать даже статику, либо заблокирован.
Изображение в HTML, вставлемое тэгом img, по умолчанию имеет размеры, определяемые самим файлом-картинкой. Изображение, которое загрузить не удалось, тоже имеет какие-то размеры - в разных браузерах разные. Вот они (ширина x высота):
Получить размеры элемента на Javascript можно с помощью свойств элемента .offsetWidth и .offsetHeight
Это достаточно маловероятно, учитывая, что сравниваются и ширина, и высота.
Можно запросить два изображения заведомо разных размеров и сравнить их полученные размеры.
Если совпадут - загрузка прошла неуспешно.
И всё же фавиконы в качестве единственных изображений лучше не дёргать.
Постарался сделать код читабельным, хотя, конечно, это не освобождает меня от приведения примера.
chasAntidot.testSiteWithImg({ url: 'https://ru.wikipedia.org/static/images/project-logos/ruwiki.png', //URL картинки-детектора ifBlocked: function(){message('заблокирована');}, //callback, если заблокировано ifNotBlocked: function(){message('не заблокирована');}, //callback, если не заблокировано time: 3500, //Время ожидания ответа в миллисекундах, по умолчанию 4000 secondImage: 'https://ru.wikipedia.org/favicon.ico', //URL второй картинки - необязательно });Никаких дополнительных библиотек типа jQuery не требуется, всё на чистом JS.
Во-первых, в любом случае саму библиотеку лучше скачать к себе на сайт. github.io не застрахован от блокировок.
Во-вторых, для чистого JS возможен, например, такой вариант:
chasAntidot.createBanner( 'Вероятно, <a href="https://ru.wikipedia.org">Википедия</a> заблокирована. <a href="http://rublacklist.net" target="_blank">Узнайте, что нужно сделать!</a>', { url: 'https://ru.wikipedia.org/static/images/project-logos/ruwiki.png', secondImage: 'https://ru.wikipedia.org/favicon.ico', } );
Это, конечно, работает, но не очень красиво :) Патчи, добавляющие функции создания баннеров с использованием различных библиотек, приветствуются!
На этот случай можно использовать схожий механизм, сравнивая доступность картинки напрямую и через какой-нибудь анонимайзер. Ресурс в таком случае можно считать заблокиованным тогда и только тогда, когда через анонимайзер картинка видна, а напрямую - нет. Правда, анонимайзер тоже может быть заблокирован, и тогда придётся проверять ещё и его доступность - например, запрашивая через него картинку с сайта самого РКН.