Показаны сообщения с ярлыком apache. Показать все сообщения
Показаны сообщения с ярлыком apache. Показать все сообщения

четверг, 3 марта 2011 г.

Ещё пара полезных декораторов

В веб-приложениях для отдачи статических файлов принято использовать возможности веб-серверов (Apache, Nginx), поскольку традиционные языки веб-разработки (Python, Ruby, PHP, Perl) справляются с этой задачей очень плохо. Однако, это связано с рядом ограничений. Во-первых, нельзя автоматически генерировать ссылки на основе информации о маршрутах. Но если это ещё можно пережить (хотя, честное слово, очень неудобно), то есть куда более серьёзная проблема - часто нужен "управляемый" доступ к статическим файлам. Например, скрипт должен проверить права доступа. Для решения этой дилеммы была придумана техника, когда скрипт выполняет свою логику, а реальную передачу файла делегирует веб-серверу путем настройки специальных заголовков ответа. Для nginx это X-Accel-Redirect, а для Apache - X-Sendfile.

При разработке на Common Lisp проблема отдачи статических файлов стоит значительнее менее остро, ибо язык сам по себе намного быстрее и Hunchentoot справляется с этой работой достаточно быстро. Я для публикации статических файлов пользуюсь restas-directory-publisher - модулем для RESTAS. Однако, следует признать, что возможны ситуации, когда отдавать статику средствами CL окажется не очень разумно.

Тут вот и возникла идея обеспечить возможность использования механизма XSendfile прозрачным для основной логики образом. В итоге, я добавил в RESTAS соответствующие декораторы для Apache и Nginx.

Ниже я приведу возможные примеры использования этих декораторов в пакете restas-doc, обеспечивающего работу http://restas.lisper.ru/.

для публикации файлов я использую такой код:
(restas:mount-submodule -publisher- (#:restas.directory-publisher))
При этом, сами файлы с документацией лежат в каталоге /usr/share/doc/restas/.

@apache-xsendfile
При работе с Apache всё просто:
(restas:mount-submodule -publisher- (#:restas.directory-publisher restas:@apache-xsendfile))
а в конфиге Apache необходимо установить значение параметра XSendFilePath таким образом, что бы публикуемые файлы оказались внутри указанного каталога. Самый простой путь
XSendFilePath /
Но это может оказаться не очень разумным с точки зрения администрирования, так что в данном случае можно и так
XSendFilePath /usr/share/doc/restas/
Более подробная информация о настройке сервера есть в официальной документации.

@nginx-accel-redirect
Настройка nginx является более сложной. Необходимо создать internal-секцию и дальше есть два варианта: либо установить root, либо задать alias. В зависимости от выбранного варианта необходимо различным образом формировать заголовок X-Accel-Redirect. Для поддержки этих вариантов в RESTAS добавлено три переменных:
(defvar *nginx-internal-location* nil)
(defvar *nginx-internal-alias* nil)
(defvar *nginx-internal-root* nil)
и их надо настроить точно в соответствии с настройками nginx. При этом, переменные *nginx-internal-alias* и *nginx-internal-root* являются взаимоисключающими и одна из них должна быть установлена в NIL. В принципе, их можно выставить глобально, но RESTAS позволяет сделать лучше. Например, для такого конфига nginx:

location /restas {
internal;
root /usr/share/doc;
}
Код на CL может быть таким:
(restas:mount-submodule -publisher- (#:restas.directory-publisher restas:@nginx-accel-redirect)
(restas:*nginx-internal-location* #P"/restas/")
(restas:*nginx-internal-root* #P"/usr/share/doc/"))
Настройка с root представляется мне довольно неудобной и если nginx поднят только для CL, то гораздо проще делать так
location /protected/ {
internal;
alias /usr/share/doc/restas/;
}
и
(restas:mount-submodule -publisher- (#:restas.directory-publisher restas:@nginx-accel-redirect)
(restas:*nginx-internal-location* "/protected/")
(restas:*nginx-internal-alias* "/usr/share/doc/restas/"))
Вообще, описанный функционал обеспечивает очень важную возможность работать со статическими файлами средствами CL, например, создавать повторно используемые компоненты, а в случае возникновения необходимости легко подключить механизм XSendFile с помощью подключения нужного декоратора.

Я пока разбирался с этими вопрос успел посмотреть советы по использованию XSendFile с RoR и Django - там это носит вид хаков, жёстко прибивающих код к конкретной конфигурации веб-сервера. Этот факт подкрепил моё мнение, что модель декораторов RESTAS вкупе с возможностями CL (такими, как CLOS) обеспечивает более гибкие и мощные возможности, чем более традиционная схема с middleware-компонентами.

вторник, 17 марта 2009 г.

Про патчи

Я тут недавно писал о том, как добавить к babel (а значит и к cffi) новую кодировку. Писал это я не просто так, а потому как возникла необходимость работать с cp1251, поддержка которой ещё не была реализована. Собственно, последовал своим же рекомендациям (тут возникает вопрос о курице и яйце, но неважно), написал код и отправил его в список рассылки проекта. Не прошло и двух недель :-) как мне пришло сообщение, что код принят и включен в проект. Со следующей версии (0.4) (только когда она будет?) будет доступен общественности, либо можно прямо сейчас забрать свежую версию из репозитория:
darcs get http://common-lisp.net/project/babel/darcs/babel
Сам код поддержки cp1251 (полностью списанный с iconv) можно посмотреть здесь.


Ещё недавно я показывал патч для mod_lisp, который позволяет lisp-серверу получить имя пользователя (REMOTE_USER), успешного прошедшего аутентификацию на стороне apache. Но вот беда, как я уже писал, новый hunchentoot не поддерживает mod_lisp. Это заставило меня задуматься и теперь я вообще не понимаю какого я полез использовать этот mod_lisp (да и зачем он вообще нужен не понимаю): стандартный прокси (ProxyPass) решает все проблемы. Ну, не совсем все. Опять таки, возникает проблема передачи lisp-серверу имени аутентинфицированного пользователя. К счастью, эта проблем достаточно легко решается средствами mod_rewrite следующим образом:
RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader set REMOTE-USER %{RU}e
Немного похоже на магию, но работает: добавляет к заголовку запроса поле REMOTE-USER, которое можно использовать на стороне lisp-сервера.