nginx: desenvolvimento de módulos

Uma referência incontornável na introdução ao desenvolvimento de módulos nginx é sem dúvida o artigo Emiller’s Guide To Nginx Module Development.
Não menos valiosa é ainda a contribuição do Antoine Bonavita: Development of modules for nginx (tradução para Inglês do artigo original em Russo).

Para um servidor http com o potencial do nginx esta é, até agora, a melhor literatura que encontrei especificamente sobre o desenvolvimento de módulos.
O projeto em si padece de falta de documentação técnica e a bibliografia em geral não cobre detalhadamente esta componente.

Como quando se começa com uma nova linguagem de programação, a tentação é procurar um exemplo “hello world” que também o há para o nginx, no entanto, dada a facilidade de borrar a pintura entre apontadores e referências, parece-me mais prudente iniciar a experiência com um módulo cuja principal funcionalidade é não fazer nada. Neste contexto, “não fazer nada” significa que vamos conseguir compilar o nosso módulo junto com o restante código fonte do nginx (ao contrário dos módulos de Apache que são dinamicamente linkados, os módulos nginx são compilados com o core) , não quebrando o seu funcionamento.

No contexto do nginx, existem dois tipos de módulo:

  • handlers: processam o pedido e geram output;
  • filter: manipulam o output.

O nosso módulo “do_nothing” é do segundo tipo (filter), mas neste caso particular não irá fazer qualquer alteração ao output.

A arquitetura dos módulos é bastante simples e consiste em dois ficheiros:

  • config: contem a informação do módulo (i.e. nome), as suas dependências e outras informações necessárias para a compilação (mais detalhes sobre este ficheiro);
  • do_nothing.c: a implementação do módulo que inclui um conjunto de estruturas pré-definidas responsáveis pela integração com o funcionamento base do nginx.

Assim, passemos à apresentação do nosso ficheiro config

ngx_addon_name=ngx_http_do_nothing_filter_module
#HTTP_MODULES="$HTTP_MODULES ngx_http_do_nothing_filter_module"
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_do_nothing_filter_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/do_nothing.c"

O nome “oficial” do módulo será ngx_http_do_nothing_filter_module, que segue a nomenclatura tipo (ngx_http), nome (do_nothing) e natureza (filter).

A implementação é feita em C e apresenta-se conforme abaixo:

/**
 * @file	do_nothing.c
 * @brief	nginx filter module which does nothing
 * @author		Paulo A. Silva<me@pauloasilva.com>
 * @copyright	2014 (c) Paulo A. Silva
 * @license
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include "do_nothing.h"
 
/**
 * Modules directives.
 * This module does not have any directive.
 */
static ngx_command_t  ngx_http_do_nothing_commands[] = {
 
    ngx_null_command
};
 
/**
 * Functions references for creating the three configurations.
 * This module will execute "ngx_http_do_nothing_init" only on postconfiguration
 */
static ngx_http_module_t  ngx_http_do_nothing_filter_module_ctx = {
    NULL,                       // preconfiguration
    ngx_http_do_nothing_init,   // postconfiguration
 
    NULL,                       // create main configuration
    NULL,                       // init main configuration
 
    NULL,                       // create server configuration
    NULL,                       // merge server configuration
 
    NULL,                       // create location configuration
    NULL                        // merge location configuration
};
 
/**
 * Module definition used as a key to look up associated data (e.g. module
 * directives)
 */
ngx_module_t ngx_http_do_nothing_filter_module = {
    NGX_MODULE_V1,
    &ngx_http_do_nothing_filter_module_ctx,     // module context
    ngx_http_do_nothing_commands,               // module directives
    NGX_HTTP_MODULE,                            // module type
    NULL,                                       // init master
    NULL,                                       // init module
    NULL,                                       // init process
    NULL,                                       // init thread
    NULL,                                       // exit thread
    NULL,                                       // exit process
    NULL,                                       // exit master
    NGX_MODULE_V1_PADDING
};
 
static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
 
/**
 * Installs the module's header and body filters.
 * This function runs on postconfiguration
 *
 * @param    ngx_conf_t    *cf    nginx nginx general configuration struct
 * @return   nginx_int_t
 */
static ngx_int_t
ngx_http_do_nothing_init(ngx_conf_t *cf)
{
    ngx_http_next_header_filter = ngx_http_top_header_filter;
    ngx_http_top_header_filter = ngx_http_do_nothing_header_filter;
 
    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_do_nothing_body_filter;
 
    return NGX_OK;
}
 
/**
 * HTTP request headers filter.
 * When response body is modified, Content-Length response header must be fixed
 * here.
 *
 * @param    ngx_http_request_t    *r    HTTP request struct
 * @return   ngx_int_t    exit code
 */
static ngx_int_t
ngx_http_do_nothing_header_filter(ngx_http_request_t *r)
{
    return ngx_http_next_header_filter(r);
}
 
/**
 * HTTP request body filter.
 * Any modification to the HTTP request response must be performed here,
 * manipulating the nginx body buffers.
 *
 * @param    ngx_http_request_t    *r   HTTP request struct
 * @param    ngx_chain_t           *in  nginx request response body buffers
 * @return   ngx_int_t	exit code
 */
static ngx_int_t
ngx_http_do_nothing_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    return ngx_http_next_body_filter(r, in);
}

(download do módulo do_nothing)

Este será portanto o esqueleto mais elementar dum módulo nginx capaz de filtrar o conteúdo a servir.
De tão elementar que é, o módulo “do_nothing” não recebe qualquer parâmetro/directiva, pelo que é “omnipresente” no ficheiro de configuração do nginx: simplesmente existe, executa mas não faz nada.

Falta portanto abordar o processo de compilação.

  1. fazer o download do código fonte do nginx;
  2. descomprimir o arquivo;
  3. aceder ao directório com o código fonte do nginx e executar o seguinte comando (alterar o parâmetro “–add-module” de acordo)
    sudo ./configure --with-pcre --with-http_ssl_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --add-module=/path/to/our/moudule/do_nothing
    
  4. executar o comando make install

Não havendo erros de compilação, o nginx pode ser iniciado executando sudo /usr/local/nginx/sbin/nginx. Depois basta abrir o browser e introduzir o endereço http://localhost.

Como a principal funcionalidade do módulo é não fazer nada, é expectável que vejamos a página de boas vindas do nginx, sem qualquer problema (e isto é um bom começo).

nginx welcome page

Página de boas vindas

Leave a Comment.

+ 52 = fifty six