Написание выходных фильтров Apache 2.0


В прошлой статье мы рассмотрели основные принципы фильтров сервера Apache 2.0, но этой информации недостаточно для написания полноценного фильтра. В этой статье, мы завершим обсуждения выходных фильтров сервера. После прочтения данной статьи Вы сможете написать свой собственный фильтр для Apache.
Когда интерфейс фильтров впервые разрабатывался, очень мало внимания обращалось на то, чтобы сделать его легким для понимания другими людьми (не разработчикам сервера), которые будут разрабатывать собственные фильтры. С того времени разработчики пересмотрели API и добавили более простой интерфейс поверх старого. Так, для получения всех возможностей фильтра, оригинальный API требовал, чтобы разработчик подсчитал, сколько данных он будет передавать следующему фильтру. Например, если вы пишите фильтр, который сохраняет каждое передаваемое слово, то у вас есть два решения этой задачи: либо конвертировать передаваемый файл в список блоков и поочередно обойти их, либо копировать каждое слово в огромный блок памяти.

Каждый из этих подходов имеет существенные недостатки, которые должны быть устранены. С новым API решение данной проблемы становиться гораздо проще. Все, что необходимо сделать разработчику, это только разбить файл на отдельные слова и передать их следующему фильтру. Apache же на себя возьмет заботу о копировании данных и позаботится о передачи этих данных следующему фильтру. Этот модуль реализует описанный фильтр.
Новый API фильтров имеет очень близкое сходство с файловым API POSIX. Фактически разработчики использовали данный API как модель, когда изменяли дизайн фильтров. Вот пять функций, используемых для передачи данных от текущего фильтра к следующему. Все эти функции имеют одинаковые два первых параметра. Первый параметр, передающийся каждой функции, это следующий фильтр в цепочке фильтров, а второй - это бригада, используемая для хранения данных (если это необходимо). Все эти функции обладают некоторыми одинаковыми чертами. Так, например, данные копируются в бригаду до тех пор, пока бригада содержит менее 8К данных. Когда же размер данных бригады достигает 8К, вся бригада отсылается следующему в цепочке фильтру.
*ap_fwrite(ap_filter_t *f, apr_bucket_brigade *bb, const char *data, apr_size_t nbyte) Отправить указанное число символов строки следующему фильтру. Переменная nbytes показывает, сколько символов надо отправить.
*ap_fputs(ap_filter_t *f, apr_bucket_brigade *bb, const char *s) Отправить строку s следующему фильтру.
*ap_fputc(ap_filter_t *f, apr_bucket_brigade *bb, const char c) Отправить символ с следующему фильтру.
*ap_fputstrs(ap_filter_t *f, apr_bucket_brigade *bb, …) Отправить все строки, переданные этой функции, следующему фильтру.
*ap_fprintf(ap_filter_t *f, apr_bucket_brigade *bb, const char *fmt, …) Отправить форматированные данные (формат: printf()) следующему фильтру.
В добавление к этим пяти функциям, существует еще одна не менее важная. Так как эти функции буферизируют данные перед отправкой, то важно, чтобы разработчики фильтров могли иметь возможность немедленно отправить данные в случае необходимости. Это делается с помощью функции:
ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb) Данная функция принимает текущую бригаду и пересылает ее следующему фильтру.
Теперь, когда Вы знаете, как передавать данные, остается только одна вещь, которую Вам необходимо знать перед тем, как начать писать собственные фильтры. Фильтры Apache вызываются такое количество раз, пока не обработают все данные, полученные от обработчика запроса. Это означает, что возможно, и даже вероятно, некоторые участки кода Вашего фильтра при обработке данных обнаружат, что полученных данных недостаточно для завершения обработки. В таких случаях Вы можете сохранить состояние фильтра до поступления необходимых данных. Однако чаще Вам будет требоваться сохранять обработанные данные до следующего вызова Вашего фильтра. Это делается с помощью функции:
ap_save_brigade(ap_filter_t *f, apr_bucket_brigade **save_to, apr_bucket_brigade **b, apr_pool_t *p)
Данная функция принимает текущий фильтр в качестве первого аргумента. Второй аргумент - это бригада, используемая для хранения данных. Если параметр save_to равен null, тогда бригада создается внутри функции. Третий параметр - это текущая бригада. Эта бригада должна содержать те данные, которые Вы хотите сохранить для следующего вызова фильтра. В последнем параметре функции передается пул, который используется для выделения необходимой памяти. Когда данная функция завершается, бригада save_to содержит полную копию всех данных, отправляемых следующему фильтру. Эта бригада также может быть сохранена в указателе ctx на контекст фильтра для использования при следующем вызове фильтра.
При написании фильтров важно понимать, что фильтры вызываются до тех пор, пока не будут обработаны все данные. Такой подход позволяет Apache передавать информацию клиентам гораздо быстрее. Тем не менее, это также создает некоторые проблемы для фильтров.
Важно понимать, что есть некоторые вещи, которые должны быть выполнены только при первом вызове фильтра. Например, при первом вызове фильтра можно изменить заголовки ответа. Также есть возможность добавить специальный контейнер ошибок к бригаде. Если такой контейнер добавлен к бригаде, то один из внутренних фильтров сервера, найдя этот контейнер, отошлет ошибочный ответ клиенту вместо отправки сгенерированных данных.
Вместе с описанием функций фильтра и примером выходного фильтра, в этой статье Вы получили достаточно информации для написания Вашего собственного фильтра Apache 2.0. Множество вещей можно сделать с помощью фильтров Apache, и я поддерживаю всех тех, кто будет экспериментировать с новыми возможностями фильтров Apache 2.0. В следующей статье мы рассмотрим входные фильтры Apache 2.0. Входные и выходные фильтры имеют некоторые одинаковые характеристики, но они также имеют достаточно много различий, чтобы выделить для них отдельную статью.
Автор: Райн Блум (Ryan Bloom)
Перевод: Сипягин Максим
Оригинал документа (en)

