Configuration directives

In one of the previous articles I discussed the basics of HTTP modules. As the power of Nginx comes from configuration files, you definitely need to know how to configure your module and make it ready for variety of environments that users of your module can have. Here is how you can define configuration directives. A configuration directive is described by the structure ngx_command_t:

struct ngx_command_s {
    ngx_str_t             name;
    ngx_uint_t            type;
    char               *(*set)(ngx_conf_t *cf,
                        ngx_command_t *cmd, void *conf);
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};

#define ngx_null_command  { ngx_null_string, 0, NULL, 0, 0, NULL }

typedef struct ngx_command_s     ngx_command_t;

Here name is name of the directive, type is type of the directive, number of arguments and blocks where it might appear. The value of this field is a combination of the following flags:

Flag Meaning
NGX_CONF_NOARGS The directive does not take any arguments
NGX_CONF_TAKE1 … NGX_CONF_TAKE7 The directive takes specified number of arguments
NGX_CONF_TAKE12 The directive takes 1 or 2 arguments
NGX_CONF_TAKE13 The directive takes 1 or 3 arguments
NGX_CONF_TAKE123 The directive takes 1, 2 or 3 arguments
NGX_CONF_TAKE1234 The directive takes 1, 2, 3 or 4 arguments
NGX_CONF_BLOCK An additional argument is a block
NGX_CONF_FLAG The directive is a flag (has only values ‘on’ and ‘off’)
NGX_CONF_ANY The directive takes 0 or more arguments
NGX_CONF_1MORE The directive takes 1 or more arguments
NGX_CONF_2MORE The directive takes 2 or more arguments
NGX_DIRECT_CONF The directive might be specified only in the main configuration file
NGX_MAIN_CONF The directive might be specified only on the main configuration level
NGX_ANY_CONF The directive might be specified on any configuration level
NGX_HTTP_MAIN_CONF The directive might be specified on main level of HTTP-server configuration
NGX_HTTP_SRV_CONF The directive might be specified on virtual server level of HTTP-server configuration
NGX_HTTP_LOC_CONF The directive might be specified on location level of HTTP-server configuration
NGX_HTTP_LMT_CONF The directive might be specified in limit_except block
NGX_HTTP_LIF_CONF The directive might be specified in if() block

set is a handler that Nginx calls whenever it discovers this directive. This handler must return NGX_CONF_OK in case of success (all arguments are correct, no error occured), NGX_CONF_ERROR if there is any error or arbitrary constant string that will be also considered as an error. The string then will be printed in the error message. Additionally you can use a function ngx_conf_log_error to print an error message.

For convenience there is a number of standard handlers implemented that you can use:

Name of the handler
Data type
Type of the field in the configuration that offset points to
ngx_conf_set_flag_slot Flag ngx_flag_t
ngx_conf_set_str_slot String ngx_str_t
ngx_conf_set_str_array_slot Array of srings Pointer to ngx_array_t -> ngx_str_t
ngx_conf_set_keyval_slot Key-value pair vector Pointer to ngx_array_t -> ngx_keyval_t
ngx_conf_set_num_slot Signed integer ngx_int_t
ngx_conf_set_size_slot Length size_t
ngx_conf_set_off_slot Offset off_t
ngx_conf_set_msec_slot Milliseconds ngx_msec_t
ngx_conf_set_sec_slot Seconds time_t
ngx_conf_set_bufs_slot Number and size of buffers ngx_bufs_t
ngx_conf_set_enum_slot Enumeration ngx_uint_t
ngx_conf_set_bitmask_slot Bitmap ngx_uint_t
ngx_conf_set_path_slot Path in the filesystem and number or characters in hashed directory name ngx_path_t
ngx_conf_set_access_slot Access  right ngx_uint_t

conf — is the level of configuration that the directive refers to or 0 if it doesn’t refer to any configuration level;

offset — the offset of the field in the configuration data structure of the module that this directive corresponds to. To calculate the offset you can use the standard offsetof macro;

post — a pointer to a post-processing handler.

A list of directives of a module is described by a vector of structures ngx_command_t that is terminated with a value ngx_null_command. Example:

static ngx_command_t  ngx_http_sample_module_commands[] = {

    { ngx_string("foo"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_str_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_sample_module_loc_conf_t, foo),
      NULL },

    ngx_null_command
};

Here we described a directive foo, that takes 1 argument. The directive will be allowed to appear on HTTP configuration level, virtual server configuration and location configuration. The argument of the directive will be converted into a string and stored into the field foo of module’s location configuration structure.

Once the field commands of ngx_module_t structure is initialized with a pointer to a list of module’s directives (see this article), Nginx will look for these directives while parsing the configuration file.

Nginx processes configuration file from top to bottom and calls handlers of corresponding configuration directives. A handler is allowed to do anything it wants with the configuration, as long as it knows where the data to be manipulated are located. A handler is also allowed to create a new configuration level and process a configuration block that corresponds to that level.

As you can see the behavior of the directive is totally determined by it’s handler, the conf and offset fields are here only for convenience. This makes complex things possible, while making sure that simple configuration parameters are implemented simply with the help of the standard handlers.

When you want to customise a simple parameter of a module, it is sufficient to describe a configuration directive and use one of the standard configuration handlers. Sometimes you might want to implement a handler that activates your module in certain location, e.g.:

static char *
ngx_http_sample_module_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t  *clcf;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_sample_handler;

    return NGX_CONF_OK;
}

Configuration handlers also can process blocks of a configuration file (block is delimited by curly brackets: { } ). Blocks can be handful when the configuration of your module is very complex, such as the configuration of the HTTP module, at which we will take a look later.

This entry was posted in nginx. Bookmark the permalink.

Comments are closed.