<!-- review: finished -->

<a id="developer-guide"></a>

# Guía del desarrollador

<a id="coding-conventions"></a>

## Convenciones de codificación

El código fuente sigue la siguiente estructura y convenciones.

<a id="code-layout"></a>

### Disposición del código

* `auto` — Scripts de compilación
* `src`
  * `core` — Tipos y funciones básicas — cadena, arreglo, registro,
    pool, etc.
  * `event` — Núcleo de eventos
    * `modules` — Módulos de notificación de eventos:
      `epoll`, `kqueue`, `select`
      etc.
  * `http` — Módulo HTTP principal y código común
    * `modules` — Otros módulos HTTP
    * `v2` — HTTP/2
  * `mail` — Módulos de correo
  * `os` — Código específico de la plataforma
    * `unix`
    * `win32`
  * `stream` — Módulos de flujo

<a id="include-files"></a>

### Archivos de inclusión

Las siguientes dos sentencias `#include` deben aparecer al
principio de cada archivo Angie:

```c
#include <ngx_config.h>
#include <ngx_core.h>
```

Además de eso, el código HTTP debe incluir

```c
#include <ngx_http.h>
```

El código de correo debe incluir

```c
#include <ngx_mail.h>
```

El código de flujo debe incluir

```c
#include <ngx_stream.h>
```

<a id="integers"></a>

### Enteros

Para fines generales, el código de Angie utiliza dos tipos enteros:
`ngx_int_t` y `ngx_uint_t`, que son
typedefs para `intptr_t` y `uintptr_t`
respectivamente.

<a id="common-return-codes"></a>

### Códigos de retorno comunes

La mayoría de las funciones en Angie devuelven los siguientes códigos:

* `NGX_OK` — Operación exitosa.
* `NGX_ERROR` — La operación falló.
* `NGX_AGAIN` — Operación incompleta; vuelva a llamar a la función.
* `NGX_DECLINED` — Operación rechazada, por ejemplo, porque está
  deshabilitada en la configuración. Esto nunca es un error.
* `NGX_BUSY` — El recurso no está disponible.
* `NGX_DONE` — Operación completa o continuada en otro lugar.
  También se usa como código de éxito alternativo.
* `NGX_ABORT` — La función fue abortada.
  También se usa como código de error alternativo.

<a id="error-handling"></a>

### Manejo de errores

La macro `ngx_errno` devuelve el último código de error del sistema.
Se asigna a `errno` en plataformas POSIX y a la llamada
`GetLastError()` en Windows.
La macro `ngx_socket_errno` devuelve el último número de error de socket.
Al igual que la macro `ngx_errno`, se asigna a
`errno` en plataformas POSIX.
Se asigna a la llamada `WSAGetLastError()` en Windows.
Acceder a los valores de `ngx_errno` o
`ngx_socket_errno` más de una vez seguidas puede causar
problemas de rendimiento.
Si el valor de error podría usarse varias veces, guárdelo en una variable local
de tipo `ngx_err_t`.
Para establecer errores, use las macros `ngx_set_errno(errno)` y
`ngx_set_socket_errno(errno)`.

Los valores de `ngx_errno` y
`ngx_socket_errno` pueden pasarse a las funciones de registro
`ngx_log_error()` y `ngx_log_debugX()`, en
cuyo caso se añade el texto de error del sistema al mensaje de registro.

Ejemplo usando `ngx_errno`:

```c
ngx_int_t
ngx_my_kill(ngx_pid_t pid, ngx_log_t *log, int signo)
{
    ngx_err_t  err;

    if (kill(pid, signo) == -1) {
        err = ngx_errno;

        ngx_log_error(NGX_LOG_ALERT, log, err, "kill(%P, %d) failed", pid, signo);

        if (err == NGX_ESRCH) {
            return 2;
        }

        return 1;
    }

    return 0;
}
```

<a id="strings"></a>

### Cadenas

<a id="overview"></a>

#### Visión general

Para cadenas en C, Angie utiliza un puntero de tipo carácter sin signo
`u_char *`.

El tipo de cadena de Angie `ngx_str_t` se define como sigue:

```c
typedef struct {
    size_t      len;
    u_char     *data;
} ngx_str_t;
```

El campo `len` almacena la longitud de la cadena y
`data` contiene los datos de la cadena.
La cadena, contenida en `ngx_str_t`, puede o no estar
terminada en nulo tras los bytes de `len`.
En la mayoría de los casos no lo está.
Sin embargo, en ciertas partes del código (por ejemplo, al analizar la configuración),
se sabe que los objetos `ngx_str_t` están terminados en nulo, lo que
simplifica la comparación de cadenas y facilita pasarlas a
llamadas al sistema.

Las operaciones de cadena en Angie se declaran en
`src/core/ngx_string.h`.
Algunas de ellas son envoltorios alrededor de funciones estándar de C:

* `ngx_strcmp()`
* `ngx_strncmp()`
* `ngx_strstr()`
* `ngx_strlen()`
* `ngx_strchr()`
* `ngx_memcmp()`
* `ngx_memset()`
* `ngx_memcpy()`
* `ngx_memmove()`

Otras funciones de cadena son específicas de Angie:

* `ngx_memzero()` — Llena la memoria de ceros.
* `ngx_explicit_memzero()` — Hace lo mismo que
  `ngx_memzero()`, pero esta llamada nunca es eliminada por la
  optimización de eliminación de almacenamiento muerto del compilador.
  Esta función puede usarse para borrar datos sensibles como contraseñas y claves.
* `ngx_cpymem()` — Hace lo mismo que
  `ngx_memcpy()`, pero devuelve la dirección final del destino.
  Esto resulta práctico para anexar varias cadenas en una fila.
* `ngx_movemem()` — Hace lo mismo que
  `ngx_memmove()`, pero devuelve la dirección final del destino.
* `ngx_strlchr()` — Busca un carácter en una cadena,
  delimitada por dos punteros.

Las siguientes funciones realizan conversión de mayúsculas/minúsculas y comparación:

* `ngx_tolower()`
* `ngx_toupper()`
* `ngx_strlow()`
* `ngx_strcasecmp()`
* `ngx_strncasecmp()`

Las siguientes macros simplifican la inicialización de cadenas:

* `ngx_string(text)` — inicializador estático para el
  tipo `ngx_str_t` a partir de la cadena literal C
  `text`
* `ngx_null_string` — inicializador estático de cadena vacía para el
  tipo `ngx_str_t`
* `ngx_str_set(str, text)` — inicializa la cadena
  `str` de tipo `ngx_str_t *` con la literal de cadena C
  `text`
* `ngx_str_null(str)` — inicializa la cadena `str`
  de tipo `ngx_str_t *` con la cadena vacía

<a id="formatting"></a>

#### Formato

Las siguientes funciones de formato admiten tipos específicos de Angie:

* `ngx_sprintf(buf, fmt, ...)`
* `ngx_snprintf(buf, max, fmt, ...)`
* `ngx_slprintf(buf, last, fmt, ...)`
* `ngx_vslprintf(buf, last, fmt, args)`
* `ngx_vsnprintf(buf, max, fmt, args)`

La lista completa de opciones de formato admitidas por estas funciones se
encuentra en `src/core/ngx_string.c`. Algunas de ellas son:

* `%O` — `off_t`
* `%T` — `time_t`
* `%z` — `ssize_t`
* `%i` — `ngx_int_t`
* `%p` — `void *`
* `%V` — `ngx_str_t *`
* `%s` — `u_char *` (terminada en nulo)
* `%*s` — `size_t + u_char *`

Puede anteponer `u` en la mayoría de tipos para hacerlos sin signo.
Para convertir la salida a hexadecimal, use `X` o `x`.

<a id="numeric-conversion"></a>

### Conversión numérica

Varias funciones para conversión numérica están implementadas en Angie.
Las cuatro primeras convierten una cadena de longitud dada a un entero positivo del
tipo indicado.
Devuelven `NGX_ERROR` en caso de error.

* `ngx_atoi(line, n)` — `ngx_int_t`
* `ngx_atosz(line, n)` — `ssize_t`
* `ngx_atoof(line, n)` — `off_t`
* `ngx_atotm(line, n)` — `time_t`

Hay dos funciones adicionales de conversión numérica.
Al igual que las cuatro primeras, devuelven `NGX_ERROR` en caso de error.

* `ngx_atofp(line, n, point)` — Convierte un número de punto fijo
  de longitud dada a un entero positivo del tipo
  `ngx_int_t`.
  El resultado se desplaza a la izquierda por `point` posiciones
  decimales.
  Se espera que la representación en cadena del número tenga no más
  de `point` dígitos fraccionarios.
  Por ejemplo, `ngx_atofp("10.5", 4, 2)` devuelve
  `1050`.
* `ngx_hextoi(line, n)` — Convierte una representación hexadecimal
  de un entero positivo a `ngx_int_t`.

<a id="regular-expressions"></a>

### Expresiones regulares

