Friday, March 27, 2009

Nothing is always absolutely so

Сменил заголовок своего блога на утверждение высказанное писателем-фантастом Theodore_Sturgeon, думаю оно максимально выразит идею, что все записаное в блоге является только моим субъективным мнением и на истину в полной мере не претендует.

Простейшая реализация OpenID

Документация изначально написана для внутреннего пользования при создании модуля работы с OpenId. Модуль поддерживает только часть функционала openid (только регистрацию по первой версии OpenId). Результат можно посмотреть в здесь. Поддерживает только идентификаторы вида http://имя пользователя с именем провайдера - на этот идентификатор все openid провайдеры должны возвращать свое описание в заголовках страницы. Решил выложить, так как за пол года не появилось более полной реализации по сравнению с той, что есть у меня.

Общие шаги(OpenID *)

Полученному идентификатору запрашиваем страницу в ней ищем значения openid2.provider(OpenId 2.0), openid.delegate (OpenId 1.0 в общем случае должен совпадать с введенным именем пользователя), openid2.local_id(OpenId 2.0 в общем случае должен совпадать с введенным именем пользователя), openid.server (OpenId 1.0) и X-XRDS-Location (OpenId 2.0).

Например:
  • <link rel="openid2.provider" href="http://openid.yandex.ru/server/" />
  • <link rel="openid2.local_id" href="http://openid.yandex.ru/имя пользователя/" />
  • <link rel="openid.server" href="http://openid.yandex.ru/server/" />
  • <meta http-equiv="X-XRDS-Location" content="http://openid.yandex.ru/имя пользователя/yadis/" />
Для OpenId 1.0 Перенаправление пользователя для проверки его валидности

Сделать запрос к серверу (openid.server) на проверку пользователя (openid2.local_id) режим checkid_setup - так как это простейший режим и требующий минимальной реализации с нашей стороны:
  1. [openid.server]?
  2. openid.mode=checkid_setup&
  3. openid.identity=[openid2.local_id]&
  4. openid.return_to=[Путь на который нужно вернуться]&
  5. openid.trust_root=[Проверяем доверие серверу(доменное имя)]&
  6. openid.claimed_id=[openid2.local_id]
Для OpenId 2.0 Получение дополнительной информации

По полученному X-XRDS-Location получаем Yadis документ:
<?xml version="1.0" encoding="UTF-8" ?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<Service priority="20">
<Type>http://specs.openid.net/auth/2.0/signon</Type>
<Type>http://openid.net/signon/1.0</Type>
<URI>http://openid.yandex.ru/server/</URI>
<LocalID>http://openid.yandex.ru/имя пользователя/</LocalID>
</Service>
</XRD>
</xrds:XRDS>

По нему нужно сформировать адрес перенаправления на сайт провайдера для проверки, но в текущей реализации это не сделано и перенаправление всегда генерируется на основе первой версии OpenId. Вторая версия более сложная в реализации, но позволяет получить дополнительные поля при регистрации (описание пользователя).

Возвращаемый сайтом ответ через обратное переполнение
В результате проверки на сайт мы должны вернуться в любом случае с такими параметрами:
  1. Удачный:
  • [Вернутся на такой url]?
  • openid.assoc_handle=[Тип подписи]&
  • openid.identity=[openid2.local_id]&
  • openid.mode=id_res& (нам доверяют)
  • openid.op_endpoint=[openid.server]&
  • openid.response_nonce=[временной штамп]&
  • openid.return_to=[Вернутся на такой url]&
  • openid.sig=&(подпись)
  • openid.signed=(от каких полей подпись)
  1. Не удачный
  • [Вернутся на такой url]?
  • openid.mode=cancel (вам не доверяют)
Проверка подписи
Для яндекса проверка не сработала, когда я тестировал модуль, возможно я что-то делаю не так. Стандартный код проверки OpenId тоже не делал эту проверку.

После получения мы должны проверить, а те ли нам ответили и запросить с сервера дополнительные сведения:
  • [openid.server]?
  • openid.mode=check_authentication&
  • openid.assoc_handle=[Значение openid.assoc_handle из предыдущего запроса]&
  • openid.sig=[Значение openid.sig из предыдущего запроса]&
  • openid.signed=[Значение openid.signed из предыдущего запроса]&
  • openid.identity=[Значение openid.identity из предыдущего запроса]&
  • openid.return_to=[Значение openid.return_to из предыдущего запроса]

