nginx_http_core_phase_event_handler

Overview

nginx provides several phases for developer, developer can register its own handler to some phases, do its own work without breaking nginx source code, it’s flexible, here are phases with order(runs from top to bottom).

  • NGX_HTTP_SERVER_REWRITE_PHASE
  • NGX_HTTP_FIND_CONFIG_PHASE
  • NGX_HTTP_REWRITE_PHASE
  • NGX_HTTP_POST_REWRITE_PHASE
  • NGX_HTTP_PREACCESS_PHASE
  • NGX_HTTP_ACCESS_PHASE
  • NGX_HTTP_POST_ACCESS_PHASE
  • NGX_HTTP_PRECONTENT_PHASE
  • NGX_HTTP_CONTENT_PHASE
  • NGX_HTTP_LOG_PHASE

each phase has a checker, nginx phase engine runs the checker with fixed order, inside each checker there could be several handlers, each checker runs handlers of that phase.

Note: phase is for client request(filter is for response), engine runs after parsing all request headers.

HTTP

phase

http phases

Data Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
typedef struct ngx_http_phase_handler_s  ngx_http_phase_handler_t;
typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);

/* each handler has such instance */
struct ngx_http_phase_handler_s {
/* each phase has a checker which calls handler
* and does extra work after handler returns
*/
ngx_http_phase_handler_pt checker;
ngx_http_handler_pt handler;
/* next phase to run, if handler does not run sequently, quick jump in some case,
* next is not always used, but used in some rare case
*
* most phase handler
* next: point to the subsequent phase
*
* post rewrite phase handler
* next: points to find_conf_phase, used when uri change(rewrite change uri)
* in some phase, next is not used actually
*/
ngx_uint_t next;
};

typedef struct {
/* all ordered handlers from all phases used for runtime */
ngx_http_phase_handler_t *handlers;
/* server_rewrite_index: NGX_HTTP_SERVER_REWRITE_PHASE(first handler index)
* location_rewrite_index: NGX_HTTP_REWRITE_PHASE(first handler index)
* for quick jump in some case
*/
ngx_uint_t server_rewrite_index;
ngx_uint_t location_rewrite_index;
} ngx_http_phase_engine_t;

typedef struct {
/* phase_engine is used runtime which copies handlers from each phase
* and save them in a large array phase_engine->handlers
* each element is ngx_http_phase_handler_s which has the copied handler
* and other info like phase checker and next phase to run
*/
ngx_http_phase_engine_t phase_engine;

/* stores all handlers for each phase, after initialized each module
* as a module can register handler at different phases
* we save that handler to the given phase
*
* each phase is an array which stores all handlers
* for that phase, each handler takes one slot
* ngx_http_handler_pt
*----------------------------------------------------
* it's temporary use, NOT used runtime
*----------------------------------------------------
*/
ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;

API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// construct runtime phase engine
static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)

void ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;

cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

/* all handlers */
ph = cmcf->phase_engine.handlers;

/* checker converts handler return value
*
* handler return checker return
*
* NGX_DECLINE NGX_AGAIN: next handler
* NGX_DONE NGX_OK: run phase done
* NGX_OK different based on checker
* NGX_XX(error) finalize_request, NGX_OK, run phase done
* NGX_YYY(not error) based on checker
*
* more detail refer to each checker definition
*/
while (ph[r->phase_handler].checker) {

rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);

if (rc == NGX_OK) {
/* return only when checker returns NGX_OK */
return;
}
}
}

event handler

For http request, the event handler changes during what it’s processing, process header or process body, here is diagram shows how they are changing during processing request.

http event handler