These icons link to social bookmarking sites where readers can share and discover new web pages.
  • News2.ru
  • NewsLand.ru
  • del.icio.us
  • BobrDobr.ru
  • Ma.gnolia
  • Digg
  • Reddit
  • Technorati
  • Slashdot
  • Netscape
  • DZone
  • ThisNext
  • Furl
  • YahooMyWeb
Опубликовано в: Разработка модулей Февраль 2, 2006

6 Комментариев »

  1. Насколько я понимаю это единственная статья в интернете на эту тему. Или я ошибаюсь? Где можно почитать о разработке модулей для apache 2.Х под виндовс, в частности фильтров, желательно на Delphi.

    Комментарий от Serg — Октябрь 28, 2006 @ 11:59 pm

  2. не работает модуль в примере
    mod_swap.c(31) : error C2198: ‘apr_brigade_create’ : too few arguments for call
    mod_swap.c(37) : warning C4013: ‘APR_BRIGADE_FOREACH’ undefined; assuming extern
    mod_swap.c(37) : error C2143: syntax error : missing ‘;’ before ‘{’
    mod_swap.c(68) : error C2065: ‘AP_FTYPE_CONTENT’ : undeclared identifier
    mod_swap.c(68) : warning C4047: ‘function’ : ‘ap_init_filter_func’ differs in le
    mod_swap.c(68) : warning C4024: ‘ap_register_output_filter’ : different types fo
    mod_swap.c(68) : error C2198: ‘ap_register_output_filter’ : too few arguments fo

    Комментарий от nick — Январь 29, 2007 @ 3:56 pm

  3. Да статья одна! И притом очень рульная!! Респект!!
    ____________________
    http://buildstory.ru/

    Комментарий от андрюха — Август 29, 2008 @ 1:52 pm

  4. h1 all

    Комментарий от Анджела — Октябрь 18, 2008 @ 6:02 pm

  5. приветики

    Комментарий от Вероника — Октябрь 18, 2008 @ 6:02 pm

  6. ap_save_brigade(ap_filter_t *f, apr_bucket_brigade **save_to, apr_bucket_brigade **b, apr_pool_t *p) - несовершенна (

    Комментарий от Наталья — Апрель 9, 2009 @ 6:18 pm

Оставить комментарий

You must be logged in to post a comment.

Работает на WordPress