Saturday, March 21, 2009

Продолжая тему кэширования: идеи относительно ответов

Еще пара идей:
  • Если пришел запрос на проверку и у нас есть закэшированный вариант(и время кэширования его истекло) ответа можно сравнить результат ответа на запрос с кэшем, если контент не изменился - дату кэширования оставить тем же(дата создания) - но увеличить время критического и валидного кэширования - ответ не изменилось гораздо предпочтителен по сравнению с полным результатом.
  • Станицу ответа - желательно разбивать на несколько частей - чтобы они грузились через отдельные запросы, тогда можно для разных частей указывать разные политики кэширования и кэшировать более маленькие кусочки.
  • Уменьшить количество запросов дающих одинаковый результат с разными url, например a=b/c=d === c=d/a=b. Если избежать их по каким то причинам нельзя - нужно всегда на уровне сервера перенаправлять на наиболее популярный (по каким то причинам) вариант запроса.

Sunday, March 15, 2009

Strange proxy или неправильное кэширование.

Любое кэширование это спор между выдачей реальных данных и выдачей немного устаревших данных. Если выдавать реальные данные то мы тратим ресурсы на получение результата, который уже был ранее посчитан и выдачей немного старых данных. Пользователь получит данные созданные 5 минут назад или полчаса назад - так ли это существенно? Иногда да, иногда нет.. Но не в этом суть - метод определения нужно ли запрашивать заново результат или подойдет уже закешированный - сейчас (для стандартного протокола кэширования http) - может указывать время которое можно считать результат валидным после запроса и дает возможность уточнить валидны ли данные в кэше (если нет получить все данные). Как следствие - прокси вне зависимости от загруженности ресурсов (пропускной канал и сервер) будет спрашивать: а валидны ли данные?

Но если немного сменить стратегию и указывать не только конечный срок валидности, а еще и конечный срок критичной валидности - то мы получим возможность, как и прежде не спрашивать ресурс заново пересчитать результат, но и получить возможность, если ресурс не ответил в установленное время, но еще критичный срок не наступил - выдать старые данные и если ресурс ответил заменить данные в кэше его ответом, чтобы при следующем запросе мы могли ответить более новыми данными с продолженным сроком кэширования.

И если применить это принцип к обратному проксированию мы можем дольше поддерживать работоспособность основного сервера: если количество запросов превысило допустимое по каким-то параметрам, можно выдать кэш. Примерный алгоритм такого решения - при поступлении запроса добавлять запрос в очередь, при превышении лимита времени на заполнение очереди или количества элементов в очереди мы отправляем все эти запросы на следующий этап и ждем новых запросов. Запросы на выполнения сортируются в порядке наступления времени кэширования. Все запросы для которых есть кэш - сразу возвращается результат. Все запросы для которых нет результата отправляются на выполнение. Запросы у которых время кэширования еще не критично ставятся в очередь выполнения - из которой они опадают или на выполнение, если выполнились все запросы на выполнение, или, если приближается максимальное время ожидания, отдается результат из кэша (может просто ответ: не изменилось). Все запросы находящиеся в стадии критического кэширования, начинают выполняться только если свободна очередь от запросов без кэша. Запросы без кэша ставятся в очередь, где контролируется количество запросов на одновременную обработку, все не попавшие ожидают - или прихода своей очереди или просто отмены выполнения, если они в рамках критического кэширования. После выполнения, все запросы подобные обработанному получают его результат и добавляются в кэш, если кэш заполнен, то заменяется запрос с просроченным кэшем или максимально близким к концу временем критического ожидания.

В теории, если не процент выдачи данных с критическим кэшем не высок, то это позволит пережить резкий рост нагрузки или дать время подготовиться к более высоким нагрузкам. Но злоуподреблять не стоит - клиенты могут отказаться от системы - где скорость реакции на изменения очень низкая.

Saturday, March 14, 2009

Strange server

