Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org
 

Chapter 3 - Архитектура Apache Module API

Apache API написаны из условия , что Apache - это HTTP-server, который работает как демон . Поскольку он HTTP-server, он должен слушать входящие TCP/IP-пакеты,распознавть URI , парсить их в имена файлов и скриптов и возвращать контент на клиентский броузер . Модули играют активную роль во всех этих аспектах . Апач устроен так , что новый запрос может инициировать новый процесс прежде , чем закончится процесс , обслуживающий предыдущий запрос . Используется мультипроцессорная модель с наличием множества серверов , каждый из которых может обслуживать множество клиентов . На Win32-модели в большей степени используется мультитрэдинговая модель . HTTP Protocol Пример запроса , который клиент посылает на сервер : GET /very/important/document.html HTTP/1.1 Host: www.modperl.com 1-я строка состоит из 3-х компонентов : GET - метод запроса (GET,POST,PUT,HEAD,DELETE) /very/important/document.html - URI документа HTTP/1.1 - тип протокола ; 1.1 отличается от 1.0 наличием виртуальных хостов и кэшированием 2-я строка состоит из имени хоста Дальше идут серия строк , каждая из которых состоит из хидера , двоеточия и расшифровки : GET /news.html HTTP/1.1 Connection: Keep-Alive User-Agent: Mozilla/4.05 [en] (X11; I; Linux 2.0.33 i686) Host: www.modperl.com Referer: http://www.modperl.com/index.html If-Modified-Since: Tue, 24 Feb 1998 11:19:03 GMT Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* Accept-Language: en Accept-Charset: iso-8859-1,*,utf-8 В этом примере приведены большинство HTTP-хидеров , которые нужно знать . Например , хидер Connection говорит о том , что TCP-коннект будет открытым до окончания запроса. В User-Agent указывается тип броузера . Host - имя хоста , откуда пришел запрос . Referer - URI ссылаемого документа . If-Modified-Since - дата кэширования документа на клиенте . В зависимости от него сервер может не возвращать контент . Accept - список MIME-типов , которые поддерживаются броузером . Если тип запроса POST , могут быть другие дополнительные поля .
 
 Apache Life Cycle
 
 Апачевский цикл показан на картинке .
 Он стартует , инициализирует , создает несколько копий самого себя любимого ,
 после чего запускается цикл , в котором проверяются входящие запросы .
 Модули регистрируют хэндлеры , которые вызываются в нужное время .
 Порядок вызова зависит от того , в каком порядке загружены модули . 
 
 
  Server Startup 
 
  При старте апач парсит командную строку и конфиг файлы .
 Конфиги могут включать директивы , реализованные в модулях .
 В каждом модуле есть init-процедура , которая передает от сервера информацию 
 в структуру server_rec . 
 Ее полями являются ServerName, Port,ServerAdmin.
 Модули на C имеют дополнительный указатель на область памяти "resource pool".
 В перловом модуле , на этапе инициализации , могут быть применены 
 директивы PerlRequire и PerlModule.
 Далее апач создает несколько процессов , которые будут обслуживать 
 входящие запросы .  
 Эти процессы устанавливают собственные  user и group IDs для нерутовых пользователей 
 ("nobody" или "guest"). 
 Родительский рутовый процесс обслуживает эту очередь дочерних процессов .
  Каждый дочерний процесс , обслужив положенную порцию процессов , 
  равную MaxRequestsPerChild ,
 прекращает свое существование . При этом в соответствующем модуле будет 
 вызываться хэндлер child_exit ,
 где могут комититься незавершенные транзакции , закрываться файлы и т.д.
 Перловые модули при этом могут вызвать хэндлер , который может быть прописан как
 PerlChildExitHandler в конфиге .
 
 Основной цикл
 
  Он показан на следующей картинке .
 
  Решения принимает апач , но свою лепту могут вносить модули .
 Можно выделить 8 основных моментов : 
  
 1. Что это ? (трансляция URI )
  URI может ссылаться на физический файл , на документ , генерируемый на лету внешним скриптом ,
 или на документ , генерируемый модулем . 
 2. Откуда пришел запрос ?
 3. От кого пришел запрос ?
 4. Кому разрешено выполнять этот запрос ? 
  В конфигурации могут быть перечислены файлы , доступ к которым имеют далеко не все .
 5. Тип документа ? (MIME)
 6. Кто генерирует контент для этого документа ?
       Апач может принять решение о том , что генерация контента отдается внешнему модулю .
 7. Кто и куда пишет лог ?
       Вообще-то логами занимается сам апч , но может быть принято решение о передаче внешнему
       модулю прав на специальное логирование , например в базу данных . 
 8. Кто двери закрывает ?
       После обработки запроса модули могут выполнять различные телодвижения .
 
 
 
 
 Внутренние запросы апача 
 
  Они могут быть сгенерированы апачем при обработке ошибок или в других ситуациях .
 При этом возвращаемый контент заменяется на другой . 
 С помощью функции internal_redirect() апач прекращает обработку текущего запроса и передает
 управление другому процессу . При возникновении ошибок срабатывает  ErrorDocument ,
 при этом возвращается спциальный HTML-file или CGI-script .
 В некоторых ситуациях вызываются функции lookup_file() или lookup_uri() .
 Они генерят запрос , как будто он пришел снаружи .
 
  Некоторые стандартные апач-модули используют т.н.  environment variables .
 mod_cgi устанавливает их для хранения информации о запросе .
 mod_include использует их при генерации HTML . 
 mod_log_config включает информацию о них в лог-файл .
 mod_access принимает решение о разрешении доступа на их основе.
 Их можно модифицировать с помощью PassEnv, SetEnv, UnsetEnv директив 
 которые реализованы в модуле mod_env . 
 Pass-Env может передавать их процессу .
 Эти переменные также можно выставлять в конфиге с помощью директив <Directory> и <Location> : 
 	PerlPassEnv     ORGANIZATION
 	PerlSetEnv      TMPDIR  /usr/tmp
 	<Location /stage/upload>
 	PerlSetEnv      TMPDIR /tmp/staging
 	</Location>
 
  При старте апач копирует  environment variables во внутреннюю таблицу .
 После чего загружаемые модули читают из нее эти переменные , а не из конфигов .
 Perl и C API позволяют модифицировать содержимое этой таблицы .
 
 
 
 Handler API
 
  При вызове хэндлера апач передает ему информацию о текущей транзакции и конфигурации сервера ,
 который должен быть возвращен апачу назад . 
 В Perl API определение хэндлера такое : 
 	sub  {
 	my $r = shift;
 	# do something
 	return ;
 	}
 Хэндлер может быть вызван в любой момент . Он возвращает единственный аргумент , являющийся
 ссылкой на обьект запроса . Этот обьект есть структура и называется request record,
 включающая в себя всю необходимую информацию о транзакции .
 Этот обьект хранится в перл-переменной , называемой  $r. 
 В особом случае хэндлер может вернуть и 2 аргумента ($$) , где первым аргументом будет
 имя пакета . Это позволяет перловым хэндлерам использовать возможности наследования и полиморфизма .
 Такие хэндлеры называются "method handlers" : 
 	sub  ($$) {
 	my $class = shift;
 	my $r = shift;
 	# do something
 	return ;
 	}
 
  Хэндлеры на C API декларируются так :
    static int  (request_rec* r) {
    /* do something */
    return ;
 	}
 
  В отличие от Perl API, где все хэндлеры имеют одинаковую структуру , C API handlers 
 могут иметь другую форму .Например , child_init()-handler выглядит так :
 	static void child_init (server_rec *s, pool *p) {
 	/* do something */
 	}
 
 
 
 Status Codes 
 Каждый хэндлер должен возвращать статус-код , который ассоциируется с символической констаной .
 Для перла они определены в модуле Apache::Constants и для си в httpd.h-include .
 
