nginx extension module development

Apache's plug-ins exist in the form of dynamic libraries and are dynamically loaded through configuration; nginx plug-ins need to be compiled into nginx executable programs, and the same is true for openresty, which directly embeds the lua interpreter into nginx, making it capable of parsing lua scripts. The nginx built-in plugin directory is under src/http/modules.

The process of writing nginx plug-ins is complicated and requires a certain understanding of nginx source code and data structure. nginx implements common functions such as strings, timers, containers (HashTable, Queue, red-black tree), memory pools, logs, network processing, threads, etc. The learning value is very high.

This article is from the Taobao Tengine document, and some comments are made according to my own understanding.

 

 1. hello world module

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>


// hello configuration structure
typedef struct
{
	ngx_int_t hello_counter; // counter configuration
} ngx_http_hello_loc_conf_t;


// context callback function
static ngx_int_t ngx_http_hello_init (ngx_conf_t * cf);
static void *ngx_http_hello_create_loc_conf( ngx_conf_t *cf );

// configure the handler function
static char * ngx_hello_set (ngx_conf_t *, ngx_command_t *, void *);
// Callback
static ngx_int_t ngx_http_hello_handler( ngx_http_request_t * );


// configuration item
static ngx_command_t ngx_http_hello_commands[] = {
	{
		ngx_string("hello_counter"), // configuration name hello_counter
		NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, // Configure as bool type, the value is on/off
		ngx_hello_set, // configuration handler
		NGX_HTTP_LOC_CONF_OFFSET,
		0,
		NULL
	},
	ngx_null_command // null terminated
};

// module context
static ngx_http_module_t ngx_hello_ctx = {
	NULL,
	ngx_http_hello_init, // Called after reading the module configuration
	NULL,
	NULL,
	NULL,
	NULL,
	ngx_http_hello_create_loc_conf, // Called after reading the location configuration (create one for each location)
	NULL
};

// module definition
ngx_module_t ngx_http_hello_module = {
	NGX_MODULE_V1,
	&ngx_hello_ctx,
	ngx_http_hello_commands,
	NGX_HTTP_MODULE,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NGX_MODULE_V1_PADDING
};



static char * ngx_hello_set (ngx_conf_t * cf, ngx_command_t * cmd, void * conf) {
	ngx_http_hello_loc_conf_t *local_conf;
	local_conf = conf;
	char *rv = NULL;

	// Read NGX_CONF_FLAG type parameters
	rv = ngx_conf_set_flag_slot(cf, cmd, conf);

	ngx_conf_log_error( NGX_LOG_INFO, cf, 0, "hello_counter:%d", local_conf->hello_counter );
	return rv;
}


static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf)
{
	ngx_http_hello_loc_conf_t* local_conf = NULL;
	local_conf = ngx_pcalloc (cf-> pool, sizeof (ngx_http_hello_loc_conf_t));
	if ( local_conf == NULL )
	{
		return NULL;
	}

	// Initially set default value
	local_conf-> hello_counter = NGX_CONF_UNSET;
	return local_conf;
}

static ngx_int_t ngx_http_hello_init (ngx_conf_t * cf)
{
	ngx_http_handler_pt *h;
	ngx_http_core_main_conf_t *cmcf;

	cmcf = ngx_http_conf_get_module_main_conf( cf, ngx_http_core_module );

	h = ngx_array_push( &cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers );
	if (h == NULL) {
		return NGX_ERROR;
	}

	// Set the callback function in the NGX_HTTP_CONTENT_PHASE phase
	*h = ngx_http_hello_handler;
	return NGX_OK;
}


static int ngx_hello_visited_times = 0; // number of visits

static ngx_int_t ngx_http_hello_handler( ngx_http_request_t *r ) {
	ngx_int_t rc;
	ngx_buf_t * b;
	ngx_chain_t out;
	ngx_http_hello_loc_conf_t *my_conf;
	ngx_uint_t content_length = 0;
	u_char ngx_hello_string[1024] = {0};
	
	ngx_log_error( NGX_LOG_EMERG, r->connection->log, 0, "ngx_http_hello_handler is called!" );
	
	// get configuration value
	my_conf = ngx_http_get_module_loc_conf( r, ngx_http_hello_module );
	if ( my_conf->hello_counter == NGX_CONF_UNSET || my_conf->hello_counter == 0 )
	{
		ngx_sprintf( ngx_hello_string, "<h1>Non counter</h1>" );
	}
	else
	{
		ngx_sprintf (ngx_hello_string,
					"<h1>Visited Times:%d</h1>",
					++ngx_hello_visited_times );
	}
	
	ngx_log_error( NGX_LOG_EMERG, r->connection->log, 0, "hello_string:%s", ngx_hello_string );
	content_length = ngx_strlen (ngx_hello_string);
	
	// allocate response buffer
	b = ngx_pcalloc (r-> pool, sizeof (ngx_buf_t));
	out.buf = b;	// attach
	out.next = NULL;
	
	b->pos = ngx_hello_string;
	b->last = ngx_hello_string + content_length;
	b->memory = 1;
	b->last_buf = 1;

	// set the response
	ngx_str_set( &r->headers_out.content_type, "text/html" );
	r->headers_out.status = NGX_HTTP_OK;
	r->headers_out.content_length_n = content_length;
	
	// send response
	rc = ngx_http_send_header( r );

	// pass to other filters for processing
	return ngx_http_output_filter( r, &out );
}

 

 2. Compile

Plugin directory:

~/hlmodule

-- config

-- ngx_http_hello_module.c

 

Prepare the config file with the following contents:

ngx_addon_name=ngx_http_hello_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_module.c"

 

Compile:

./configure --prefix=~/nginx --add-module=~/hlmodule
make && make install

 

3. Configure to enable hello_counter 

vi conf/nginx.conf 

location /hello {
	hello_counter on; // enable counting
}

 

4. Test 

hello_counter is set on:

hello counter

 

hello_counter is set off:

off counter

 

 

 Reference link:

Taobao nginx module development  

http://tengine.taobao.org/book/chapter_03.html#hello-handler

official reference

http://nginx.org/en/docs/dev/development_guide.html#core_modules

 

 

 

 

 

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326437381&siteId=291194637