Если на сервер поставить приложение которое будет перенаправлять с одного входящего соединения в другое получим интересный полувирусный сервер - реальная обработка будет происходить на одном из клиентов, можно без статического адреса, с блокировкой входящих соединением и остальными ужасными ограничениями(шутка), а остальные будут им пользоваться как общедоступным ресурсом. Получиться полувирусный сервер... хорошая идея для скрытой или пиринговой сети. В принципе похоже на другие пиринговые алгоритмы, но немного не то, клиент никогда не узнает реального адресса сервера - а вычислить кто из клиентов был сервером можно только по объему трафика и его контенту. Если контент полностью отслеживать и сохранять не стоит, то объем вполне может свидетельствовать, что клиент может быть сервером, и нужно обратить внимание на этот трафик. Но такой сервер всегда будет слабым звеном - он всегда получит раза в 2 большые затраты трафика, по сравнению с решением, когда сервер сам вычисляет значение запроса.

Saturday, March 7, 2009

Изменения в разрабатываемом браузере

Привел к нормальному внешнему виду в разрабатываемый мною браузер:
  • одиночное окно отображавшее сразу компонент для отображения отрендеренного кода - заменил на классическое отображение содержащее над компонентом отображения страницы панель с отображением текущего адреса, кнопки назад, напечатать и выйти. В результате реализовано полный функционал доступный из публичных интерфейсов библиотеки gtkhtml, связанный с рендеренгом страниц. В внутри еще доступен дамп внутреннего состояния текущего отображенной страницы - но вовне он не доступен.
  • не реализовал: автоматическое перенаправление через определенное время (сообщение в консоль) и анимацию при загрузке страницы;
  • в остальном можно уже использовать как нормальный браузер, простой POST без передачи файлов реализован, есть поддержка cookies - как основной браузер использовать не рекомендую из-за проблем отображения, но для тестов вполне.
Приложение наследует особености библиотеки gtkhtml:
  • не поддерживает стили css;
  • не корректный рендеринг страниц - может расползаться отображение фреймов и дивов;
  • не поддерживает javascript;
  • алгоритм рендеринга отличается от классического: преобразования HTML -> DOM -> Rendering HTML + Styles(просчет стили для каждого элемента DOM с последующим отображением. На данный момент структуру формирования дерева подобного DOM я не обнаружил - страница разбивается на список открывающихся и закрывающихся тегов, и как следствие сложно добавить применение стилей.
В новых версиях библиотеки с присутствует мой патч решающий пролему с поддержкой кодирово отличных от utf8, и исправлена ошибка с неправильным отображением entity в некоторых случаях.

Sunday, March 1, 2009

Использование общего отображения

В отношении кросплатформенных систем,
например: приложение и веб.

Достоинства:
  • Возможность описания поведения на псевдоязыке(если нет общего языка) общего для всех видов отображения;
  • Возможность быстро переносить логику между системами,
  • Достаточно быстрое создание логики на новой системе, если она где-то уже используется.
Недостатки полное следствие достоинств:
  • Нужно искать или создавать общий язык для описания логики и зависимостей между формами - для простой логики создать достаточно просто, но зачем для простой логики городить сложности - можно просто написать на языке наиболее удобном для каждой платформы, но при этом получиться, что логика реализована 2 раза и исправление ошибки или изменение автоматически не отобразиться на другой платформе;
  • Проблемы отображения - нужно преобразовывать отображения с одного вида в другой - не всегда это удается получить отображение которое будет отображаться в удобном виде. Пример: шаблон отображения приложения использует позиции элементов друг в друга - но в случае веб отображения или другой системы отображения нужно указывать порядок вложенности и\или размеры - и для поддержки нового отображения нужно переделывать всю систему преобразования шаблона в разметку на всех платформах для поддержки всех ограничений или особенностей системы. В результате получается, что кроссплатформенная система отображения содержит все ограничения и общности всех платформ (возможно одна из проблем проблем из-за которой google отказался от идеи использовать кроссплатформенное отображения для своего браузера).

А в остальном получается удобная система получения новой функциональности на другой платформе(если она уже есть на одой из версий системы), но можно портировать только ограниченное количество функциональности - так как функциональность существующая в одной из версий приложения может быть слишком сложной для другой - регистрация на сайте и возможности настроек для веб отображения гораздо проще чем в системе в виде установленного приложения с указанием кучи специфических, не нужных обычному пользователю с веба возможностей. А создание новой системы быстрого создания офисных приложений вряд ли окупит себя, так нужно конкурировать с 1C или Microsoft, и проще создать простое, но максимально эффективное приложения для каждой платформы. Или простое максимально эфективное ограничено кросплатформенное приложение максимально соответствующее требованиям, но без излишней универсальности.