Code
Constant (Nickname)
Описание

2XX Codes--Success

200
HTTP_OK
(DOCUMENT_FOLLOWS)
URI был найден и контент определен.
201
HTTP_CREATED
URI создан с помощью PUT.
202
HTTP_ACCEPTED
Доступ к запросу
203
HTTP_NON_AUTHORITATIVE
Ошибка авторизации
204
HTTP_NO_CONTENT
Запрос правильный , но контент нулевой
206
HTTP_PARTIAL_CONTENT
(PARTIAL_CONTENT)
Часть контента документа

3XX Codes--Multiple Choices Available

300
HTTP_MULTIPLE_CHOICES
(MULTIPLE_CHOICES)
Несколько документов
301
HTTP_MOVED_PERMANENTLY
(MOVED)
Документ перемещен на другой URI.
302
HTTP_MOVED_TEMPORARILY
(REDIRECT)
Документ временно перемещен на другой URI.
304
HTTP_NOT_MODIFIED
(USE_LOCAL_COPY)
Документ закэширован , обновлять не надо .

4XX Codes--Client-Side Errors

400
HTTP_BAD_REQUEST
(BAD_REQUEST)
Запрос с ошибкой
401
HTTP_UNAUTHORIZED
(AUTH_REQUIRED)
Неправильно авторизованный клиент
402
HTTP_PAYMENT_REQUIRED
Деньги вперед
403
HTTP_FORBIDDEN
(FORBIDDEN)
Доступ к документу для клиента запрещен
404
HTTP_NOT_FOUND
(NOT_FOUND)
Запрашиваемый документ не существует
405
HTTP_METHOD_NOT_ALLOWED
(METHOD_NOT_ALLOWED)
Метод (e.g., PUT) не разрешен
406
HTTP_NOT_ACCEPTABLE
Запрос недоступен
407
HTTP_PROXY_AUTHENTICATION_REQUIRED
Proxy authentication.
408
HTTP_REQUEST_TIME_OUT
Клиент ждет
410
HTTP_GONE
Документа нет.
412
HTTP_PRECONDITION_FAILED
(PRECONDITION_FAILED)
Документ не найден
413
HTTP_REQUEST_ENTITY_TOO_LARGE
Слишком большой обьем данных от клиента
414
HTTP_REQUEST_URI_TOO_LARGE
Слишком длинный URI
415
HTTP_UNSUPPORTED_MEDIA_TYPE
MIME type не поддерживается