La interfaz de expresiones regulares en Angie es un envoltorio alrededor
de la biblioteca [PCRE](http://www.pcre.org).
El archivo de encabezado correspondiente es `src/core/ngx_regex.h`.

Para usar una expresión regular para la coincidencia de cadenas, primero debe
compilarse, lo cual generalmente se realiza en la fase de configuración.
Tenga en cuenta que dado que el soporte de PCRE es opcional, todo el código que use la interfaz debe
estar protegido por la macro circundante `NGX_PCRE`:

```c
#if (NGX_PCRE)
ngx_regex_t          *re;
ngx_regex_compile_t   rc;

u_char                errstr[NGX_MAX_CONF_ERRSTR];

ngx_str_t  value = ngx_string("message (\\d\\d\\d).*Codeword is '(?<cw>\\w+)'");

ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

rc.pattern = value;
rc.pool = cf->pool;
rc.err.len = NGX_MAX_CONF_ERRSTR;
rc.err.data = errstr;
/* rc.options can be set to NGX_REGEX_CASELESS */

if (ngx_regex_compile(&rc) != NGX_OK) {
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
    return NGX_CONF_ERROR;
}

re = rc.regex;
#endif
```

Después de una compilación exitosa, los campos `captures` y
`named_captures` en la estructura
`ngx_regex_compile_t` contienen la cantidad de todas las
capturas y capturas con nombre, respectivamente, encontradas en la expresión regular.

La expresión regular compilada puede luego usarse para hacer coincidencias con cadenas:

```c
ngx_int_t  n;
int        captures[(1 + rc.captures) * 3];

ngx_str_t input = ngx_string("This is message 123. Codeword is 'foobar'.");

n = ngx_regex_exec(re, &input, captures, (1 + rc.captures) * 3);
if (n >= 0) {
    /* string matches expression */

} else if (n == NGX_REGEX_NO_MATCHED) {
    /* no match was found */

} else {
    /* some error */
    ngx_log_error(NGX_LOG_ALERT, log, 0, ngx_regex_exec_n " failed: %i", n);
}
```

Los argumentos de `ngx_regex_exec()` son la expresión regular compilada `re`, la cadena a comparar `input`, un arreglo opcional de enteros para contener las `captures` que se encuentren, y el `size` del arreglo.
El tamaño del arreglo `captures` debe ser un múltiplo de tres, tal como lo exige la
[API de PCRE](http://www.pcre.org/original/doc/html/pcreapi.html).
En el ejemplo, el tamaño se calcula a partir del número total de capturas más
uno para la propia cadena coincidente.

Si hay coincidencias, las capturas pueden accederse de la siguiente manera:

```c
u_char     *p;
size_t      size;
ngx_str_t   name, value;

/* todas las capturas */
for (i = 0; i < n * 2; i += 2) {
    value.data = input.data + captures[i];
    value.len = captures[i + 1] - captures[i];
}

/* accediendo a capturas con nombre */

size = rc.name_size;
p = rc.names;

for (i = 0; i < rc.named_captures; i++, p += size) {

    /* nombre de la captura */
    name.data = &p[2];
    name.len = ngx_strlen(name.data);

    n = 2 * ((p[0] << 8) + p[1]);

    /* valor capturado */
    value.data = &input.data[captures[n]];
    value.len = captures[n + 1] - captures[n];
}
```

La función `ngx_regex_exec_array()` acepta un arreglo de elementos
`ngx_regex_elt_t` (que son simplemente expresiones regulares compiladas con nombres asociados),
una cadena a comparar y un log. La función aplica expresiones del arreglo a la cadena hasta que se encuentre una coincidencia o no queden más expresiones.
El valor de retorno es `NGX_OK` cuando hay una coincidencia y
`NGX_DECLINED` en caso contrario, o `NGX_ERROR`
en caso de error.

<a id="time"></a>

### Tiempo

La estructura `ngx_time_t` representa el tiempo con tres tipos separados para segundos, milisegundos y el desplazamiento GMT:

```c
typedef struct {
    time_t      sec;
    ngx_uint_t  msec;
    ngx_int_t   gmtoff;
} ngx_time_t;
```

La estructura `ngx_tm_t` es un alias de
`struct tm` en plataformas UNIX y de `SYSTEMTIME`
en Windows.

Para obtener la hora actual, por lo general es suficiente acceder a una de las variables globales disponibles, que representan el valor del tiempo almacenado en caché en el formato deseado.

Las representaciones en cadena disponibles son:

* `ngx_cached_err_log_time` — Utilizada en entradas de registro de errores:
  `"1970/09/28 12:00:00"`
* `ngx_cached_http_log_time` — Utilizada en entradas de registro de acceso HTTP:
  `"28/Sep/1970:12:00:00 +0600"`
* `ngx_cached_syslog_time` — Utilizada en entradas de syslog:
  `"Sep 28 12:00:00"`
* `ngx_cached_http_time` — Utilizada en encabezados HTTP:
  `"Mon, 28 Sep 1970 06:00:00 GMT"`
* `ngx_cached_http_log_iso8601` — El formato estándar ISO 8601:
  `"1970-09-28T12:00:00+06:00"`

Las macros `ngx_time()` y `ngx_timeofday()` devuelven el valor de tiempo actual en segundos y son la forma preferida de acceder al valor de tiempo en caché.

Para obtener el tiempo explícitamente, use `ngx_gettimeofday()`, que actualiza su argumento (puntero a `struct timeval`).
El tiempo se actualiza siempre cuando Angie regresa al bucle de eventos desde llamadas al sistema.
Para actualizar el tiempo de inmediato, llame a `ngx_time_update()`,
o `ngx_time_sigsafe_update()` si está actualizando el tiempo en el contexto del manejador de señales.

Las siguientes funciones convierten `time_t` en la representación de tiempo desglosada indicada.
La primera función de cada par convierte `time_t` a `ngx_tm_t` y la segunda (con el infijo `_libc_`)
a `struct tm`:

* `ngx_gmtime(), ngx_libc_gmtime()` — Tiempo expresado como UTC
* `ngx_localtime(), ngx_libc_localtime()` — Tiempo expresado
  relativo a la zona horaria local

La función `ngx_http_time(buf, time)` devuelve una representación en cadena adecuada para su uso en encabezados HTTP (por ejemplo, `"Mon, 28 Sep 1970 06:00:00 GMT"`).
La función `ngx_http_cookie_time(buf, time)` devuelve una representación en cadena adecuada para cookies HTTP (`"Thu, 31-Dec-37 23:55:55 GMT"`).

<a id="containers"></a>

## Contenedores

<a id="array"></a>

### Arreglo

El tipo de arreglo Angie `ngx_array_t` se define de la siguiente manera

```c
typedef struct {
    void        *elts;
    ngx_uint_t   nelts;
    size_t       size;
    ngx_uint_t   nalloc;
    ngx_pool_t  *pool;
} ngx_array_t;
```

Los elementos del arreglo están disponibles en el campo `elts`.
El campo `nelts` contiene el número de elementos.
El campo `size` contiene el tamaño de un solo elemento y se establece cuando el arreglo se inicializa.

Utilice la llamada `ngx_array_create(pool, n, size)` para crear un arreglo en un pool, y la llamada `ngx_array_init(array, pool, n, size)` para inicializar un objeto de arreglo que ya ha sido asignado.

```c
ngx_array_t  *a, b;

/* crear un arreglo de cadenas con memoria preasignada para 10 elementos */
a = ngx_array_create(pool, 10, sizeof(ngx_str_t));

/* inicializar arreglo de cadenas para 10 elementos */
ngx_array_init(&b, pool, 10, sizeof(ngx_str_t));
```

Utilice las siguientes funciones para añadir elementos a un arreglo:

* `ngx_array_push(a)` añade un elemento al final y devuelve un puntero a él
* `ngx_array_push_n(a, n)` añade `n` elementos al final
  y devuelve un puntero al primero

Si la cantidad de memoria actualmente asignada no es suficiente para alojar
los nuevos elementos, se asigna un nuevo bloque de memoria y los elementos
existentes se copian en él.
El nuevo bloque de memoria suele ser el doble de grande que el existente.

```c
s = ngx_array_push(a);
ss = ngx_array_push_n(&b, 3);
```

<a id="list"></a>

### Lista

En Angie, una lista es una secuencia de arreglos, optimizada para insertar una cantidad potencialmente grande de elementos.
El tipo de lista `ngx_list_t` se define de la siguiente manera:

```c
typedef struct {
    ngx_list_part_t  *last;
    ngx_list_part_t   part;
    size_t            size;
    ngx_uint_t        nalloc;
    ngx_pool_t       *pool;
} ngx_list_t;
```

Los elementos reales se almacenan en partes de la lista, que se definen como sigue:

```c
typedef struct ngx_list_part_s  ngx_list_part_t;

struct ngx_list_part_s {
    void             *elts;
    ngx_uint_t        nelts;
    ngx_list_part_t  *next;
};
```

Antes de usarla, una lista debe ser inicializada llamando
`ngx_list_init(list, pool, n, size)` o creada llamando
`ngx_list_create(pool, n, size)`.
Ambas funciones toman como argumentos el tamaño de un solo elemento y
una cantidad de elementos por parte de la lista.
Para añadir un elemento a una lista, use la función
`ngx_list_push(list)`.
Para iterar sobre los elementos, acceda directamente a los campos de la lista como se muestra en el
ejemplo:

```c
ngx_str_t        *v;
ngx_uint_t        i;
ngx_list_t       *list;
ngx_list_part_t  *part;

list = ngx_list_create(pool, 100, sizeof(ngx_str_t));
if (list == NULL) { /* error */ }

/* añadir elementos a la lista */

v = ngx_list_push(list);
if (v == NULL) { /* error */ }
ngx_str_set(v, "foo");

v = ngx_list_push(list);
if (v == NULL) { /* error */ }
ngx_str_set(v, "bar");

/* iterar sobre la lista */

part = &list->part;
v = part->elts;

for (i = 0; /* void */; i++) {

    if (i >= part->nelts) {
        if (part->next == NULL) {
            break;
        }

        part = part->next;
        v = part->elts;
        i = 0;
    }

    ngx_do_smth(&v[i]);
}
```

Las listas se utilizan principalmente para encabezados HTTP de entrada y salida.

Las listas no admiten la eliminación de elementos.
Sin embargo, cuando sea necesario, los elementos pueden marcarse internamente como ausentes sin eliminarse realmente de la lista.
Por ejemplo, para marcar como ausentes los encabezados de salida HTTP (que se almacenan como objetos `ngx_table_elt_t`), establezca el campo `hash` en `ngx_table_elt_t` a cero.
Los elementos marcados de esta forma se omiten explícitamente cuando se itera sobre los encabezados.

<a id="queue"></a>

### Cola

En Angie, una cola es una lista doblemente enlazada intrusiva, con cada nodo definido como sigue:

```c
typedef struct ngx_queue_s  ngx_queue_t;

struct ngx_queue_s {
    ngx_queue_t  *prev;
    ngx_queue_t  *next;
};
```

El nodo cabeza de la cola no está enlazado con ningún dato.
Utilice la llamada `ngx_queue_init(q)` para inicializar la cabeza de la lista antes de su uso.
Las colas soportan las siguientes operaciones:

* `ngx_queue_insert_head(h, x)`,
  `ngx_queue_insert_tail(h, x)` — Insertar un nuevo nodo
* `ngx_queue_remove(x)` — Eliminar un nodo de la cola
* `ngx_queue_split(h, q, n)` — Dividir una cola en un nodo,
  devolviendo la cola final en una cola separada
* `ngx_queue_add(h, n)` — Añadir una segunda cola a la primera
* `ngx_queue_head(h)`,
  `ngx_queue_last(h)` — Obtener el primer o último nodo de la cola
* `ngx_queue_sentinel(h)` — Obtener un objeto centinela de cola para terminar
  la iteración en él
* `ngx_queue_data(q, type, link)` — Obtener una referencia al
  inicio de la estructura de datos del nodo de la cola, considerando el desplazamiento
  del campo de la cola en ella

Un ejemplo:

```c
typedef struct {
    ngx_str_t    value;
    ngx_queue_t  queue;
} ngx_foo_t;

ngx_foo_t    *f;
ngx_queue_t   values, *q;

ngx_queue_init(&values);

f = ngx_palloc(pool, sizeof(ngx_foo_t));
if (f == NULL) { /* error */ }
ngx_str_set(&f->value, "foo");

ngx_queue_insert_tail(&values, &f->queue);

/* insert more nodes here */

for (q = ngx_queue_head(&values);
     q != ngx_queue_sentinel(&values);
     q = ngx_queue_next(q))
{
    f = ngx_queue_data(q, ngx_foo_t, queue);

    ngx_do_smth(&f->value);
}
```

<a id="red-black-tree"></a>

### Árbol Rojo-Negro

El archivo de cabecera `src/core/ngx_rbtree.h` proporciona acceso a la implementación eficiente de árboles rojo-negro.

```c
typedef struct {
    ngx_rbtree_t       rbtree;
    ngx_rbtree_node_t  sentinel;

    /* custom per-tree data here */
} my_tree_t;

typedef struct {
    ngx_rbtree_node_t  rbnode;

    /* custom per-node data */
    foo_t              val;
} my_node_t;
```

Para tratar un árbol en su conjunto, necesitas dos nodos: la raíz y el centinela.
Generalmente, se añaden a una estructura personalizada, lo que te permite
organizar tus datos en un árbol en el que las hojas contienen un enlace a tus datos o incrustan
tus datos.

Para inicializar un árbol:

```c
my_tree_t  root;

ngx_rbtree_init(&root.rbtree, &root.sentinel, insert_value_function);
```

Para recorrer un árbol e insertar nuevos valores, usa las funciones
"`insert_value`".
Por ejemplo, la función `ngx_str_rbtree_insert_value` maneja
el tipo `ngx_str_t`.
Sus argumentos son punteros al nodo raíz de la inserción, al nodo recién creado
para añadir y al centinela del árbol.

```c
void ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
                                 ngx_rbtree_node_t *node,
                                 ngx_rbtree_node_t *sentinel)
```

El recorrido es bastante directo y puede demostrarse con el siguiente patrón de función de búsqueda:

```c
my_node_t *
my_rbtree_lookup(ngx_rbtree_t *rbtree, foo_t *val, uint32_t hash)
{
    ngx_int_t           rc;
    my_node_t          *n;
    ngx_rbtree_node_t  *node, *sentinel;

    node = rbtree->root;
    sentinel = rbtree->sentinel;

    while (node != sentinel) {

        n = (my_node_t *) node;

        if (hash != node->key) {
            node = (hash < node->key) ? node->left : node->right;
            continue;
        }

        rc = compare(val, node->val);

        if (rc < 0) {
            node = node->left;
            continue;
        }

        if (rc > 0) {
            node = node->right;
            continue;
        }

        return n;
    }

    return NULL;
}
```

La función `compare()` es una función de comparación clásica que
devuelve un valor menor que cero, igual a cero o mayor que cero.
Para acelerar las búsquedas y evitar comparar objetos de usuario que pueden ser grandes, se utiliza un campo hash entero.

Para añadir un nodo al árbol, reserva un nuevo nodo, inicialízalo y llama a
`ngx_rbtree_insert()`:

```c
my_node_t          *my_node;
ngx_rbtree_node_t  *node;

my_node = ngx_palloc(...);
init_custom_data(&my_node->val);

node = &my_node->rbnode;
node->key = create_key(my_node->val);

ngx_rbtree_insert(&root->rbtree, node);
```

Para eliminar un nodo, llama a la función `ngx_rbtree_delete()`:

```c
ngx_rbtree_delete(&root->rbtree, node);
```

<a id="hash-1"></a>

### Hash

Las funciones de tablas hash se declaran en `src/core/ngx_hash.h`.
Se admite coincidencia exacta y con comodines.
La segunda requiere una configuración adicional y se describe en una sección separada a continuación.

Antes de inicializar un hash, necesitas conocer el número de elementos que contendrá para que Angie pueda construirlo de forma óptima.
Dos parámetros que deben configurarse son `max_size` y `bucket_size`, como se detalla en un [documento](https://es.angie.software//angie/docs/configuration/configfile.md#configure-hashes) separado.
Generalmente, son configurables por el usuario.
La configuración de inicialización de hash se almacena con el tipo `ngx_hash_init_t`, y el propio hash es `ngx_hash_t`:

```c
ngx_hash_t       foo_hash;
ngx_hash_init_t  hash;

hash.hash = &foo_hash;
hash.key = ngx_hash_key;
hash.max_size = 512;
hash.bucket_size = ngx_align(64, ngx_cacheline_size);
hash.name = "foo_hash";
hash.pool = cf->pool;
hash.temp_pool = cf->temp_pool;
```

`key` es un puntero a una función que crea la clave entera del hash a partir de una cadena.
Existen dos funciones genéricas de creación de claves:
`ngx_hash_key(data, len)` y
`ngx_hash_key_lc(data, len)`.
La segunda convierte una cadena a todos los caracteres en minúscula, por lo que la cadena pasada debe ser modificable.
Si eso no es así, pasa la bandera `NGX_HASH_READONLY_KEY` a la función, inicializando el array de claves (ver más abajo).

Las claves del hash se almacenan en `ngx_hash_keys_arrays_t` y
se inicializan con `ngx_hash_keys_array_init(arr, type)`:
El segundo parámetro (`type`) controla la cantidad de recursos preasignados para el hash y puede ser `NGX_HASH_SMALL` o
`NGX_HASH_LARGE`.
Este último es adecuado si esperas que el hash contenga miles de
elementos.

```c
ngx_hash_keys_arrays_t  foo_keys;

foo_keys.pool = cf->pool;
foo_keys.temp_pool = cf->temp_pool;

ngx_hash_keys_array_init(&foo_keys, NGX_HASH_SMALL);
```

Para insertar claves en un array de claves hash, utiliza la función
`ngx_hash_add_key(keys_array, key, value, flags)`:

```c
ngx_str_t k1 = ngx_string("key1");
ngx_str_t k2 = ngx_string("key2");

ngx_hash_add_key(&foo_keys, &k1, &my_data_ptr_1, NGX_HASH_READONLY_KEY);
ngx_hash_add_key(&foo_keys, &k2, &my_data_ptr_2, NGX_HASH_READONLY_KEY);
```

Para construir la tabla hash, llama a la función
`ngx_hash_init(hinit, key_names, nelts)`:

```c
ngx_hash_init(&hash, foo_keys.keys.elts, foo_keys.keys.nelts);
```

La función falla si los parámetros `max_size` o
`bucket_size` no son lo suficientemente grandes.

Cuando se construye el hash, usa la función
`ngx_hash_find(hash, key, name, len)` para buscar elementos:

```c
my_data_t   *data;
ngx_uint_t   key;

key = ngx_hash_key(k1.data, k1.len);

data = ngx_hash_find(&foo_hash, key, k1.data, k1.len);
if (data == NULL) {
    /* key not found */
}
```

<a id="wildcard-matching"></a>

#### Coincidencia con comodines

Para crear un hash que funcione con comodines, utiliza el tipo
`ngx_hash_combined_t`.
Incluye el tipo hash descrito arriba y tiene dos arrays de claves adicionales:
`dns_wc_head` y `dns_wc_tail`.
La inicialización de las propiedades básicas es similar a la de un hash normal:

```c
ngx_hash_init_t      hash
ngx_hash_combined_t  foo_hash;

hash.hash = &foo_hash.hash;
hash.key = ...;
```

Es posible añadir claves con comodines usando la bandera
`NGX_HASH_WILDCARD_KEY`:

```c
/* k1 = ".example.org"; */
/* k2 = "foo.*";        */
ngx_hash_add_key(&foo_keys, &k1, &data1, NGX_HASH_WILDCARD_KEY);
ngx_hash_add_key(&foo_keys, &k2, &data2, NGX_HASH_WILDCARD_KEY);
```

La función reconoce comodines y añade claves a los arrays correspondientes.
Por favor, consulta la documentación del módulo
[Map](https://es.angie.software//angie/docs/configuration/modules/http/http_map.md#http-map) para la descripción de la sintaxis de comodines y del algoritmo de coincidencia.

Dependiendo del contenido de las claves añadidas, podría ser necesario inicializar hasta tres arrays de claves: uno para la coincidencia exacta (descrita arriba) y dos más para habilitar la coincidencia desde el inicio o desde el final de una cadena:

```c
if (foo_keys.dns_wc_head.nelts) {

    ngx_qsort(foo_keys.dns_wc_head.elts,
              (size_t) foo_keys.dns_wc_head.nelts,
              sizeof(ngx_hash_key_t),
              cmp_dns_wildcards);

    hash.hash = NULL;
    hash.temp_pool = pool;

    if (ngx_hash_wildcard_init(&hash, foo_keys.dns_wc_head.elts,
                               foo_keys.dns_wc_head.nelts)
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    foo_hash.wc_head = (ngx_hash_wildcard_t *) hash.hash;
}
```

El array de claves necesita ser ordenado, y los resultados de inicialización deben añadirse
al hash combinado.
La inicialización del array `dns_wc_tail` se hace de forma similar.

La búsqueda en un hash combinado se maneja mediante
`ngx_hash_find_combined(chash, key, name, len)`:

```c
/* key = "bar.example.org"; - will match ".example.org" */
/* key = "foo.example.com"; - will match "foo.*"        */

hkey = ngx_hash_key(key.data, key.len);
res = ngx_hash_find_combined(&foo_hash, hkey, key.data, key.len);
```

<a id="memory-management"></a>

## Gestión de memoria

<a id="heap"></a>

### Heap

Para asignar memoria desde el heap del sistema, use las siguientes funciones:

* `ngx_alloc(size, log)` — Asignar memoria desde el heap del sistema.
  Este es un envoltorio alrededor de `malloc()` con soporte de registro.
  Los errores de asignación y la información de depuración se registran en `log`.
* `ngx_calloc(size, log)` — Asignar memoria desde el heap del sistema
  como `ngx_alloc()`, pero llena la memoria con ceros después
  de la asignación.
* `ngx_memalign(alignment, size, log)` — Asignar memoria alineada
  desde el heap del sistema.
  Este es un envoltorio alrededor de `posix_memalign()`
  en aquellas plataformas que proporcionan esa función.
  En caso contrario, la implementación recurre a `ngx_alloc()` que
  proporciona el alineamiento máximo.
* `ngx_free(p)` — Liberar la memoria asignada.
  Este es un envoltorio alrededor de `free()`.

<a id="pooling"></a>

### Pooling

La mayoría de las asignaciones de Angie se realizan en pools.
La memoria asignada en un pool de Angie se libera automáticamente cuando el pool se
destruye.
Esto proporciona un buen rendimiento de asignación y facilita el control de la memoria.

Un pool internamente asigna objetos en bloques continuos de memoria.
Una vez que un bloque se llena, se asigna uno nuevo y se añade a la lista de bloques de memoria del pool.
Cuando la asignación solicitada es demasiado grande para caber en un bloque, la solicitud
se reenvía al asignador del sistema y el
puntero devuelto se almacena en el pool para su liberación posterior.

El tipo para los pools de Angie es `ngx_pool_t`.
Las siguientes operaciones son compatibles:

* `ngx_create_pool(size, log)` — Crear un pool con el tamaño de
  bloque especificado.
  El objeto pool devuelto también se asigna en el pool.
  El `size`
  debe ser al menos `NGX_MIN_POOL_SIZE`
  y múltiplo de `NGX_POOL_ALIGNMENT`.
* `ngx_destroy_pool(pool)` — Liberar toda la memoria del pool, incluyendo
  el propio objeto pool.
* `ngx_palloc(pool, size)` — Asignar memoria alineada desde el
  pool especificado.
* `ngx_pcalloc(pool, size)` — Asignar memoria alineada
  desde el pool especificado y llenarla con ceros.
* `ngx_pnalloc(pool, size)` — Asignar memoria no alineada desde el
  pool especificado.
  Mayormente utilizada para asignar cadenas.
* `ngx_pfree(pool, p)` — Liberar la memoria que fue previamente
  asignada en el pool especificado.
  Solo las asignaciones que resulten de solicitudes reenviadas al asignador del sistema
  pueden ser liberadas.

```c
u_char      *p;
ngx_str_t   *s;
ngx_pool_t  *pool;

pool = ngx_create_pool(1024, log);
if (pool == NULL) { /* error */ }

s = ngx_palloc(pool, sizeof(ngx_str_t));
if (s == NULL) { /* error */ }
ngx_str_set(s, "foo");

p = ngx_pnalloc(pool, 3);
if (p == NULL) { /* error */ }
ngx_memcpy(p, "foo", 3);
```

Los enlaces de cadena (`ngx_chain_t`) se utilizan activamente en Angie,
por lo que la implementación del pool de Angie proporciona una forma de reutilizarlos.
El campo `chain` de `ngx_pool_t` mantiene una
lista de enlaces asignados previamente listos para su reutilización.
Para una asignación eficiente de un enlace de cadena en un pool, use la
función `ngx_alloc_chain_link(pool)`.
Esta función busca un enlace de cadena libre en la lista del pool y asigna un nuevo
enlace de cadena si la lista del pool está vacía.
Para liberar un enlace, llame a la función `ngx_free_chain(pool, cl)`.

Se pueden registrar manejadores de limpieza en un pool.
Un manejador de limpieza es una función de callback con un argumento que se llama cuando el pool se
destruye.
Un pool suele estar vinculado a un objeto específico de Angie (como una solicitud HTTP) y se
destruye cuando el objeto llega al final de su vida útil.
Registrar una limpieza de pool es una forma conveniente de liberar recursos, cerrar
descriptores de archivos o hacer ajustes finales a los datos compartidos asociados con
el objeto principal.

Para registrar una limpieza de pool, llame a
`ngx_pool_cleanup_add(pool, size)`, que devuelve un
puntero `ngx_pool_cleanup_t` para
ser rellenado por el llamador.
Use el argumento `size` para asignar contexto para el manejador de limpieza.

```c
ngx_pool_cleanup_t  *cln;

cln = ngx_pool_cleanup_add(pool, 0);
if (cln == NULL) { /* error */ }

cln->handler = ngx_my_cleanup;
cln->data = "foo";

...

static void
ngx_my_cleanup(void *data)
{
    u_char  *msg = data;

    ngx_do_smth(msg);
}
```

<a id="shared-memory"></a>

### Memoria compartida

Angie utiliza memoria compartida para compartir datos comunes entre procesos.
La función `ngx_shared_memory_add(cf, name, size, tag)` añade
una nueva entrada de memoria compartida `ngx_shm_zone_t` a un ciclo.
La función recibe el `name` y el `size`
de la zona.
Cada zona compartida debe tener un nombre único.
Si ya existe una entrada de zona compartida con el `name` y
`tag` proporcionados, se reutiliza la entrada de zona existente.
La función falla con un error si una entrada existente con el mismo nombre tiene una
etiqueta diferente.
Normalmente, la dirección de la estructura del módulo se pasa como
`tag`, lo que permite reutilizar zonas compartidas por nombre dentro
de un módulo de Angie.

La estructura de entrada de memoria compartida `ngx_shm_zone_t` tiene los
siguientes campos:

* `init` — Callback de inicialización, llamado después de que la zona compartida
  se mapea a la memoria real
* `data` — Contexto de datos, utilizado para pasar datos arbitrarios al
  callback `init`
* `noreuse` — Bandera que deshabilita la reutilización de una zona compartida del
  ciclo antiguo
* `tag` — Etiqueta de la zona compartida
* `shm` — Objeto específico de la plataforma de tipo
  `ngx_shm_t`, que tiene al menos los siguientes campos:
  * `addr` — Dirección de memoria compartida mapeada, inicialmente NULL
  * `size` — Tamaño de la memoria compartida
  * `name` — Nombre de la memoria compartida
  * `log` — Registro de la memoria compartida
  * `exists` — Bandera que indica que la memoria compartida fue heredada
    del proceso maestro (específico de Windows)

Las entradas de zona compartida se mapean a la memoria real en
`ngx_init_cycle()` después de que se analiza la configuración.
En sistemas POSIX, se utiliza la llamada al sistema `mmap()` para crear el
mapeo anónimo compartido.
En Windows, se utiliza el par `CreateFileMapping()`/
`MapViewOfFileEx()`.

Para asignar memoria compartida, Angie proporciona el slab pool
de tipo `ngx_slab_pool_t`.
Se crea automáticamente un slab pool para asignar memoria en cada zona compartida de Angie.
El pool se encuentra al principio de la zona compartida y se puede acceder mediante
la expresión `(ngx_slab_pool_t *) shm_zone->shm.addr`.
Para asignar memoria en una zona compartida, llame a
`ngx_slab_alloc(pool, size)` o
`ngx_slab_calloc(pool, size)`.
Para liberar memoria, llame a `ngx_slab_free(pool, p)`.

El slab pool divide toda la zona compartida en páginas.
Cada página se utiliza para asignar objetos del mismo tamaño.
El tamaño especificado debe ser una potencia de 2 y mayor que el tamaño mínimo de
8 bytes.
Los valores no conformes se redondean hacia arriba.
Una máscara de bits para cada página rastrea qué bloques están en uso y cuáles están libres para
asignación.
Para tamaños mayores que media página (que normalmente es 2048 bytes), la asignación se
realiza de una página completa a la vez.

Para proteger los datos en la memoria compartida del acceso concurrente, utilice el mutex
disponible en el campo `mutex` de
`ngx_slab_pool_t`.
Un mutex se utiliza más comúnmente por el slab pool al asignar y liberar
memoria, pero se puede usar para proteger cualquier otra estructura de datos de usuario asignada
en la zona compartida.
Para bloquear o desbloquear un mutex, llame a
`ngx_shmtx_lock(&shpool->mutex)` o
`ngx_shmtx_unlock(&shpool->mutex)` respectivamente.

```c
ngx_str_t        name;
ngx_foo_ctx_t   *ctx;
ngx_shm_zone_t  *shm_zone;

ngx_str_set(&name, "foo");

/* allocate shared zone context */
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_foo_ctx_t));
if (ctx == NULL) {
    /* error */
}

/* add an entry for 64k shared zone */
shm_zone = ngx_shared_memory_add(cf, &name, 65536, &ngx_foo_module);
if (shm_zone == NULL) {
    /* error */
}

/* register init callback and context */
shm_zone->init = ngx_foo_init_zone;
shm_zone->data = ctx;


...


static ngx_int_t
ngx_foo_init_zone(ngx_shm_zone_t *shm_zone, void *data)
{
    ngx_foo_ctx_t  *octx = data;

    size_t            len;
    ngx_foo_ctx_t    *ctx;
    ngx_slab_pool_t  *shpool;

    value = shm_zone->data;

    if (octx) {
        /* reusing a shared zone from old cycle */
        ctx->value = octx->value;
        return NGX_OK;
    }

    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;

    if (shm_zone->shm.exists) {
        /* initialize shared zone context in Windows Angie worker */
        ctx->value = shpool->data;
        return NGX_OK;
    }

    /* initialize shared zone */

    ctx->value = ngx_slab_alloc(shpool, sizeof(ngx_uint_t));
    if (ctx->value == NULL) {
        return NGX_ERROR;
    }

    shpool->data = ctx->value;

    return NGX_OK;
}
```

<a id="logging-1"></a>

### Registro

Para el registro, Angie utiliza objetos `ngx_log_t`.
El registrador de Angie admite varios tipos de salida:

* stderr — registro a la salida estándar de error (stderr)
* file — registro a un archivo
* syslog — registro a syslog
* memory — registro en el almacenamiento de memoria interna para fines de desarrollo; la memoria
  puede ser accedida más tarde con un depurador

Una instancia de registrador puede ser una cadena de registradores, vinculados entre sí mediante
el campo `next`.
En este caso, cada mensaje se escribe en todos los registradores de la cadena.

Para cada registrador, un nivel de severidad controla qué mensajes se escriben en el
registro (solo se registran los eventos asignados a ese nivel o superior).
Los siguientes niveles de severidad son compatibles:

* `NGX_LOG_EMERG`
* `NGX_LOG_ALERT`
* `NGX_LOG_CRIT`
* `NGX_LOG_ERR`
* `NGX_LOG_WARN`
* `NGX_LOG_NOTICE`
* `NGX_LOG_INFO`
* `NGX_LOG_DEBUG`

Para el registro de depuración, también se verifica la máscara de depuración.
Las máscaras de depuración son:

* `NGX_LOG_DEBUG_CORE`
* `NGX_LOG_DEBUG_ALLOC`
* `NGX_LOG_DEBUG_MUTEX`
* `NGX_LOG_DEBUG_EVENT`
* `NGX_LOG_DEBUG_HTTP`
* `NGX_LOG_DEBUG_MAIL`
* `NGX_LOG_DEBUG_STREAM`

Normalmente, los registradores se crean por el código existente de Angie a partir de
las directivas `error_log` y están disponibles en casi todas las etapas
del procesamiento en el ciclo, la configuración, la conexión del cliente y otros objetos.

Angie proporciona las siguientes macros de registro:

* `ngx_log_error(level, log, err, fmt, ...)` — registro de errores
* `ngx_log_debug0(level, log, err, fmt)`,
  `ngx_log_debug1(level, log, err, fmt, arg1)` etc. — registro de depuración
  con hasta ocho argumentos de formato compatibles

Un mensaje de registro se formatea en un búfer de tamaño
`NGX_MAX_ERROR_STR` (actualmente, 2048 bytes) en la pila.
El mensaje se antepone con el nivel de severidad, el ID de proceso (PID), el
ID de conexión (almacenado en `log->connection`), y el texto de error del sistema.
Para los mensajes que no son de depuración, `log->handler` también se llama para
anteponer información más específica al mensaje de registro.
El módulo HTTP establece la función `ngx_http_log_error()` como manejador de registro
para registrar direcciones de cliente y servidor, acción actual (almacenada en
`log->action`), línea de la solicitud del cliente, nombre del servidor, etc.

```c
/* specify what is currently done */
log->action = "sending mp4 to client";

/* error and debug log */
ngx_log_error(NGX_LOG_INFO, c->log, 0, "client prematurely
              closed connection");

ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
               "mp4 start:%ui, length:%ui", mp4->start, mp4->length);
```

El ejemplo anterior da como resultado entradas de registro como estas:

```text
2016/09/16 22:08:52 [info] 17445#0: *1 client prematurely closed connection while
sending mp4 to client, client: 127.0.0.1, server: , request: "GET /file.mp4 HTTP/1.1"
2016/09/16 23:28:33 [debug] 22140#0: *1 mp4 start:0, length:10000
```

<a id="cycles"></a>

### Ciclos

Un objeto de ciclo almacena el contexto de ejecución de Angie creado a partir de una configuración específica.
Su tipo es `ngx_cycle_t`.
El ciclo actual es referenciado por la variable global `ngx_cycle` y heredado por los workers de Angie cuando se inician.
Cada vez que se recarga la configuración de Angie, se crea un nuevo ciclo a partir de la nueva configuración de Angie; el ciclo antiguo normalmente se elimina después de que el nuevo se crea exitosamente.

Un ciclo es creado por la función `ngx_init_cycle()`, que toma el ciclo anterior como argumento.
La función localiza el archivo de configuración del ciclo anterior y hereda tantos recursos como sea posible del ciclo anterior.
Un ciclo de marcador de posición llamado "init cycle" se crea al inicio de Angie, y luego es reemplazado por un ciclo real construido a partir de la configuración.

Los miembros del ciclo incluyen:

* `pool` — Pool del ciclo.
  Creado para cada nuevo ciclo.
* `log` — Registro del ciclo.
  Inicialmente heredado del ciclo antiguo, se configura para apuntar a `new_log` después de que se lee la configuración.
* `new_log` — Registro del ciclo, creado por la configuración.
  Se ve afectado por la directiva `error_log` de ámbito raíz.
* `connections`, `connection_n` —
  Array de conexiones de tipo `ngx_connection_t`, creado por el módulo de eventos al inicializar cada worker de Angie.
  La directiva `worker_connections` en la configuración de Angie establece el número de conexiones `connection_n`.
* `free_connections`,
  `free_connection_n` — Lista y número de conexiones actualmente disponibles.
  Si no hay conexiones disponibles, un worker de Angie rechaza aceptar nuevos clientes o conectarse a servidores upstream.
* `files`, `files_n` — Array para mapear descriptores de archivo a conexiones de Angie.
  Este mapeo es utilizado por los módulos de eventos que tienen la bandera `NGX_USE_FD_EVENT` (actualmente, son `poll` y `devpoll`).
* `conf_ctx` — Array de configuraciones de módulos principales.
  Las configuraciones se crean y llenan al leer los archivos de configuración de Angie.
* `modules`, `modules_n` — Array de módulos de tipo `ngx_module_t`, tanto estáticos como dinámicos, cargados por la configuración actual.
* `listening` — Array de objetos de escucha de tipo `ngx_listening_t`.
  Los objetos de escucha normalmente se agregan mediante la directiva `listen` de diferentes módulos que llaman a la función `ngx_create_listening()`.
  Los sockets de escucha se crean basándose en los objetos de escucha.
* `paths` — Array de rutas de tipo `ngx_path_t`.
  Las rutas se agregan llamando a la función `ngx_add_path()` desde módulos que van a operar en ciertos directorios.
  Estos directorios son creados por Angie después de leer la configuración, si faltan.
  Además, se pueden agregar dos manejadores para cada ruta:
  * path loader — Se ejecuta solo una vez en 60 segundos después de iniciar o recargar Angie.
    Normalmente, el loader lee el directorio y almacena datos en la memoria compartida de Angie.
    El manejador es llamado desde el proceso dedicado de Angie "cache loader".
  * path manager — Se ejecuta periódicamente.
    Normalmente, el manager elimina archivos antiguos del directorio y actualiza la memoria de Angie para reflejar los cambios.
    El manejador es llamado desde el proceso dedicado "cache manager".
* `open_files` — Lista de objetos de archivo abierto de tipo `ngx_open_file_t`, que se crean llamando a la función `ngx_conf_open_file()`.
  Actualmente, Angie usa este tipo de archivos abiertos para el registro.
  Después de leer la configuración, Angie abre todos los archivos en la lista `open_files` y almacena cada descriptor de archivo en el campo `fd` del objeto.
  Los archivos se abren en modo de anexado y se crean si faltan.
  Los archivos en la lista son reabiertos por los workers de Angie al recibir la señal de reapertura (más comúnmente `USR1`).
  En este caso, el descriptor en el campo `fd` cambia a un nuevo valor.
* `shared_memory` — Lista de zonas de memoria compartida, cada una agregada llamando a la función `ngx_shared_memory_add()`.
  Las zonas compartidas se mapean al mismo rango de direcciones en todos los procesos de Angie y se utilizan para compartir datos comunes, por ejemplo el árbol en memoria de la caché HTTP.

<a id="buffer"></a>

### Buffer

Para operaciones de entrada/salida, Angie proporciona el tipo de buffer `ngx_buf_t`.
Normalmente, se utiliza para contener datos que deben escribirse en un destino o leerse desde una fuente.
Un buffer puede hacer referencia a datos en la memoria o en un archivo y, técnicamente, es posible que un buffer haga referencia a ambos al mismo tiempo.
La memoria para el buffer se asigna por separado y no está relacionada con la estructura del buffer `ngx_buf_t`.

La estructura `ngx_buf_t` tiene los siguientes campos:

* `start`, `end` — Los límites del bloque de memoria asignado para el buffer.
* `pos`, `last` — Los límites del buffer de memoria; normalmente un subrango de `start` .. `end`.
* `file_pos`, `file_last` — Los límites de un buffer de archivo, expresados como desplazamientos desde el inicio del archivo.
* `tag` — Valor único usado para distinguir buffers; creado por diferentes módulos de Angie, usualmente con el propósito de reutilización de buffers.
* `file` — Objeto de archivo.
* `temporary` — Bandera que indica que el buffer hace referencia a memoria escribible.
* `memory` — Bandera que indica que el buffer hace referencia a memoria de solo lectura.
* `in_file` — Bandera que indica que el buffer hace referencia a datos en un archivo.
* `flush` — Bandera que indica que todos los datos anteriores al buffer deben ser vaciados.
* `recycled` — Bandera que indica que el buffer puede reutilizarse y debe consumirse lo antes posible.
* `sync` — Bandera que indica que el buffer no transporta datos ni señal especial como `flush` o `last_buf`.
  Por defecto, Angie considera tales buffers como una condición de error, pero esta bandera indica a Angie que omita la comprobación de errores.
* `last_buf` — Bandera que indica que el buffer es el último en la salida.
* `last_in_chain` — Bandera que indica que no hay más buffers de datos en una solicitud o subsolicitud.
* `shadow` — Referencia a otro buffer ("shadow") relacionado con el buffer actual, usualmente en el sentido de que el buffer utiliza datos del shadow.
  Cuando el buffer se consume, normalmente el buffer shadow también se marca como consumido.
* `last_shadow` — Bandera que indica que el buffer es el último que hace referencia a un buffer shadow particular.
* `temp_file` — Bandera que indica que el buffer se encuentra en un archivo temporal.

Para operaciones de entrada y salida, los buffers se enlazan en cadenas.
Una cadena es una secuencia de eslabones de cadena del tipo `ngx_chain_t`,
definidos como sigue:

```c
typedef struct ngx_chain_s  ngx_chain_t;

struct ngx_chain_s {
    ngx_buf_t    *buf;
    ngx_chain_t  *next;
};
```

Cada eslabón de la cadena mantiene una referencia a su buffer y una referencia al siguiente eslabón de la cadena.

Un ejemplo de uso de buffers y cadenas:

```c
ngx_chain_t *
ngx_get_my_chain(ngx_pool_t *pool)
{
    ngx_buf_t    *b;
    ngx_chain_t  *out, *cl, **ll;

    /* first buf */
    cl = ngx_alloc_chain_link(pool);
    if (cl == NULL) { /* error */ }

    b = ngx_calloc_buf(pool);
    if (b == NULL) { /* error */ }

    b->start = (u_char *) "foo";
    b->pos = b->start;
    b->end = b->start + 3;
    b->last = b->end;
    b->memory = 1; /* read-only memory */

    cl->buf = b;
    out = cl;
    ll = &cl->next;

    /* second buf */
    cl = ngx_alloc_chain_link(pool);
    if (cl == NULL) { /* error */ }

    b = ngx_create_temp_buf(pool, 3);
    if (b == NULL) { /* error */ }

    b->last = ngx_cpymem(b->last, "foo", 3);

    cl->buf = b;
    cl->next = NULL;
    *ll = cl;

    return out;
}
```

<a id="networking"></a>

## Redes

<a id="connections"></a>

### Conexión

El tipo de conexión `ngx_connection_t` es un envoltorio alrededor de un descriptor de socket.
Incluye los siguientes campos:

* `fd` — Descriptor de socket
* `data` — Contexto arbitrario de la conexión.
  Normalmente, es un puntero a un objeto de nivel superior construido sobre la conexión, como una solicitud HTTP o una sesión de Stream.
* `read`, `write` — Eventos de lectura y escritura para la conexión.
* `recv`, `send`,
  `recv_chain`, `send_chain` — Operaciones de E/S para la conexión.
* `pool` — Pool de conexiones.
* `log` — Registro de la conexión.
* `sockaddr`, `socklen`,
  `addr_text` — Dirección de socket remota en formas binaria y textual.
* `local_sockaddr`, `local_socklen` — Dirección de socket local en forma binaria.
  Inicialmente, estos campos están vacíos.
  Usa la función `ngx_connection_local_sockaddr()` para obtener la dirección del socket local.
* `proxy_protocol_addr`, `proxy_protocol_port`
  — Dirección y puerto del cliente del protocolo PROXY, si el protocolo PROXY está habilitado para la conexión.
* `ssl` — Contexto SSL para la conexión.
* `reusable` — Bandera que indica que la conexión está en un estado que la hace elegible para reutilización.
* `close` — Bandera que indica que la conexión está siendo reutilizada y debe cerrarse.

Una conexión Angie puede encapsular de manera transparente la capa SSL.
En este caso, el campo `ssl` de la conexión contiene un puntero a una estructura `ngx_ssl_connection_t`, que mantiene todos los datos relacionados con SSL para la conexión, incluyendo `SSL_CTX` y `SSL`.
Los manejadores `recv`, `send`,
`recv_chain` y `send_chain` también se configuran como funciones habilitadas para SSL.

La directiva `worker_connections` en la configuración de Angie limita el número de conexiones por worker de Angie.
Todas las estructuras de conexión se crean de antemano cuando un worker inicia y se almacenan en el campo `connections` del objeto ciclo.
Para recuperar una estructura de conexión, usa la función `ngx_get_connection(s, log)`.
Toma como argumento `s` un descriptor de socket, que debe envolverse en una estructura de conexión.

Debido a que el número de conexiones por worker está limitado, Angie proporciona una forma de obtener conexiones que están actualmente en uso.
Para habilitar o deshabilitar la reutilización de una conexión, llama a la función `ngx_reusable_connection(c, reusable)`.
Llamar `ngx_reusable_connection(c, 1)` establece la bandera `reuse` en la estructura de conexión e inserta la conexión en la cola `reusable_connections_queue` del ciclo.
Cada vez que `ngx_get_connection()` detecta que no hay conexiones disponibles en la lista `free_connections` del ciclo, llama a `ngx_drain_connections()` para liberar un número específico de conexiones reutilizables.
Para cada una de esas conexiones, se establece la bandera `close` y se llama a su manejador de lectura, que debe liberar la conexión llamando a `ngx_close_connection(c)` y dejarla disponible para su reutilización.
Para salir del estado cuando una conexión puede reutilizarse, se llama a `ngx_reusable_connection(c, 0)`.
Las conexiones de cliente HTTP son un ejemplo de conexiones reutilizables en Angie; se marcan como reutilizables hasta que se recibe el primer byte de solicitud del cliente.

<a id="events-1"></a>

## Eventos

<a id="event"></a>

### Evento

El objeto de evento `ngx_event_t` en Angie proporciona un mecanismo para notificar que ha ocurrido un evento específico.

Los campos en `ngx_event_t` incluyen:

* `data` — Contexto de evento arbitrario utilizado en los manejadores de eventos, normalmente como puntero a una conexión relacionada con el evento.
* `handler` — Función de devolución de llamada que se invocará cuando ocurra el evento.
* `write` — Bandera que indica un evento de escritura.
  La ausencia de la bandera indica un evento de lectura.
* `active` — Bandera que indica que el evento está registrado para recibir notificaciones de E/S, normalmente desde mecanismos de notificación como `epoll`, `kqueue`, `poll`.
* `ready` — Bandera que indica que el evento ha recibido una notificación de E/S.
* `delayed` — Bandera que indica que la E/S está retrasada debido a la limitación de velocidad.
* `timer` — Nodo de árbol rojo-negro para insertar el evento en el árbol de temporizadores.
* `timer_set` — Bandera que indica que el temporizador del evento está configurado y aún no ha expirado.
* `timedout` — Bandera que indica que el temporizador del evento ha expirado.
* `eof` — Bandera que indica que se produjo EOF al leer datos.
* `pending_eof` — Bandera que indica que hay un EOF pendiente en el socket, aunque pueda haber algunos datos disponibles antes.
  La bandera se entrega a través del evento `EPOLLRDHUP` de `epoll` o la bandera `EV_EOF` de `kqueue`.
* `error` — Bandera que indica que ocurrió un error durante la lectura (para un evento de lectura) o escritura (para un evento de escritura).
* `cancelable` — Bandera de evento de temporizador que indica que el evento debe ignorarse durante el apagado del worker.
  El apagado suave del worker se retrasa hasta que no haya eventos de temporizador no cancelables programados.
* `posted` — Bandera que indica que el evento está publicado en una cola.
* `queue` — Nodo de cola para colocar el evento en una cola.

<a id="i-o-events"></a>

### Eventos de E/S

Cada conexión obtenida al llamar a la función `ngx_get_connection()` tiene dos eventos adjuntos, `c->read` y `c->write`, que se utilizan para recibir notificación de que el socket está listo para leer o escribir.
Todos estos eventos operan en modo Edge-Triggered, lo que significa que solo disparan notificaciones cuando cambia el estado del socket.
Por ejemplo, realizar una lectura parcial en un socket no hace que Angie entregue una notificación de lectura repetida hasta que lleguen más datos al socket.
Incluso cuando el mecanismo subyacente de notificación de E/S es esencialmente Level-Triggered (`poll`, `select`, etc.), Angie convierte las notificaciones a Edge-Triggered.
Para hacer que las notificaciones de eventos de Angie sean consistentes en todos los sistemas de notificación en diferentes plataformas, las funciones `ngx_handle_read_event(rev, flags)` y `ngx_handle_write_event(wev, lowat)` deben llamarse después de manejar una notificación de socket de E/S o de llamar a cualquier función de E/S en ese socket.
Normalmente, las funciones se llaman una vez al final de cada manejador de evento de lectura o escritura.

<a id="timer-events"></a>

### Eventos de temporización

Un evento puede configurarse para enviar una notificación cuando expire un tiempo de espera.
El temporizador utilizado por los eventos cuenta milisegundos desde algún punto anterior no especificado
truncados al tipo `ngx_msec_t`.
Su valor actual se puede obtener de la variable `ngx_current_msec`.

La función `ngx_add_timer(ev, timer)` establece un tiempo de espera para un
evento, `ngx_del_timer(ev)` elimina un tiempo de espera previamente configurado.
El árbol rojo-negro global de temporizadores `ngx_event_timer_rbtree`
almacena todos los tiempos de espera actualmente configurados.
La clave en el árbol es de tipo `ngx_msec_t` y es el momento
en que ocurre el evento.
La estructura del árbol permite operaciones rápidas de inserción y eliminación, así como
acceso a los tiempos de espera más cercanos, que Angie utiliza para determinar cuánto tiempo esperar
para eventos de E/S y para la expiración de eventos de temporización.

<a id="posted-events"></a>

### Eventos publicados

Un evento puede ser publicado, lo que significa que su manejador se llamará en algún
momento más tarde dentro de la iteración actual del bucle de eventos.
Publicar eventos es una buena práctica para simplificar el código y evitar
desbordamientos de pila.
Los eventos publicados se mantienen en una cola de publicaciones.
La macro `ngx_post_event(ev, q)` publica el evento
`ev` en la cola de publicaciones `q`.
La macro `ngx_delete_posted_event(ev)` elimina el evento
`ev` de la cola en la que está publicado actualmente.
Normalmente, los eventos se publican en la cola `ngx_posted_events`,
que se procesa tarde en el bucle de eventos — después de que ya se hayan manejado
todos los eventos de E/S y temporizadores.
La función `ngx_event_process_posted()` se llama para procesar
una cola de eventos.
Llama a los manejadores de eventos hasta que la cola esté vacía.
Esto significa que un manejador de eventos publicado puede publicar más eventos para ser procesados
dentro de la iteración actual del bucle de eventos.

Un ejemplo:

```c
void
ngx_my_connection_read(ngx_connection_t *c)
{
    ngx_event_t  *rev;

    rev = c->read;

    ngx_add_timer(rev, 1000);

    rev->handler = ngx_my_read_handler;

    ngx_my_read(rev);
}


void
ngx_my_read_handler(ngx_event_t *rev)
{
    ssize_t            n;
    ngx_connection_t  *c;
    u_char             buf[256];

    if (rev->timedout) { /* timeout expired */ }

    c = rev->data;

    while (rev->ready) {
        n = c->recv(c, buf, sizeof(buf));

        if (n == NGX_AGAIN) {
            break;
        }

        if (n == NGX_ERROR) { /* error */ }

        /* process buf */
    }

    if (ngx_handle_read_event(rev, 0) != NGX_OK) { /* error */ }
}
```

<a id="event-loop"></a>

### Bucle de eventos

A excepción del proceso maestro de Angie, todos los procesos de Angie realizan E/S y, por lo tanto, tienen un bucle de eventos.
(El proceso maestro de Angie, en cambio, pasa la mayor parte de su tiempo en la llamada
`sigsuspend()` esperando a que lleguen señales.)
El bucle de eventos de Angie se implementa en la función
`ngx_process_events_and_timers()`, la cual se llama
repetidamente hasta que el proceso salga.

El bucle de eventos tiene las siguientes etapas:

* Encontrar el tiempo de espera que esté más cercano a expirar, llamando a
  `ngx_event_find_timer()`.
  Esta función localiza el nodo más a la izquierda del árbol de temporizadores y devuelve
  el número de milisegundos hasta que expire el nodo.
* Procesar eventos de E/S llamando a un manejador, específico del mecanismo de notificación de eventos, elegido por la configuración de Angie.
  Este manejador espera a que ocurra al menos un evento de E/S, pero solo hasta que expire el siguiente
  tiempo de espera.
  Cuando ocurre un evento de lectura o escritura, se establece la bandera `ready`
  y se llama al manejador del evento.
  Para Linux, normalmente se utiliza el manejador `ngx_epoll_process_events()`,
  que llama a `epoll_wait()` para esperar eventos de E/S.
* Expirar temporizadores llamando a `ngx_event_expire_timers()`.
  El árbol de temporizadores se recorre desde el elemento más a la izquierda hacia la derecha hasta encontrar un
  temporizador no vencido.
  Para cada nodo vencido se establece la bandera de evento `timedout`,
  la bandera `timer_set` se restablece y se llama al manejador del evento.
* Procesar eventos publicados llamando a `ngx_event_process_posted()`.
  La función elimina repetidamente el primer elemento de la cola de eventos publicados
  y llama al manejador del elemento, hasta que la cola esté vacía.

Todos los procesos de Angie manejan señales también.
Los manejadores de señales solo establecen variables globales que se verifican después de la
llamada a `ngx_process_events_and_timers()`.

<a id="processes"></a>

### Procesos

Hay varios tipos de procesos en Angie.
El tipo de un proceso se guarda en la variable global `ngx_process`,
y es uno de los siguientes:

* `NGX_PROCESS_MASTER` — El proceso maestro, que lee la
  configuración de Angie, crea ciclos e inicia y controla procesos hijo.
  No realiza ninguna E/S y solo responde a señales.
  Su función de ciclo es `ngx_master_process_cycle()`.
* `NGX_PROCESS_WORKER` — El proceso trabajador, que maneja las conexiones
  de los clientes.
  Es iniciado por el proceso maestro y también responde a sus señales y comandos de canal.
  Su función de ciclo es `ngx_worker_process_cycle()`.
  Puede haber varios procesos trabajadores, tal como lo configure la directiva
  `worker_processes`.
* `NGX_PROCESS_SINGLE` — El proceso único, que existe únicamente en
  el modo `master_process off`, y es el único proceso que se ejecuta en
  ese modo.
  Crea ciclos (como lo hace el proceso maestro) y maneja las conexiones de clientes
  (como lo hace el proceso trabajador).
  Su función de ciclo es `ngx_single_process_cycle()`.
* `NGX_PROCESS_HELPER` — El proceso auxiliar, del cual actualmente
  existen dos tipos: gestor de caché y cargador de caché.
  La función de ciclo para ambos es
  `ngx_cache_manager_process_cycle()`.

Los procesos de Angie manejan las siguientes señales:

* `NGX_SHUTDOWN_SIGNAL` (`SIGQUIT` en la mayoría
  de sistemas) — Apagado suave.
  Al recibir esta señal, el proceso maestro envía una señal de apagado a todos
  los procesos hijo.
  Cuando ya no quedan procesos hijo, el maestro destruye el grupo de ciclos y sale.
  Cuando un proceso trabajador recibe esta señal, cierra todos los sockets de escucha y
  espera hasta que no haya eventos programados no cancelables, luego destruye el
  grupo de ciclos y sale.
  Cuando el proceso de gestor de caché o el cargador de caché recibe esta señal, sale
  inmediatamente.
  La variable `ngx_quit` se establece en `1` cuando un
  proceso recibe esta señal, y se restablece inmediatamente después de ser procesada.
  La variable `ngx_exiting` se establece en `1` mientras
  un proceso trabajador está en el estado de apagado.
* `NGX_TERMINATE_SIGNAL` (`SIGTERM` en la mayoría
  de sistemas) — Terminación.
  Al recibir esta señal, el proceso maestro envía una señal de terminación a todos
  los procesos hijo.
  Si un proceso hijo no sale en 1 segundo, el proceso maestro envía la
  señal `SIGKILL` para terminarlo.
  Cuando ya no quedan procesos hijo, el maestro destruye el grupo de ciclos y
  sale.
  Cuando un proceso trabajador, el gestor de caché o el cargador de caché
  recibe esta señal, destruye el grupo de ciclos y sale.
  La variable `ngx_terminate` se establece en `1`
  al recibir esta señal.
* `NGX_NOACCEPT_SIGNAL` (`SIGWINCH` en la mayoría
  de sistemas) — Detener todos los procesos trabajador y auxiliar.
  Al recibir esta señal, el proceso maestro apaga sus procesos hijo.
  Si un binario Angie recién iniciado sale, los procesos hijo del antiguo
  maestro se inician de nuevo.
  Cuando un proceso trabajador recibe esta señal, se apaga en modo de depuración
  establecido por la directiva `debug_points`.
* `NGX_RECONFIGURE_SIGNAL` (`SIGHUP` en la mayoría
  de sistemas) — Reconfigurar.
  Al recibir esta señal, el proceso maestro vuelve a leer la configuración y
  crea un nuevo ciclo basado en ella.
  Si el nuevo ciclo se crea con éxito, se elimina el antiguo ciclo y se inician los nuevos
  procesos hijo.
  Mientras tanto, los procesos hijo antiguos reciben la
  señal `NGX_SHUTDOWN_SIGNAL`.
  En modo de un solo proceso, Angie crea un nuevo ciclo, pero mantiene el antiguo hasta
  que ya no haya clientes con conexiones activas vinculadas a él.
  Los procesos trabajadores y auxiliares ignoran esta señal.
* `NGX_REOPEN_SIGNAL` (`SIGUSR1` en la mayoría
  de sistemas) — Reabrir archivos.
  El proceso maestro envía esta señal a los trabajadores, que vuelven a abrir todos los
  `open_files` relacionados con el ciclo.
* `NGX_CHANGEBIN_SIGNAL` (`SIGUSR2` en la mayoría
  de sistemas) — Cambiar el binario de Angie.
  El proceso maestro inicia un nuevo binario de Angie y pasa una lista de todos los sockets de escucha.
  La lista en formato de texto, pasada en la variable de entorno `"NGINX"`,
  consta de números de descriptor separados por punto y coma.
  El nuevo binario de Angie lee la variable `"NGINX"` y añade los
  sockets a su ciclo de inicio.
  Otros procesos ignoran esta señal.

Aunque todos los procesos trabajadores de Angie pueden recibir y manejar adecuadamente las señales POSIX, el proceso maestro no utiliza la syscall estándar `kill()`
para pasar señales a trabajadores y auxiliares.
En su lugar, Angie utiliza pares de sockets entre procesos que permiten enviar mensajes
entre todos los procesos de Angie.
Sin embargo, actualmente, los mensajes solo se envían desde el maestro a sus hijos.
Los mensajes transportan las señales estándar.

<a id="threading"></a>

### Threading

Es posible delegar a un hilo separado tareas que de otro modo
bloquearían el proceso worker de Angie.
Por ejemplo, Angie puede configurarse para usar hilos para realizar
[E/S de archivos](https://es.angie.software//angie/docs/configuration/modules/http/index.md#aio).
Otro caso de uso es una biblioteca que no tiene interfaz asíncrona
y por tanto no puede usarse normalmente con Angie.
Tenga en cuenta que la interfaz de hilos es una ayuda para el enfoque
asíncrono existente de procesamiento de conexiones de cliente, y de ninguna manera
está destinada como reemplazo.

Para tratar con la sincronización, están disponibles los siguientes envoltorios sobre
primitivas `pthreads`:

* `typedef pthread_mutex_t  ngx_thread_mutex_t;`
  * `ngx_int_t
    ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log);`
  * `ngx_int_t
    ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log);`
  * `ngx_int_t
    ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log);`
  * `ngx_int_t
    ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log);`
* `typedef pthread_cond_t  ngx_thread_cond_t;`
  * `ngx_int_t
    ngx_thread_cond_create(ngx_thread_cond_t *cond, ngx_log_t *log);`
  * `ngx_int_t
    ngx_thread_cond_destroy(ngx_thread_cond_t *cond, ngx_log_t *log);`
  * `ngx_int_t
    ngx_thread_cond_signal(ngx_thread_cond_t *cond, ngx_log_t *log);`
  * `ngx_int_t
    ngx_thread_cond_wait(ngx_thread_cond_t *cond, ngx_thread_mutex_t *mtx,
    ngx_log_t *log);`

En lugar de crear un nuevo hilo para cada tarea, Angie implementa
una estrategia de [thread_pool](https://es.angie.software//angie/docs/configuration/modules/core.md#thread-pool).
Pueden configurarse múltiples pools de hilos para diferentes propósitos
(por ejemplo, realizar E/S en diferentes conjuntos de discos).
Cada pool de hilos se crea al inicio y contiene un número limitado de hilos
que procesan una cola de tareas.
Cuando se completa una tarea, se llama a un manejador de finalización predefinido.

El archivo de cabecera `src/core/ngx_thread_pool.h` contiene
las definiciones relevantes:

```c
struct ngx_thread_task_s {
    ngx_thread_task_t   *next;
    ngx_uint_t           id;
    void                *ctx;
    void               (*handler)(void *data, ngx_log_t *log);
    ngx_event_t          event;
};

typedef struct ngx_thread_pool_s  ngx_thread_pool_t;

ngx_thread_pool_t *ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name);
ngx_thread_pool_t *ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name);

ngx_thread_task_t *ngx_thread_task_alloc(ngx_pool_t *pool, size_t size);
ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task);
```

En tiempo de configuración, un módulo que desee usar hilos debe obtener una
referencia a un pool de hilos llamando a
`ngx_thread_pool_add(cf, name)`, que crea un
nuevo pool de hilos con el `name` dado o devuelve una referencia
al pool con ese nombre si ya existe.

Para añadir una `task` a una cola de un pool de hilos especificado
`tp` en tiempo de ejecución, use la
función `ngx_thread_task_post(tp, task)`.

Para ejecutar una función en un hilo, pase parámetros y configure un manejador de finalización
usando la estructura `ngx_thread_task_t`:

```c
typedef struct {
    int    foo;
} my_thread_ctx_t;


static void
my_thread_func(void *data, ngx_log_t *log)
{
    my_thread_ctx_t *ctx = data;

    /* this function is executed in a separate thread */
}


static void
my_thread_completion(ngx_event_t *ev)
{
    my_thread_ctx_t *ctx = ev->data;

    /* executed in Angie event loop */
}


ngx_int_t
my_task_offload(my_conf_t *conf)
{
    my_thread_ctx_t    *ctx;
    ngx_thread_task_t  *task;

    task = ngx_thread_task_alloc(conf->pool, sizeof(my_thread_ctx_t));
    if (task == NULL) {
        return NGX_ERROR;
    }

    ctx = task->ctx;

    ctx->foo = 42;

    task->handler = my_thread_func;
    task->event.handler = my_thread_completion;
    task->event.data = ctx;

    if (ngx_thread_task_post(conf->thread_pool, task) != NGX_OK) {
        return NGX_ERROR;
    }

    return NGX_OK;
}
```

<a id="modules-1"></a>

## Módulos

<a id="adding-new-modules"></a>

### Añadir nuevos módulos

Cada módulo independiente de Angie reside en un directorio separado que contiene
al menos dos archivos:
`config` y un archivo con el código fuente del módulo.
El archivo `config` contiene toda la información necesaria para que Angie
integre el módulo, por ejemplo:

```bash
ngx_module_type=CORE
ngx_module_name=ngx_foo_module
ngx_module_srcs="$ngx_addon_dir/ngx_foo_module.c"

. auto/module

ngx_addon_name=$ngx_module_name
```

El archivo `config` es un script de shell POSIX que puede establecer
y acceder a las siguientes variables:

* `ngx_module_type` — Tipo de módulo a construir.
  Los valores posibles son `CORE`, `HTTP`,
  `HTTP_FILTER`, `HTTP_INIT_FILTER`,
  `HTTP_AUX_FILTER`, `MAIL`,
  `STREAM`, o `MISC`.
* `ngx_module_name` — Nombres de módulo.
  Para construir múltiples módulos desde un conjunto de archivos fuente, especifique una
  lista de nombres separados por espacios.
  El primer nombre indica el nombre del binario de salida para el módulo dinámico.
  Los nombres en la lista deben coincidir con los nombres usados en el código fuente.
* `ngx_addon_name` — Nombre del módulo tal como aparece en la salida
  en la consola del script configure.
* `ngx_module_srcs` — Lista separada por espacios de archivos fuente
  usados para compilar el módulo.
  La variable `$ngx_addon_dir` puede usarse para representar la ruta
  al directorio del módulo.
* `ngx_module_incs` — Rutas de inclusión requeridas para construir el módulo
* `ngx_module_deps` — Lista separada por espacios de las dependencias del módulo.
  Normalmente, es la lista de archivos de cabecera.
* `ngx_module_libs` — Lista separada por espacios de bibliotecas a
  enlazar con el módulo.
  Por ejemplo, use `ngx_module_libs=-lpthread` para enlazar
  la biblioteca `libpthread`.
  Las siguientes macros pueden usarse para enlazar con las mismas bibliotecas que
  Angie:
  `LIBXSLT`, `LIBGD`, `GEOIP`,
  `PCRE`, `OPENSSL`, `MD5`,
  `SHA1`, `ZLIB`, y `PERL`.
* `ngx_module_link` — Variable establecida por el sistema de construcción a
  `DYNAMIC` para un módulo dinámico o `ADDON`
  para un módulo estático y usada para determinar diferentes acciones a realizar
  dependiendo del tipo de enlace.
* `ngx_module_order` — Orden de carga para el módulo;
  útil para los tipos de módulo `HTTP_FILTER` y
  `HTTP_AUX_FILTER`.
  El formato para esta opción es una lista separada por espacios de módulos.
  Todos los módulos en la lista que siguen al nombre del módulo actual terminan después de él en
  la lista global de módulos, lo que establece el orden para la inicialización de módulos.
  Para módulos de filtro, una inicialización posterior significa una ejecución anterior.

  Los siguientes módulos se usan típicamente como referencias.
  El `ngx_http_copy_filter_module` lee los datos para otros
  módulos de filtro y se coloca cerca del final de la lista para que sea uno de
  los primeros en ejecutarse.
  El `ngx_http_write_filter_module` escribe los datos al
  socket del cliente y se coloca cerca del principio de la lista, y es el último en
  ejecutarse.

  Por defecto, los módulos de filtro se colocan antes del
  `ngx_http_copy_filter` en la lista de módulos para que el
  manejador de filtro se ejecute después del manejador del filtro de copia.
  Para otros tipos de módulo el valor por defecto es la cadena vacía.

Para compilar un módulo en Angie estáticamente, use el
argumento `--add-module=/path/to/module` del script configure.
Para compilar un módulo para carga dinámica posterior en Angie, use el
argumento `--add-dynamic-module=/path/to/module`.

<a id="core-modules"></a>

### Módulos núcleo

Los módulos son los bloques de construcción de Angie, y la mayor parte de su funcionalidad se
implementa como módulos.
El archivo fuente del módulo debe contener una variable global de tipo
`ngx_module_t`, que se define de la siguiente manera:

```c
struct ngx_module_s {

    /* la parte privada se omite */

    void                 *ctx;
    ngx_command_t        *commands;
    ngx_uint_t            type;

    ngx_int_t           (*init_master)(ngx_log_t *log);

    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);

    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);
    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);
    void                (*exit_thread)(ngx_cycle_t *cycle);
    void                (*exit_process)(ngx_cycle_t *cycle);

    void                (*exit_master)(ngx_cycle_t *cycle);

    /* los stubs para extensiones futuras se omiten */
};
```

La parte privada omitida incluye la versión del módulo y una firma y se
completa usando la macro predefinida `NGX_MODULE_V1`.

Cada módulo mantiene sus datos privados en el campo `ctx`,
reconoce las directivas de configuración especificadas en el
array `commands`, y puede invocarse en ciertas etapas del
ciclo de vida de Angie.
El ciclo de vida del módulo consiste en los siguientes eventos:

* Los manejadores de directivas de configuración se llaman tal como aparecen
  en los archivos de configuración en el contexto del proceso maestro.
* Después de que la configuración se analiza correctamente, el manejador `init_module`
  se llama en el contexto del proceso maestro.
  El manejador `init_module` se llama en el proceso maestro cada
  vez que se carga una configuración.
* El proceso maestro crea uno o más procesos worker y el
  manejador `init_process` se llama en cada uno de ellos.
* Cuando un proceso worker recibe el comando de apagado o terminación del
  maestro, invoca el manejador `exit_process`.
* El proceso maestro llama al manejador `exit_master` antes
  de salir.

Debido a que los hilos se usan en Angie solo como una facilidad de E/S suplementaria con su
propia API, los manejadores `init_thread` y `exit_thread`
no se llaman actualmente.
Tampoco existe un manejador `init_master`, porque sería
una sobrecarga innecesaria.

El `type` del módulo define exactamente qué se almacena en el
campo `ctx`.
Su valor es uno de los siguientes tipos:

* `NGX_CORE_MODULE`
* `NGX_EVENT_MODULE`
* `NGX_HTTP_MODULE`
* `NGX_MAIL_MODULE`
* `NGX_STREAM_MODULE`

El `NGX_CORE_MODULE` es el tipo de módulo más básico y, por lo tanto, el más
genérico y de nivel más bajo.
Los otros tipos de módulos se implementan sobre él y proporcionan una
forma más conveniente de tratar con dominios correspondientes, como el manejo de eventos o solicitudes HTTP.

El conjunto de módulos núcleo incluye los módulos `ngx_core_module`,
`ngx_errlog_module`, `ngx_regex_module`,
`ngx_thread_pool_module` y
`ngx_openssl_module`.
El módulo HTTP, el módulo stream, el módulo mail y los módulos de eventos también son módulos núcleo.
El contexto de un módulo núcleo se define como:

```c
typedef struct {
    ngx_str_t             name;
    void               *(*create_conf)(ngx_cycle_t *cycle);
    char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);
} ngx_core_module_t;
```

donde `name` es una cadena con el nombre del módulo,
`create_conf` e `init_conf`
son punteros a funciones que crean e inicializan la configuración del módulo
respectivamente.
Para los módulos núcleo, Angie llama a `create_conf` antes de analizar
una nueva configuración e `init_conf` después de que toda la configuración
se analiza correctamente.
La función típica `create_conf` asigna memoria para la
configuración y establece valores predeterminados.

Por ejemplo, un módulo simplista llamado `ngx_foo_module` podría
verse así:

```c
/*
 * Copyright (C) Author.
 */


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


typedef struct {
    ngx_flag_t  enable;
} ngx_foo_conf_t;


static void *ngx_foo_create_conf(ngx_cycle_t *cycle);
static char *ngx_foo_init_conf(ngx_cycle_t *cycle, void *conf);

static char *ngx_foo_enable(ngx_conf_t *cf, void *post, void *data);
static ngx_conf_post_t  ngx_foo_enable_post = { ngx_foo_enable };


static ngx_command_t  ngx_foo_commands[] = {

    { ngx_string("foo_enabled"),
      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
      ngx_conf_set_flag_slot,
      0,
      offsetof(ngx_foo_conf_t, enable),
      &ngx_foo_enable_post },

      ngx_null_command
};


static ngx_core_module_t  ngx_foo_module_ctx = {
    ngx_string("foo"),
    ngx_foo_create_conf,
    ngx_foo_init_conf
};


ngx_module_t  ngx_foo_module = {
    NGX_MODULE_V1,
    &ngx_foo_module_ctx,                   /* module context */
    ngx_foo_commands,                      /* module directives */
    NGX_CORE_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 void *
ngx_foo_create_conf(ngx_cycle_t *cycle)
{
    ngx_foo_conf_t  *fcf;

    fcf = ngx_pcalloc(cycle->pool, sizeof(ngx_foo_conf_t));
    if (fcf == NULL) {
        return NULL;
    }

    fcf->enable = NGX_CONF_UNSET;

    return fcf;
}


static char *
ngx_foo_init_conf(ngx_cycle_t *cycle, void *conf)
{
    ngx_foo_conf_t *fcf = conf;

    ngx_conf_init_value(fcf->enable, 0);

    return NGX_CONF_OK;
}


static char *
ngx_foo_enable(ngx_conf_t *cf, void *post, void *data)
{
    ngx_flag_t  *fp = data;

    if (*fp == 0) {
        return NGX_CONF_OK;
    }

    ngx_log_error(NGX_LOG_NOTICE, cf->log, 0, "Foo Module is enabled");

    return NGX_CONF_OK;
}
```

<a id="configuration-directives"></a>

### Directivas de configuración

El tipo `ngx_command_t` define una única directiva de configuración.
Cada módulo que admite configuración proporciona un array de dichas estructuras
que describe cómo procesar los argumentos y qué manejadores llamar:

```c
typedef struct ngx_command_s  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;
};
```

Termine el array con el valor especial `ngx_null_command`.
El `name` es el nombre de la directiva tal como aparece
en el archivo de configuración, por ejemplo, "worker_processes" o "listen".
El `type` es un campo de bits de flags que especifican el número de
argumentos que acepta la directiva, su tipo y el contexto en el que aparece.
Los flags son:

* `NGX_CONF_NOARGS` — La directiva no acepta argumentos.
* `NGX_CONF_1MORE` — La directiva acepta uno o más argumentos.
* `NGX_CONF_2MORE` — La directiva acepta dos o más argumentos.
* `NGX_CONF_TAKE1` .. `NGX_CONF_TAKE7` —
  La directiva acepta exactamente el número indicado de argumentos.
* `NGX_CONF_TAKE12`, `NGX_CONF_TAKE13`,
  `NGX_CONF_TAKE23`, `NGX_CONF_TAKE123`,
  `NGX_CONF_TAKE1234` — La directiva puede aceptar un número diferente de
  argumentos.
  Las opciones están limitadas a los números especificados.
  Por ejemplo, `NGX_CONF_TAKE12` significa que acepta uno o dos
  argumentos.

Flags para tipos de directiva:

* `NGX_CONF_BLOCK` — La directiva es un bloque, es decir, puede
  contener otras directivas dentro de sus llaves de apertura y cierre, o incluso
  implementar su propio analizador para manejar el contenido interno.
* `NGX_CONF_FLAG` — La directiva acepta un valor booleano, ya sea
  `on` o `off`.

El contexto de la directiva define dónde puede aparecer en la configuración:

* `NGX_MAIN_CONF` — En el contexto de nivel superior.
* `NGX_HTTP_MAIN_CONF` — En el bloque `http`.
* `NGX_HTTP_SRV_CONF` — En un bloque `server`
  dentro del bloque `http`.
* `NGX_HTTP_LOC_CONF` — En un bloque `location`
  dentro del bloque `http`.
* `NGX_HTTP_UPS_CONF` — En un bloque `upstream`
  dentro del bloque `http`.
* `NGX_HTTP_SIF_CONF` — En un bloque `if` dentro
  de un bloque `server` en el bloque `http`.
* `NGX_HTTP_LIF_CONF` — En un bloque `if` dentro
  de un bloque `location` en el bloque `http`.
* `NGX_HTTP_LMT_CONF` — En un bloque `limit_except`
  dentro del bloque `http`.
* `NGX_STREAM_MAIN_CONF` — En el bloque `stream`.
* `NGX_STREAM_SRV_CONF` — En un bloque `server`
  dentro del bloque `stream`.
* `NGX_STREAM_UPS_CONF` — En un bloque `upstream`
  dentro del bloque `stream`.
* `NGX_MAIL_MAIN_CONF` — En el bloque `mail`.
* `NGX_MAIL_SRV_CONF` — En un bloque `server`
  dentro del bloque `mail`.
* `NGX_EVENT_CONF` — En el bloque `events`.
* `NGX_DIRECT_CONF` — Utilizado por módulos que no
  crean una jerarquía de contextos y tienen solo una configuración global única.
  Esta configuración se pasa al manejador como el argumento `conf`.

El analizador de configuración utiliza estos flags para generar un error ante una
directiva mal ubicada y llama a los manejadores de directivas suministrados con el
puntero de configuración apropiado, de modo que las mismas directivas en diferentes ubicaciones puedan
almacenar sus valores en ubicaciones distintas.

El campo `set` define un manejador que procesa la directiva
y almacena los valores analizados en la configuración correspondiente.
Existen varias funciones que realizan conversiones comunes:

* `ngx_conf_set_flag_slot` — Convierte las cadenas literales
  `on` y `off` en un
  valor `ngx_flag_t` con valores 1 o 0, respectivamente.
* `ngx_conf_set_str_slot` — Almacena una cadena como un valor del
  tipo `ngx_str_t`.
* `ngx_conf_set_str_array_slot` — Añade un valor a un array
  `ngx_array_t` de cadenas `ngx_str_t`.
  El array se crea si aún no existe.
* `ngx_conf_set_keyval_slot` — Añade un par clave-valor a un
  array `ngx_array_t` de pares clave-valor
  `ngx_keyval_t`.
  La primera cadena se convierte en la clave y la segunda en el valor.
  El array se crea si aún no existe.
* `ngx_conf_set_num_slot` — Convierte un argumento de la directiva
  a un valor `ngx_int_t`.
* `ngx_conf_set_size_slot` — Convierte un
  [tamaño](https://es.angie.software//angie/docs/configuration/configfile.md#syntax) a un valor `size_t`
  expresado en bytes.
* `ngx_conf_set_off_slot` — Convierte un
  [desplazamiento](https://es.angie.software//angie/docs/configuration/configfile.md#syntax) a un valor `off_t`
  expresado en bytes.
* `ngx_conf_set_msec_slot` — Convierte un
  [tiempo](https://es.angie.software//angie/docs/configuration/configfile.md#syntax) a un valor `ngx_msec_t`
  expresado en milisegundos.
* `ngx_conf_set_sec_slot` — Convierte un
  [tiempo](https://es.angie.software//angie/docs/configuration/configfile.md#syntax) a un valor `time_t`
  expresado en segundos.
* `ngx_conf_set_bufs_slot` — Convierte los dos argumentos suministrados
  en un objeto `ngx_bufs_t` que contiene el número y
  [tamaño](https://es.angie.software//angie/docs/configuration/configfile.md#syntax) de búferes.
* `ngx_conf_set_enum_slot` — Convierte el argumento suministrado
  a un valor `ngx_uint_t`.
  El array terminado en null de `ngx_conf_enum_t` pasado en el
  campo `post` define las cadenas aceptables y los correspondientes
  valores enteros.
* `ngx_conf_set_bitmask_slot` — Convierte los argumentos suministrados
  a un valor `ngx_uint_t`.
  Los valores de máscara para cada argumento se combinan con OR produciendo el resultado.
  El array terminado en null de `ngx_conf_bitmask_t` pasado en el
  campo `post` define las cadenas aceptables y los correspondientes
  valores de máscara.
* `ngx_conf_set_path_slot` — Convierte los argumentos suministrados a un
  valor `ngx_path_t` y realiza todas las inicializaciones necesarias.
  Para más detalles, consulte la documentación de la
  directiva [proxy_temp_path](https://es.angie.software//angie/docs/configuration/modules/http/http_proxy.md#proxy-temp-path).
* `ngx_conf_set_access_slot` — Convierte los argumentos suministrados a una máscara de
  permisos de archivo.
  Para más detalles, consulte la documentación de la
  directiva [proxy_store_access](https://es.angie.software//angie/docs/configuration/modules/http/http_proxy.md#proxy-store-access).

El campo `conf` define qué estructura de configuración
se pasa al manejador de la directiva.
Los módulos principales solo tienen la configuración global y establecen el
flag `NGX_DIRECT_CONF` para acceder a ella.
Módulos como HTTP, Stream o Mail crean jerarquías de configuraciones.
Por ejemplo, la configuración de un módulo se crea para los ámbitos `server`,
`location` e `if`.

* `NGX_HTTP_MAIN_CONF_OFFSET` — Configuración para el
  bloque `http`.
* `NGX_HTTP_SRV_CONF_OFFSET` — Configuración para un
  bloque `server` dentro del bloque `http`.
* `NGX_HTTP_LOC_CONF_OFFSET` — Configuración para un
  bloque `location` dentro del bloque `http`.
* `NGX_STREAM_MAIN_CONF_OFFSET` — Configuración para el
  bloque `stream`.
* `NGX_STREAM_SRV_CONF_OFFSET` — Configuración para un
  bloque `server` dentro del bloque `stream`.
* `NGX_MAIL_MAIN_CONF_OFFSET` — Configuración para el
  bloque `mail`.
* `NGX_MAIL_SRV_CONF_OFFSET` — Configuración para un
  bloque `server` dentro del bloque `mail`.

El campo `offset` define el desplazamiento de un campo en la estructura de configuración de un módulo
que contiene los valores para esta directiva en particular.
El uso típico es emplear la macro `offsetof()`.

El campo `post` tiene dos propósitos: puede utilizarse para definir
un manejador que se llamará después de que el manejador principal haya completado, o para pasar
datos adicionales al manejador principal.
En el primer caso, la estructura `ngx_conf_post_t` necesita
inicializarse con un puntero al manejador, por ejemplo:

```c
static char *ngx_do_foo(ngx_conf_t *cf, void *post, void *data);
static ngx_conf_post_t  ngx_foo_post = { ngx_do_foo };
```

El argumento `post` es el objeto `ngx_conf_post_t`
en sí mismo, y `data` es un puntero al valor,
convertido desde los argumentos por el manejador principal con el tipo apropiado.

<a id="http"></a>

## HTTP

<a id="http-connection"></a>

### Conexión

Cada conexión de cliente HTTP pasa por las siguientes etapas:

* `ngx_event_accept()` acepta una conexión TCP de cliente.
  Este manejador se llama en respuesta a una notificación de lectura en un socket de escucha.
  En esta etapa se crea un nuevo objeto `ngx_connection_t`
  para envolver el socket de cliente recién aceptado.
  Cada listener de Angie proporciona un manejador para pasar el nuevo objeto de conexión.
  Para conexiones HTTP es `ngx_http_init_connection(c)`.
* `ngx_http_init_connection()` realiza la inicialización temprana de
  la conexión HTTP.
  En esta etapa se crea un objeto `ngx_http_connection_t` para
  la conexión y su referencia se almacena en el campo
  `data` de la conexión.
  Posteriormente será reemplazado por un objeto de solicitud HTTP.
  En esta etapa también se inician el analizador del protocolo PROXY y el handshake SSL.
* El manejador de eventos de lectura `ngx_http_wait_request_handler()`
  se llama cuando hay datos disponibles en el socket del cliente.
  En esta etapa se crea un objeto de solicitud HTTP `ngx_http_request_t` y
  se establece en el campo `data` de la conexión.
* El manejador de eventos de lectura `ngx_http_process_request_line()`
  lee la línea de solicitud del cliente.
  El manejador es establecido por `ngx_http_wait_request_handler()`.
  Los datos se leen en el `buffer` de la conexión.
  El tamaño del búfer se establece inicialmente mediante la directiva
  [client_header_buffer_size](https://es.angie.software//angie/docs/configuration/modules/http/index.md#client-header-buffer-size).
  Se supone que todo el encabezado del cliente debe caber en el búfer.
  Si el tamaño inicial no es suficiente, se asigna un búfer más grande,
  con la capacidad establecida por la directiva [large_client_header_buffers](https://es.angie.software//angie/docs/configuration/modules/http/index.md#large-client-header-buffers).
* El manejador de eventos de lectura `ngx_http_process_request_headers()`,
  se establece después de `ngx_http_process_request_line()` para leer
  el encabezado de la solicitud del cliente.
* `ngx_http_core_run_phases()` se llama cuando el encabezado de la solicitud
  se ha leído y analizado completamente.
  Esta función ejecuta las fases de la solicitud desde
  `NGX_HTTP_POST_READ_PHASE` hasta
  `NGX_HTTP_CONTENT_PHASE`.
  La última fase está destinada a generar una respuesta y pasarla a lo largo de la cadena de filtros.
  La respuesta no se envía necesariamente al cliente en esta fase.
  Puede permanecer en búfer y enviarse en la etapa de finalización.
* `ngx_http_finalize_request()` normalmente se llama cuando la
  solicitud ha generado toda la salida o ha producido un error.
  En este último caso se busca una página de error apropiada y se usa como
  respuesta.
  Si la respuesta no se ha enviado completamente al cliente en este punto, se
  activa un escritor HTTP `ngx_http_writer()` para terminar
  de enviar los datos pendientes.
* `ngx_http_finalize_connection()` se llama cuando la respuesta
  completa se ha enviado al cliente y la solicitud puede destruirse.
  Si la función keepalive de la conexión del cliente está habilitada,
  se llama a `ngx_http_set_keepalive()`, que destruye la
  solicitud actual y espera la siguiente solicitud en la conexión.
  De lo contrario, `ngx_http_close_request()` destruye tanto la
  solicitud como la conexión.

<a id="request"></a>

### Solicitud

Para cada solicitud HTTP del cliente se crea el objeto `ngx_http_request_t`.
Algunos de los campos de este objeto son:

* `connection` — Puntero a un objeto de conexión de cliente
  `ngx_connection_t`.
  Varias solicitudes pueden referenciar el mismo objeto de conexión al mismo tiempo:
  una solicitud principal y sus subsolicitudes.
  Después de que se elimina una solicitud, se puede crear una nueva solicitud en la misma conexión.

  Tenga en cuenta que para las conexiones HTTP el campo `data` de
  `ngx_connection_t` apunta de vuelta a la solicitud.
  Tales solicitudes se denominan activas, en contraposición a las otras solicitudes vinculadas a la
  conexión.
  Una solicitud activa se utiliza para manejar eventos de conexión del cliente y se le permite
  enviar su respuesta al cliente.
  Normalmente, cada solicitud se vuelve activa en algún momento para poder enviar su
  salida.
* `ctx` — Array de contextos de módulos HTTP.
  Cada módulo de tipo `NGX_HTTP_MODULE` puede almacenar cualquier valor
  (normalmente, un puntero a una estructura) en la solicitud.
  El valor se almacena en el array `ctx` en la posición
  `ctx_index` del módulo.
  Las siguientes macros proporcionan una forma conveniente de obtener y establecer contextos de solicitud:
  * `ngx_http_get_module_ctx(r, module)` — Devuelve
    el contexto del `module`
  * `ngx_http_set_ctx(r, c, module)` — Establece `c`
    como el contexto del `module`
* `main_conf`, `srv_conf`,
  `loc_conf` — Arrays de configuraciones de la solicitud
  actual.
  Las configuraciones se almacenan en las posiciones `ctx_index`
  del módulo.
* `read_event_handler`, `write_event_handler` -
  Manejadores de eventos de lectura y escritura para la solicitud.
  Normalmente, tanto el manejador de eventos de lectura como el de escritura para una conexión HTTP
  se establecen en `ngx_http_request_handler()`.
  Esta función llama a los manejadores `read_event_handler` y
  `write_event_handler` para la solicitud activa
  actual.
* `cache` — Objeto de caché de solicitud para almacenar en caché la
  respuesta upstream.
* `upstream` — Objeto upstream de solicitud para proxy.
* `pool` — Pool de solicitud.
  El objeto de solicitud en sí se asigna en este pool, que se destruye cuando
  se elimina la solicitud.
  Para asignaciones que necesitan estar disponibles durante toda la vida de la conexión del cliente,
  use el pool de `ngx_connection_t` en su lugar.
* `header_in` — Buffer en el que se lee el encabezado de la solicitud
  HTTP del cliente.
* `headers_in`, `headers_out` — Objetos de encabezados
  HTTP de entrada y salida.
  Ambos objetos contienen el campo `headers` de tipo
  `ngx_list_t` para mantener la lista sin procesar de encabezados.
  Además de eso, los encabezados específicos están disponibles para obtener y establecer como
  campos separados, por ejemplo `content_length_n`,
  `status`, etc.
* `request_body` — Objeto de cuerpo de solicitud del cliente.
* `start_sec`, `start_msec` — Punto temporal en el que
  se creó la solicitud, utilizado para rastrear la duración de la solicitud.
* `method`, `method_name` — Representación numérica y de texto
  del método de solicitud HTTP del cliente.
  Los valores numéricos para los métodos se definen en
  `src/http/ngx_http_request.h` con las macros
  `NGX_HTTP_GET`, `NGX_HTTP_HEAD`,
  `NGX_HTTP_POST`, etc.
* `http_protocol`  — Versión del protocolo HTTP del cliente en su
  forma de texto original ("HTTP/1.0", "HTTP/1.1", etc.).
* `http_version`  — Versión del protocolo HTTP del cliente en
  forma numérica (`NGX_HTTP_VERSION_10`,
  `NGX_HTTP_VERSION_11`, etc.).
* `http_major`, `http_minor`  — Versión del protocolo HTTP
  del cliente en forma numérica dividida en partes mayor y menor.
* `request_line`, `unparsed_uri` — Línea de solicitud
  y URI en la solicitud original del cliente.
* `uri`, `args`, `exten` —
  URI, argumentos y extensión de archivo para la solicitud actual.
  El valor de URI aquí puede diferir del URI original enviado por el cliente debido a
  la normalización.
  Durante el procesamiento de la solicitud, estos valores pueden cambiar a medida que se realizan redirecciones
  internas.
* `main` — Puntero a un objeto de solicitud principal.
  Este objeto se crea para procesar una solicitud HTTP del cliente, en contraposición a
  las subsolicitudes, que se crean para realizar una subtarea específica dentro de la solicitud
  principal.
* `parent` — Puntero a la solicitud padre de una subsolicitud.
* `postponed` — Lista de buffers de salida y subsolicitudes, en el
  orden en que se envían y crean.
  La lista es utilizada por el filtro postpone para proporcionar una salida de solicitud consistente
  cuando partes de ella son creadas por subsolicitudes.
* `post_subrequest` — Puntero a un manejador con el contexto
  que se llamará cuando una subsolicitud se finalice.
  No se utiliza para solicitudes principales.
* `posted_requests` — Lista de solicitudes que se iniciarán o
  reanudarán, lo cual se hace llamando al
  `write_event_handler` de la solicitud.
  Normalmente, este manejador contiene la función principal de la solicitud, que al principio ejecuta
  las fases de la solicitud y luego produce la salida.

  Una solicitud normalmente se publica mediante la llamada
  `ngx_http_post_request(r, NULL)`.
  Siempre se publica en la lista `posted_requests` de la solicitud principal.
  La función `ngx_http_run_posted_requests(c)` ejecuta todas
  las solicitudes que están publicadas en la solicitud principal de la solicitud activa
  de la conexión pasada.
  Todos los manejadores de eventos llaman a `ngx_http_run_posted_requests`,
  lo que puede conducir a nuevas solicitudes publicadas.
  Normalmente, se llama después de invocar el manejador de lectura o escritura de una solicitud.
* `phase_handler` — Índice de la fase actual de la solicitud.
* `ncaptures`, `captures`,
  `captures_data` — Capturas de regex producidas
  por la última coincidencia de regex de la solicitud.
  Una coincidencia de regex puede ocurrir en varios lugares durante el procesamiento de la solicitud:
  búsqueda de map, búsqueda de servidor por SNI o Host HTTP, rewrite, proxy_redirect, etc.
  Las capturas producidas por una búsqueda se almacenan en los campos mencionados anteriormente.
  El campo `ncaptures` contiene el número de capturas,
  `captures` contiene los límites de las capturas y
  `captures_data` contiene la cadena contra la cual se comparó la regex
  y que se utiliza para extraer las capturas.
  Después de cada nueva coincidencia de regex, las capturas de la solicitud se restablecen para contener nuevos valores.
* `count` — Contador de referencias de la solicitud.
  El campo solo tiene sentido para la solicitud principal.
  Aumentar el contador se hace mediante un simple `r->main->count++`.
  Para disminuir el contador, llame a
  `ngx_http_finalize_request(r, rc)`.
  La creación de una subsolicitud y la ejecución del proceso de lectura del cuerpo de la solicitud
  incrementan el contador.
* `subrequests` — Nivel de anidamiento de subsolicitud actual.
  Cada subsolicitud hereda el nivel de anidamiento de su padre, disminuido en uno.
  Se genera un error si el valor llega a cero.
  El valor para la solicitud principal se define mediante la
  constante `NGX_HTTP_MAX_SUBREQUESTS`.
* `uri_changes` — Número de cambios de URI restantes para
  la solicitud.
  El número total de veces que una solicitud puede cambiar su URI está limitado por la
  constante `NGX_HTTP_MAX_URI_CHANGES`.
  Con cada cambio, el valor se disminuye hasta que llega a cero, momento en el cual
  se genera un error.
  Las reescrituras y las redirecciones internas a ubicaciones normales o con nombre se consideran cambios de URI.
* `blocked` — Contador de bloqueos mantenidos en la solicitud.
  Mientras este valor sea distinto de cero, la solicitud no puede finalizarse.
  Actualmente, este valor se incrementa por operaciones AIO pendientes (POSIX AIO y
  operaciones de hilos) y bloqueos de caché activos.
* `buffered` — Máscara de bits que muestra qué módulos tienen salida
  almacenada en buffer producida por la solicitud.
  Varios filtros pueden almacenar en buffer la salida; por ejemplo, sub_filter puede almacenar datos en buffer
  debido a una coincidencia parcial de cadena, el filtro copy puede almacenar datos en buffer debido a
  la falta de buffers de salida libres, etc.
  Mientras este valor sea distinto de cero, la solicitud no se finaliza,
  esperando un vaciado.
* `header_only` — Bandera que indica que la salida no requiere
  un cuerpo.
  Por ejemplo, esta bandera se utiliza en las solicitudes HTTP HEAD.
* `keepalive` — Bandera que indica si se admite
  keepalive de conexión del cliente.
  El valor se infiere de la versión HTTP y del valor del
  encabezado "Connection".
* `header_sent` — Bandera que indica que el encabezado de salida
  ya ha sido enviado por la solicitud.
* `internal` — Bandera que indica que la solicitud actual
  es interna.
  Para entrar en el estado interno, una solicitud debe pasar por una
  redirección interna o ser una subsolicitud.
  Las solicitudes internas pueden entrar en ubicaciones internas.
* `allow_ranges` — Bandera que indica que se puede enviar una respuesta parcial
  al cliente, según lo solicitado por el encabezado HTTP Range.
* `subrequest_ranges` — Bandera que indica que se puede enviar una respuesta parcial
  mientras se procesa una subsolicitud.
* `single_range` — Bandera que indica que solo se puede enviar un único rango
  continuo de datos de salida al cliente.
  Esta bandera generalmente se establece cuando se envía un flujo de datos, por ejemplo, desde
  un servidor proxy, y la respuesta completa no está disponible en un solo buffer.
* `main_filter_need_in_memory`,
  `filter_need_in_memory` — Banderas
  que solicitan que la salida se produzca en buffers de memoria pero no en archivos.
  Esta es una señal para el filtro copy de leer datos de buffers de archivo incluso si
  sendfile está habilitado.
  La diferencia entre las dos banderas es la ubicación de los módulos de filtro que
  las establecen.
  Los filtros llamados antes del filtro postpone en la cadena de filtros establecen
  `filter_need_in_memory`, solicitando que solo la salida de la
  solicitud actual entre en buffers de memoria.
  Los filtros llamados más tarde en la cadena de filtros establecen
  `main_filter_need_in_memory`, solicitando que tanto
  la solicitud principal como todas las subsolicitudes lean archivos en memoria
  al enviar la salida.
* `filter_need_temporary` — Bandera que solicita que la salida de la solicitud
  se produzca en buffers temporales, pero no en buffers de memoria de solo lectura o
  buffers de archivo.
  Esto es utilizado por filtros que pueden cambiar la salida directamente en los buffers donde
  se envía.

<a id="http-module-configuration"></a>

### Configuración de módulos HTTP

Cada módulo HTTP puede tener tres tipos de configuración:

* Configuración principal — Se aplica a todo el bloque `http`.
  Sirve como configuración global para el módulo.
* Configuración de servidor — Se aplica a un único bloque `server`.
  Sirve como configuración específica del servidor para el módulo.
* Configuración de ubicación — Se aplica a un único bloque `location`,
  `if` o `limit_except`.
  Sirve como configuración específica de ubicación para el módulo.

Las estructuras de configuración se crean en la etapa de configuración de Angie
llamando a funciones que asignan las estructuras, las inicializan
y las fusionan.
El siguiente ejemplo muestra cómo crear una configuración de ubicación simple
para un módulo.
La configuración tiene un parámetro, `foo`, de tipo
entero sin signo.

```c
typedef struct {
    ngx_uint_t  foo;
} ngx_http_foo_loc_conf_t;


static ngx_http_module_t  ngx_http_foo_module_ctx = {
    NULL,                                  /* preconfiguration */
    NULL,                                  /* postconfiguration */

    NULL,                                  /* create main configuration */
    NULL,                                  /* init main configuration */

    NULL,                                  /* create server configuration */
    NULL,                                  /* merge server configuration */

    ngx_http_foo_create_loc_conf,          /* create location configuration */
    ngx_http_foo_merge_loc_conf            /* merge location configuration */
};


static void *
ngx_http_foo_create_loc_conf(ngx_conf_t *cf)
{
    ngx_http_foo_loc_conf_t  *conf;

    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_foo_loc_conf_t));
    if (conf == NULL) {
        return NULL;
    }

    conf->foo = NGX_CONF_UNSET_UINT;

    return conf;
}


static char *
ngx_http_foo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_foo_loc_conf_t *prev = parent;
    ngx_http_foo_loc_conf_t *conf = child;

    ngx_conf_merge_uint_value(conf->foo, prev->foo, 1);
}
```

Como se ve en el ejemplo, la función `ngx_http_foo_create_loc_conf()`
crea una nueva estructura de configuración, y
`ngx_http_foo_merge_loc_conf()` fusiona una configuración con
la configuración de un nivel superior.
De hecho, las configuraciones de servidor y ubicación no solo existen en los niveles
de servidor y ubicación, sino que también se crean para todos los niveles superiores.
Específicamente, una configuración de servidor también se crea en el nivel principal, y
las configuraciones de ubicación se crean en los niveles principal, de servidor y de ubicación.
Estas configuraciones permiten especificar parámetros específicos de servidor y ubicación
en cualquier nivel de un archivo de configuración de Angie.
Finalmente, las configuraciones se fusionan hacia abajo.
Se proporcionan varias macros, como `NGX_CONF_UNSET` y
`NGX_CONF_UNSET_UINT`, para indicar un parámetro faltante
e ignorarlo durante la fusión.
Las macros de fusión estándar de Angie, como `ngx_conf_merge_value()` y
`ngx_conf_merge_uint_value()`, proporcionan una forma conveniente de
fusionar un parámetro y establecer el valor predeterminado si ninguna de las configuraciones
proporcionó un valor explícito.
Para obtener una lista completa de macros para diferentes tipos, consulte
`src/core/ngx_conf_file.h`.

Las siguientes macros están disponibles
para acceder a la configuración de módulos HTTP en tiempo de configuración.
Todas toman una referencia `ngx_conf_t` como primer argumento.

* `ngx_http_conf_get_module_main_conf(cf, module)`
* `ngx_http_conf_get_module_srv_conf(cf, module)`
* `ngx_http_conf_get_module_loc_conf(cf, module)`

El siguiente ejemplo obtiene un puntero a una configuración de ubicación
del [módulo HTTP core](https://es.angie.software//angie/docs/configuration/modules/http/index.md#http-core) estándar
y reemplaza el manejador de contenido de ubicación almacenado
en el campo `handler` de la estructura.

```c
static ngx_int_t ngx_http_foo_handler(ngx_http_request_t *r);


static ngx_command_t  ngx_http_foo_commands[] = {

    { ngx_string("foo"),
      NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
      ngx_http_foo,
      0,
      0,
      NULL },

      ngx_null_command
};


static char *
ngx_http_foo(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_bar_handler;

    return NGX_CONF_OK;
}
```

Las siguientes macros están disponibles para acceder a la configuración de módulos HTTP
en tiempo de ejecución.

* `ngx_http_get_module_main_conf(r, module)`
* `ngx_http_get_module_srv_conf(r, module)`
* `ngx_http_get_module_loc_conf(r, module)`

Estas macros reciben una referencia a una solicitud HTTP
`ngx_http_request_t`.
La configuración principal de una solicitud nunca cambia.
La configuración de servidor puede cambiar de la predeterminada después de
elegir un servidor virtual para una solicitud.
La configuración de ubicación seleccionada para procesar una solicitud puede cambiar
varias veces como resultado de una operación de reescritura o redirección interna.
El siguiente ejemplo muestra cómo acceder a la configuración HTTP de un módulo
en tiempo de ejecución.

```c
static ngx_int_t
ngx_http_foo_handler(ngx_http_request_t *r)
{
    ngx_http_foo_loc_conf_t  *flcf;

    flcf = ngx_http_get_module_loc_conf(r, ngx_http_foo_module);

    ...
}
```

<a id="phases"></a>

### Fases

Cada petición HTTP pasa por una secuencia de fases.
En cada fase se realiza un tipo distinto de procesamiento sobre la petición.
Los manejadores específicos de módulos pueden registrarse en la mayoría de las fases,
y muchos módulos estándar de Angie registran sus manejadores de fase como una forma de
ser invocados en una etapa específica del procesamiento de la petición.
Las fases se procesan sucesivamente y los manejadores de fase se llaman
una vez que la petición alcanza la fase.
A continuación se muestra la lista de fases HTTP de Angie.

* `NGX_HTTP_POST_READ_PHASE` — Primera fase.
  El módulo [RealIP](https://es.angie.software//angie/docs/configuration/modules/http/http_realip.md#http-realip)
  registra su manejador en esta fase para habilitar
  la sustitución de direcciones de cliente antes de que se invoque cualquier otro módulo.
* `NGX_HTTP_SERVER_REWRITE_PHASE` — Fase donde
  se procesan las directivas de reescritura definidas en un bloque `server`
  (pero fuera de un bloque `location`).
  El módulo [Rewrite](https://es.angie.software//angie/docs/configuration/modules/http/http_rewrite.md#http-rewrite)
  instala su manejador en esta fase.
* `NGX_HTTP_FIND_CONFIG_PHASE` — Fase especial donde
  se elige una ubicación basándose en el URI de la petición.
  Antes de esta fase, la ubicación predeterminada para el servidor virtual relevante se asigna a la
  petición, y cualquier módulo que solicite una configuración de ubicación
  recibe la configuración para la ubicación del servidor predeterminado.
  Esta fase asigna una nueva ubicación a la petición.
  No se pueden registrar manejadores adicionales en esta fase.
* `NGX_HTTP_REWRITE_PHASE` — Igual que
  `NGX_HTTP_SERVER_REWRITE_PHASE`, pero para
  reglas de reescritura definidas en la ubicación elegida en la fase anterior.
* `NGX_HTTP_POST_REWRITE_PHASE` — Fase especial donde
  la petición se redirige a una nueva ubicación si su URI cambió
  durante una reescritura.
  Esto se implementa haciendo que la petición pase por la
  `NGX_HTTP_FIND_CONFIG_PHASE` nuevamente.
  No se pueden registrar manejadores adicionales en esta fase.
* `NGX_HTTP_PREACCESS_PHASE` — Una fase común para diferentes
  tipos de manejadores, no asociada con el control de acceso.
  Los módulos estándar de Angie
  [Limit Conn](https://es.angie.software//angie/docs/configuration/modules/http/http_limit_conn.md#http-limit-conn) y
  [Limit Req](https://es.angie.software//angie/docs/configuration/modules/http/http_limit_req.md#http-limit-req) registran sus manejadores en esta fase.
* `NGX_HTTP_ACCESS_PHASE` — Fase donde se verifica
  que el cliente esté autorizado para realizar la petición.
  Los módulos estándar de Angie como
  [Access](https://es.angie.software//angie/docs/configuration/modules/http/http_access.md#http-access) y
  [Auth Basic](https://es.angie.software//angie/docs/configuration/modules/http/http_auth_basic.md#http-auth-basic) registran sus manejadores en esta fase.
  Por defecto, el cliente debe pasar la verificación de autorización de todos los manejadores
  registrados en esta fase para que la petición continúe a la siguiente fase.
  La directiva [satisfy](https://es.angie.software//angie/docs/configuration/modules/http/index.md#satisfy)
  puede usarse para permitir que el procesamiento continúe si alguno de los manejadores de fase
  autoriza al cliente.
* `NGX_HTTP_POST_ACCESS_PHASE` — Fase especial donde se
  procesa la directiva [satisfy](https://es.angie.software//angie/docs/configuration/modules/http/index.md#satisfy).
  Si algunos manejadores de fase de acceso denegaron el acceso y ninguno lo permitió explícitamente,
  la petición se finaliza.
  No se pueden registrar manejadores adicionales en esta fase.
* `NGX_HTTP_PRECONTENT_PHASE` — Fase para manejadores que se llaman
  antes de generar contenido.
  Los módulos estándar como
  [try_files](https://es.angie.software//angie/docs/configuration/modules/http/index.md#try-files) y
  [Mirror](https://es.angie.software//angie/docs/configuration/modules/http/http_mirror.md#http-mirror)
  registran sus manejadores en esta fase.
* `NGX_HTTP_CONTENT_PHASE` — Fase donde normalmente
  se genera la respuesta.
  Múltiples módulos estándar de Angie registran sus manejadores en esta fase,
  incluyendo
  [Index](https://es.angie.software//angie/docs/configuration/modules/http/http_index.md#http-index).
  Se llaman secuencialmente hasta que uno de ellos produce
  la salida.
  También es posible establecer manejadores de contenido por ubicación.
  Si la configuración de ubicación del módulo [Módulo HTTP](https://es.angie.software//angie/docs/configuration/modules/http/index.md#http-core) tiene
  `handler` establecido, se llama como el manejador de contenido
  y los manejadores instalados en esta fase se ignoran.
* `NGX_HTTP_LOG_PHASE` — Fase donde se realiza
  el registro de la petición.
  Actualmente, solo el
  módulo [Log](https://es.angie.software//angie/docs/configuration/modules/http/http_log.md#http-log)
  registra su manejador
  en esta etapa para el registro de acceso.
  Los manejadores de fase de registro se llaman al final del procesamiento de la petición, justo
  antes de liberar la petición.

A continuación se muestra un ejemplo de un manejador de fase de preacceso.

```c
static ngx_http_module_t  ngx_http_foo_module_ctx = {
    NULL,                                  /* preconfiguration */
    ngx_http_foo_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 */
};


static ngx_int_t
ngx_http_foo_handler(ngx_http_request_t *r)
{
    ngx_table_elt_t  *ua;

    ua = r->headers_in.user_agent;

    if (ua == NULL) {
        return NGX_DECLINED;
    }

    /* reject requests with "User-Agent: foo" */
    if (ua->value.len == 3 && ngx_strncmp(ua->value.data, "foo", 3) == 0) {
        return NGX_HTTP_FORBIDDEN;
    }

    return NGX_DECLINED;
}


static ngx_int_t
ngx_http_foo_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_PREACCESS_PHASE].handlers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    *h = ngx_http_foo_handler;

    return NGX_OK;
}
```

Se espera que los manejadores de fase devuelvan códigos específicos:

* `NGX_OK` — proceder a la siguiente fase.
* `NGX_DECLINED` — proceder al siguiente manejador de la fase
  actual.
  Si el manejador actual es el último en la fase actual,
  pasar a la siguiente fase.
* `NGX_AGAIN`, `NGX_DONE` — suspender
  el manejo de fase hasta algún evento futuro, que podría ser
  una operación de E/S asíncrona o simplemente un retraso, por ejemplo.
  Se asume que el manejo de fase se reanudará más tarde llamando a
  `ngx_http_core_run_phases()`.
* Cualquier otro valor devuelto por el manejador de fase se trata como un código
  de finalización de petición, en particular, un código de respuesta HTTP.
  La petición se finaliza con el código proporcionado.

Para algunas fases, los códigos de retorno se tratan de manera ligeramente diferente.
En la fase de contenido, cualquier código de retorno distinto de
`NGX_DECLINED` se considera un código de finalización.
Cualquier código de retorno de los manejadores de contenido de ubicación se considera
un código de finalización.
En la fase de acceso, en
modo [satisfy any](https://es.angie.software//angie/docs/configuration/modules/http/index.md#satisfy),
devolver un código distinto de `NGX_OK`,
`NGX_DECLINED`, `NGX_AGAIN`,
`NGX_DONE` se considera una denegación.
Si ningún manejador de acceso posterior permite o deniega el acceso con un código
diferente, el código de denegación se convertirá en el código de finalización.

<a id="examples"></a>

### Ejemplos

El
repositorio [nginx-dev-examples](https://github.com/nginx/nginx-dev-examples)
proporciona ejemplos de módulos nginx adecuados para Angie también.

<a id="code-style"></a>

## Estilo de código

<a id="general-rules"></a>

### Reglas generales

* el ancho máximo de texto es de 80 caracteres
* la sangría es de 4 espacios
* sin tabulaciones, sin espacios finales
* los elementos de lista en la misma línea se separan con espacios
* los literales hexadecimales están en minúsculas
* los nombres de archivos, funciones y tipos, y las variables globales tienen
  el prefijo `ngx_` o un prefijo más específico como
  `ngx_http_` y `ngx_mail_`

```c
size_t
ngx_utf8_length(u_char *p, size_t n)
{
    u_char  c, *last;
    size_t  len;

    last = p + n;

    for (len = 0; p < last; len++) {

        c = *p;

        if (c < 0x80) {
            p++;
            continue;
        }

        if (ngx_utf8_decode(&p, last - p) > 0x10ffff) {
            /* invalid UTF-8 */
            return n;
        }
    }

    return len;
}
```

<a id="files"></a>

### Archivos

Un archivo fuente típico puede contener las siguientes secciones, separadas por
dos líneas en blanco:

* declaraciones de copyright
* inclusiones
* definiciones de preprocesador
* definiciones de tipos
* prototipos de funciones
* definiciones de variables
* definiciones de funciones

Las declaraciones de copyright se ven así:

```c
/*
 * Copyright (C) Author Name
 * Copyright (C) Organization, Inc.
 */
```

Si el archivo se modifica significativamente, la lista de autores debe actualizarse,
el nuevo autor se añade al principio.

Los archivos `ngx_config.h` y `ngx_core.h`
siempre se incluyen primero, seguidos de uno de
`ngx_http.h`, `ngx_stream.h`,
o `ngx_mail.h`.
Luego siguen los archivos de cabecera externos opcionales:

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

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxslt/xslt.h>

#if (NGX_HAVE_EXSLT)
#include <libexslt/exslt.h>
#endif
```

Los archivos de cabecera deben incluir la llamada "protección de cabecera":

```c
#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_
#define _NGX_PROCESS_CYCLE_H_INCLUDED_
...
#endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */
```

<a id="comments"></a>

### Comentarios

* no se usan comentarios `//`
* el texto está en inglés, se prefiere la ortografía americana
* los comentarios multilínea se formatean así:
  ```c
  /*
   * The red-black tree code is based on the algorithm described in
   * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
   */
  ```

  ```c
  /* find the server configuration for the address:port */
  ```

<a id="preprocessor"></a>

### Preprocesador

Los nombres de macros comienzan con `ngx_` o `NGX_`
(o prefijo más específico).
Los nombres de macros para constantes están en mayúsculas.
Las macros parametrizadas y las macros para inicializadores están en minúsculas.
El nombre de la macro y su valor se separan por al menos dos espacios:

```c
#define NGX_CONF_BUFFER  4096

#define ngx_buf_in_memory(b)  (b->temporary || b->memory || b->mmap)

#define ngx_buf_size(b)                                                      \
    (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos):                      \
                            (b->file_last - b->file_pos))

#define ngx_null_string  { 0, NULL }
```

Las condiciones están dentro de paréntesis, la negación está fuera:

```c
#if (NGX_HAVE_KQUEUE)
...
#elif ((NGX_HAVE_DEVPOLL && !(NGX_TEST_BUILD_DEVPOLL)) \
       || (NGX_HAVE_EVENTPORT && !(NGX_TEST_BUILD_EVENTPORT)))
...
#elif (NGX_HAVE_EPOLL && !(NGX_TEST_BUILD_EPOLL))
...
#elif (NGX_HAVE_POLL)
...
#else /* select */
...
#endif /* NGX_HAVE_KQUEUE */
```

<a id="types-1"></a>

### Tipos

Los nombres de tipos terminan con el sufijo `_t`.
Un nombre de tipo definido está separado por al menos dos espacios:

```c
typedef ngx_uint_t  ngx_rbtree_key_t;
```

Los tipos de estructuras se definen usando `typedef`.
Dentro de las estructuras, los tipos y nombres de los miembros están alineados:

```c
typedef struct {
    size_t      len;
    u_char     *data;
} ngx_str_t;
```

Mantenga la misma alineación entre diferentes estructuras en el archivo.
Una estructura que apunta a sí misma tiene un nombre que termina con
`_s`.
Las definiciones de estructuras adyacentes están separadas por dos líneas en blanco:

```c
typedef struct ngx_list_part_s  ngx_list_part_t;

struct ngx_list_part_s {
    void             *elts;
    ngx_uint_t        nelts;
    ngx_list_part_t  *next;
};


typedef struct {
    ngx_list_part_t  *last;
    ngx_list_part_t   part;
    size_t            size;
    ngx_uint_t        nalloc;
    ngx_pool_t       *pool;
} ngx_list_t;
```

Cada miembro de una estructura se declara en su propia línea:

```c
typedef struct {
    ngx_uint_t        hash;
    ngx_str_t         key;
    ngx_str_t         value;
    u_char           *lowcase_key;
} ngx_table_elt_t;
```

Los punteros de funciones dentro de las estructuras tienen tipos definidos que terminan
con `_pt`:

```c
typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size);
typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
    off_t limit);
typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size);
typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
    off_t limit);

typedef struct {
    ngx_recv_pt        recv;
    ngx_recv_chain_pt  recv_chain;
    ngx_recv_pt        udp_recv;
    ngx_send_pt        send;
    ngx_send_pt        udp_send;
    ngx_send_chain_pt  udp_send_chain;
    ngx_send_chain_pt  send_chain;
    ngx_uint_t         flags;
} ngx_os_io_t;
```

Las enumeraciones tienen tipos que terminan con `_e`:

```c
typedef enum {
    ngx_http_fastcgi_st_version = 0,
    ngx_http_fastcgi_st_type,
    ...
    ngx_http_fastcgi_st_padding
} ngx_http_fastcgi_state_e;
```

<a id="variables-2"></a>

### Variables

Las variables se declaran ordenadas por la longitud del tipo base, luego alfabéticamente.
Los nombres de tipos y nombres de variables están alineados.
Las "columnas" de tipo y nombre se separan con dos espacios.
Los arreglos grandes se colocan al final de un bloque de declaraciones:

```c
u_char                      *rv, *p;
ngx_conf_t                  *cf;
ngx_uint_t                   i, j, k;
unsigned int                 len;
struct sockaddr             *sa;
const unsigned char         *data;
ngx_peer_connection_t       *pc;
ngx_http_core_srv_conf_t   **cscfp;
ngx_http_upstream_srv_conf_t *us, *uscf;
u_char                       text[NGX_SOCKADDR_STRLEN];
```

Las variables estáticas y globales pueden ser inicializadas en la declaración:

```c
static ngx_str_t  ngx_http_memcached_key = ngx_string("memcached_key");
```

```c
static ngx_uint_t  mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
```

```c
static uint32_t  ngx_crc32_table16[] = {
    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    ...
    0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
```

Existen numerosas combinaciones comunes de tipos/nombres:

```c
u_char                        *rv;
ngx_int_t                      rc;
ngx_conf_t                    *cf;
ngx_connection_t              *c;
ngx_http_request_t            *r;
ngx_peer_connection_t         *pc;
ngx_http_upstream_srv_conf_t  *us, *uscf;
```

<a id="functions"></a>

### Funciones

Todas las funciones (incluso las estáticas) deben tener prototipos.
Los prototipos incluyen los nombres de los argumentos.
Los prototipos largos se envuelven con una sangría única en las líneas de continuación:

```c
static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf,
    ngx_http_core_main_conf_t *cmcf);

static char *ngx_http_merge_servers(ngx_conf_t *cf,
    ngx_http_core_main_conf_t *cmcf, ngx_http_module_t *module,
    ngx_uint_t ctx_index);
```

El nombre de la función en una definición empieza en una nueva línea.
Las llaves de apertura y cierre del cuerpo de la función están en líneas separadas.
El cuerpo de la función está indentado.
Hay dos líneas en blanco entre funciones:

```c
static ngx_int_t
ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len)
{
    ...
}


static ngx_int_t
ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
{
    ...
}
```

No hay espacio entre el nombre de la función y el paréntesis de apertura.
Las llamadas largas a funciones se envuelven de modo que las líneas de continuación comienzan
en la posición del primer argumento de la función.
Si esto es imposible, formatee la primera línea de continuación para que termine en la posición 79:

```c
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
               "http header: \"%V: %V\"",
               &h->key, &h->value);

hc->busy = ngx_palloc(r->connection->pool,
                  cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *));
```

La macro `ngx_inline` debe utilizarse en lugar de
`inline`:

```c
static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf);
```

<a id="expressions"></a>

### Expresiones

Los operadores binarios, excepto `.` y `->`,
deben ir separados de sus operandos por un espacio.
Los operadores unarios y los subíndices no se separan de sus operandos por espacios:

```c
width = width * 10 + (*fmt++ - '0');
```

```c
ch = (u_char) ((decoded << 4) + (ch - '0'));
```

```c
r->exten.data = &r->uri.data[i + 1];
```

Los casteos están separados por un espacio de las expresiones a las que se aplican.
Un asterisco dentro de un casteo está separado por un espacio del nombre del tipo:

```c
len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1);
```

Si una expresión no cabe en una sola línea, se envuelve.
El punto preferido para romper una línea es un operador binario.
La línea de continuación se alinea con el inicio de la expresión:

```c
if (status == NGX_HTTP_MOVED_PERMANENTLY
    || status == NGX_HTTP_MOVED_TEMPORARILY
    || status == NGX_HTTP_SEE_OTHER
    || status == NGX_HTTP_TEMPORARY_REDIRECT
    || status == NGX_HTTP_PERMANENT_REDIRECT)
{
    ...
}
```

```c
p->temp_file->warn = "an upstream response is buffered "
                     "to a temporary file";
```

Como último recurso, es posible envolver una expresión para que
la línea de continuación termine en la posición 79:

```c
hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
                                     + size * sizeof(ngx_hash_elt_t *));
```

Las reglas anteriores también se aplican a subexpresiones,
donde cada subexpresión tiene su propio nivel de sangría:

```c
if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)
     || c->stale_updating) && !r->background
    && u->conf->cache_background_update)
{
    ...
}
```

A veces, es conveniente envolver una expresión después de un casteo.
En este caso, la línea de continuación está indentada:

```c
node = (ngx_rbtree_node_t *)
           ((u_char *) lr - offsetof(ngx_rbtree_node_t, color));
```

Los punteros se comparan explícitamente con
`NULL` (no `0`):

```c
if (ptr != NULL) {
    ...
}
```

<a id="conditionals-and-loops"></a>

### Condicionales y bucles

La palabra clave `if` se separa de la condición
por un espacio.
La llave de apertura se coloca en la misma línea, o en una
línea dedicada si la condición ocupa varias líneas.
La llave de cierre se coloca en una línea dedicada, opcionalmente seguida de
`else if` / `else`.
Normalmente, hay una línea vacía antes de la
parte `else if` / `else`:

```c
if (node->left == sentinel) {
    temp = node->right;
    subst = node;

} else if (node->right == sentinel) {
    temp = node->left;
    subst = node;

} else {
    subst = ngx_rbtree_min(node->right, sentinel);

    if (subst->left != sentinel) {
        temp = subst->left;

    } else {
        temp = subst->right;
    }
}
```

Reglas de formato similares se aplican a los bucles `do` y
`while`:

```c
while (p < last && *p == ' ') {
    p++;
}
```

```c
do {
    ctx->node = rn;
    ctx = ctx->next;
} while (ctx);
```

La palabra clave `switch` se separa de la condición
por un espacio.
La llave de apertura se coloca en la misma línea.
La llave de cierre se coloca en una línea dedicada.
Las palabras clave `case` se alinean con
`switch`:

```c
switch (ch) {
case '!':
    looked = 2;
    state = ssi_comment0_state;
    break;

case '<':
    copy_end = p;
    break;

default:
    copy_end = p;
    looked = 0;
    state = ssi_start_state;
    break;
}
```

La mayoría de los bucles `for` se formatean de la siguiente manera:

```c
for (i = 0; i < ccf->env.nelts; i++) {
    ...
}
```

```c
for (q = ngx_queue_head(locations);
     q != ngx_queue_sentinel(locations);
     q = ngx_queue_next(q))
{
    ...
}
```

Si se omite alguna parte de la instrucción `for`,
esto se indica mediante el comentario `/* void */`:

```c
for (i = 0; /* void */ ; i++) {
    ...
}
```

Un bucle con un cuerpo vacío también se indica mediante el
comentario `/* void */` que puede colocarse en la misma línea:

```c
for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
```

Un bucle infinito tiene este aspecto:

```c
for ( ;; ) {
    ...
}
```

<a id="labels"></a>

### Etiquetas

Las etiquetas están rodeadas de líneas vacías y se indentan al nivel anterior:

```c
    if (i == 0) {
        u->err = "host not found";
        goto failed;
    }

    u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
    if (u->addrs == NULL) {
        goto failed;
    }

    u->naddrs = i;

    ...

    return NGX_OK;

failed:

    freeaddrinfo(res);
    return NGX_ERROR;
```

<a id="debugging-memory-issues"></a>

## Depuración de problemas de memoria

Para depurar problemas de memoria como desbordamientos de búfer o errores de uso después de liberar, puede
usar [AddressSanitizer](https://en.wikipedia.org/wiki/AddressSanitizer)
(ASan), compatible con algunos compiladores modernos.
Para habilitar ASan con `gcc` y `clang`,
use la opción de compilador y enlazador `-fsanitize=address`.
Al compilar Angie, esto se puede hacer añadiendo la opción a
los parámetros `--with-cc-opt` y `--with-ld-opt`
del script `configure`.

Dado que la mayoría de las asignaciones en Angie se realizan desde el
[pool](#pool) interno de Angie, habilitar ASan puede no ser siempre suficiente para depurar
problemas de memoria.
El pool interno asigna un gran fragmento de memoria del sistema y corta
asignaciones más pequeñas de él.
Sin embargo, este mecanismo se puede deshabilitar estableciendo la
macro `NGX_DEBUG_PALLOC` en `1`.
En este caso, las asignaciones se pasan directamente al asignador del sistema, dándole
control total sobre los límites del búfer.

La siguiente línea de configuración resume la información proporcionada anteriormente.
Se recomienda al desarrollar módulos de terceros y probar Angie en
diferentes plataformas.

```bash
auto/configure --with-cc-opt='-fsanitize=address -DNGX_DEBUG_PALLOC=1'
               --with-ld-opt=-fsanitize=address
```

<a id="common-pitfalls"></a>

## Errores comunes

<a id="writing-a-c-module"></a>

### Escribir un módulo en C

El error más común es intentar escribir un módulo en C completo
cuando se puede evitar.
En la mayoría de los casos, su tarea se puede lograr creando una configuración adecuada.
Si escribir un módulo es inevitable, intente hacerlo
lo más pequeño y simple posible.
Por ejemplo, un módulo solo puede exportar algunas
[variables](#http_variables).

Antes de comenzar un módulo, considere las siguientes preguntas:

* ¿Es posible implementar una característica deseada usando
  [módulos ya disponibles](https://es.angie.software//angie/docs/configuration/modules/index.md#modules)?
* ¿Es posible resolver un problema usando lenguajes de scripting integrados,
  como [Perl](https://es.angie.software//angie/docs/configuration/modules/http/http_perl.md#http-perl) o [NJS](https://es.angie.software//angie/docs/installation/external-modules/njs.md#external-njs)?

<a id="c-strings"></a>

### Cadenas en C

El tipo de cadena más utilizado en Angie,
[ngx_str_t](#string_overview), no es una cadena terminada en cero
al estilo de C.
No puede pasar los datos a funciones estándar de la biblioteca de C
como `strlen()` o `strstr()`.
En su lugar, se deben usar las [contrapartes](#string_overview) de Angie
que aceptan `ngx_str_t` o un puntero a datos y una longitud.
Sin embargo, hay un caso en el que `ngx_str_t` contiene
un puntero a una cadena terminada en cero: las cadenas que provienen como resultado del
análisis del archivo de configuración están terminadas en cero.

<a id="global-variables"></a>

### Variables globales

Evite usar variables globales en sus módulos.
Lo más probable es que sea un error tener una variable global.
Cualquier dato global debe estar vinculado a un [ciclo de configuración](#cycle)
y asignarse desde el [pool de memoria](#pool) correspondiente.
Esto permite a Angie realizar recargas de configuración elegantes.
Un intento de usar variables globales probablemente romperá esta característica,
porque será imposible tener dos configuraciones al
mismo tiempo y deshacerse de ellas.
A veces se requieren variables globales.
En este caso, se necesita especial atención para gestionar la reconfiguración
adecuadamente.
Además, verifique si las bibliotecas utilizadas por su código tienen un estado
global implícito que pueda romperse al recargar.

<a id="manual-memory-management"></a>

### Gestión manual de memoria

En lugar de lidiar con el enfoque malloc/free que es propenso a errores,
aprenda a usar los [pools](#pool) de Angie.
Un pool se crea y se vincula a un objeto:
[configuración](#http_conf),
[ciclo](#cycle),
conexión <#http_connection>,
o [solicitud HTTP](#http_request).
Cuando el objeto se destruye, el pool asociado también se destruye.
Así que al trabajar con un objeto, es posible asignar la cantidad
necesaria desde el pool correspondiente y no preocuparse por liberar memoria
incluso en caso de errores.

<a id="dev-threads"></a>

### Hilos

Se recomienda evitar el uso de hilos en Angie porque definitivamente romperá cosas: la mayoría de las funciones de Angie no son seguras para hilos.
Se espera que un hilo solo ejecute llamadas al sistema y
funciones de biblioteca seguras para hilos.
Si necesita ejecutar algún código que no esté relacionado con el procesamiento de solicitudes de clientes,
la forma adecuada es programar un temporizador en el manejador de módulo `init_process`
y realizar las acciones requeridas en el manejador del temporizador.
Internamente, Angie hace uso de [hilos](#dev_threads) para
mejorar las operaciones relacionadas con E/S, pero este es un caso especial con muchas
limitaciones.

<a id="blocking-libraries"></a>

### Bibliotecas bloqueantes

Un error común es usar bibliotecas que son bloqueantes internamente.
La mayoría de las bibliotecas disponibles son síncronas y bloqueantes por naturaleza.
En otras palabras, realizan una operación a la vez y pierden
tiempo esperando la respuesta del otro extremo.
Como resultado, cuando se procesa una solicitud con dicha biblioteca, todo el
worker de Angie se bloquea, destruyendo así el rendimiento.
Use solo bibliotecas que proporcionen una interfaz asíncrona y no
bloqueen todo el proceso.

<a id="http-requests-to-external-services"></a>

### Solicitudes HTTP a servicios externos

A menudo, los módulos necesitan realizar una llamada HTTP a algún servicio externo.
Un error común es usar alguna biblioteca externa, como libcurl,
para realizar la solicitud HTTP.
Es absolutamente innecesario traer una gran cantidad de código
externo (¡probablemente [bloqueante](#using_libraries)!)
para la tarea que puede ser realizada por el propio Angie.

Hay dos escenarios de uso básicos cuando se necesita una solicitud externa:

* en el contexto del procesamiento de una solicitud de cliente (por ejemplo, en un manejador de contenido)
* en el contexto de un proceso worker (por ejemplo, manejador de temporizador)

En el primer caso, lo mejor es usar
la [API de subrequests](#http_subrequests).
En lugar de acceder directamente al servicio externo, declare una ubicación
en la configuración de Angie y dirija su subrequest a esta ubicación.
Esta ubicación no se limita a
[hacer proxy de](https://es.angie.software//angie/docs/configuration/modules/http/http_proxy.md#proxy-pass)
solicitudes, sino que puede contener otras directivas de Angie.
Un ejemplo de este enfoque es la
directiva [auth_request](https://es.angie.software//angie/docs/configuration/modules/http/http_auth_request.md#id1) implementada en
[Auth Request](https://es.angie.software//angie/docs/configuration/modules/http/http_auth_request.md#http-auth-request).

Para el segundo caso, es posible usar la funcionalidad básica de cliente HTTP
disponible en Angie.
Por ejemplo, el
[módulo OCSP](https://github.com/nginx/nginx/blob/master/src/event/ngx_event_openssl_stapling.c)
implementa un cliente HTTP simple.