5XX Codes--Server-Side Errors

500
HTTP_INTERNAL_SERVER_ERROR
(SERVER_ERROR)
Неопределенная ошибка
501
HTTP_NOT_IMPLEMENTED
(NOT_IMPLEMENTED)
Не реализовано
502
HTTP_BAD_GATEWAY
(BAD_GATEWAY)
Ошибка proxy
503
HTTP_SERVICE_UNAVAILABLE
Сервер в дауне
504
HTTP_GATEWAY_TIME_OUT
proxy - time out
505
HTTP_VERSION_NOT_SUPPORTED
Версия HTTP не поддерживается
506
HTTP_VARIANT_ALSO_VARIES
(VARIANT_ALSO_VARIES)
Документ представлен несколькими вариантами
Модуль Apache::Constants экспортирует не все HTTP_* имена , и при попытке вызвать некое HTTP_* имя можно получить "Undefined subroutine". Кроме статус-кодов из этой таблицы , апач может иметь дополнительно свои внутренние : OK - говорит о том , что хэндлер был успешным (не путать с HTTP_OK) DECLINED - хэндлер отказывается обрабатывать запрос . DONE - апач немедленно закрывает коннект с клиентом
  Запуск хэндлера
  Perl и C API по-разному запускают хэндлеры . 
 Для C API хэндлер определяется с помошью указателя на его функцию 
 в таблице внутри откомпилированного модуля .
 В Perl API хэндлер запускается с помощью директив конфига 
 или внутри .htaccess
 Для реализации хэндлера в перл нужно написать модуль .pm и добавить в конфиг
 директиву Perl*Handler.
 Всего в Perl API существуют 15 директив : 
 PerlTransHandler,PerlAccessHandler,PerlLogHandler, и т.д.
 В перловом модуле нужно создать подпрограмму с именем handler().
 Apache Perl модули обычно живут внтри Apache::package namespace. 
 Обычно Apache Perl module выглядит так :
 	package Apache::Foo;
 	use strict;
 	use Apache::constants qw(:common);
 	sub handler {
 	my $r = shift;
 	# do something
 	return ;
 	}
 
 Его декларация в конфиге :
 	 Apache::Foo
 
 Можно написать целый список :
 	Apache::Foo Apache::Bar Apache::Baz
 	Apache::Wiz Apache::Waz
 
 Функция хэндлера не обязана называться handler(), 
 если она например называется do_something(), то:
 	 Apache::Foo::do_something
  
 Perl*Handler не обеспечивает автоматическую загрузку хэндлера .
 Нужно использовать директиву PerlModule в конфиге :
 	PerlModule Apache::Foo
 	Apache::Foo::do_something
 Если модуль не загружается ,  возникает ошибка , которую можно найти в логе .
 
 С помощью Perl*Handlers можно использовать анонимные процедуры :
 	PerlChildInitHandler "sub { warn qq(child $$ starting\n) }"
 
 
 Perl API Configuration Directives 
 
 Здесь представлен список конфигурационных директив Perl API . 
 	 PerlRequire 
 	 PerlModule 
  Эти директивы используются для загрузки модулей с диска .	
 На перле аналогом является оператор require . 
 Конфиг-строка
 	PerlModule Apache::Plotter
 соответствует коду на перл :
 	require Apache::Plotter;
 	use Apache::Plotter ();
 Для директивы  PerlRequire нужно указывать абсолютный путь :
 	PerlRequire /opt/www/lib/directory_colorizer.pl
 	PerlRequire scripts/delete_temporary_files.pl
 и то же самое на перле:
 	require '/opt/www/lib/directory_colorizer.pl';
 	require 'scripts/delete_temporary_files.pl';
 Обе этих директивы возможны со списком модулей :
 	PerlModule CGI LWP::Simple Apache::Plotter
 	PerlRequire scripts/startup.pl scripts/config.pl
 	
 Старт апача с рутовыми правами , доступ к конфигам и скриптам таит в себе опасность .
 Директива PerlOpmask и PERL_ OPMASK_DEFAULT предназначена 
 для снижения возможного риска .
 
 PerlChildInitHandler 
   Этот хэндлер срабатывает каждый раз , когда на апаче форкается дочерний процесс .
 Пример : 
 	PerlChildInitHandler Apache::DBLogin
 Эта директива может находиться в конфиге внутри секции виртуального хоста , 
 но не внутри <Directory>, <Location>,или <Files> 
 или .htaccess . 
 
 PerlPostReadRequestHandler 
   Этот хэндлер срабатывает каждый раз , когда апач получает запрос .
 Удобное место для обработки старта транзакции .  
 Пример :
 	PerlPostReadRequestHandler Apache::StartTimer
 Порядок размещения этой директивы аналогично предыдущей .
  
 PerlTransHandler 
    Срабатывает тогда , когда происходит перевод URI в имя файла 
 Пример :
 	PerlTransHandler Apache::AdBlocker
 
 Хэндлеры :
 PerlHeaderParserHandler 
 PerlAccessHandler 
 PerlAuthenHandler 
 PerlAuthzHandler 
 PerlTypeHandler 
 PerlFixupHandler 
 PerlHandler 
 PerlLogHandler 
 PerlCleanupHandler 
 PerlChildExitHandler 
 PerlFreshRestart 
 PerlDispatchHandler 
 PerlRestartHandler 
 
 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье