Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How does nginx handle http requests

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/01 Report--

This article is about how nginx handles http requests. The editor thinks it is very practical, so share it with you as a reference and follow the editor to have a look.

1. Interaction between event events and http framework

After receiving the http request line and the http request header, the function ngx_http_process_request is called to start processing the http request. Because a http request consists of 11 processing phases, and each processing phase allows multiple http modules to intervene, in this function, the http modules of each phase are scheduled to complete the request together.

/ / after receiving the http request line and request header, the processing flow of http is the first read event callback of http processing request / / after the function is executed, the callback of read and write event will be set to ngx_http_request_handler. In this way, the ngx_http_request_handler function will be called to handle the next event, instead of calling ngx_http_process_request static void ngx_http_process_request (ngx_http_request_t * r) {ngx_connection_t * c; c = r-> connection; / / because the http request line and request header have been received, so we are ready to call each http module to process the request. / / therefore, you need to receive any read events from the client, so there is no problem of receiving http request header timeout if (c-> read- > timer_set) {ngx_del_timer (c-> read);} / / reset the current connection's read and write event callback c-> read- > handler = ngx_http_request_handler; c-> write- > handler = ngx_http_request_handler / / sets the read event callback of the http request object, which does nothing. / / what does the read event callback of the http request object have to do with the read event callback corresponding to the above connection? / / when the read event callback occurs, the read event callback ngx_http_request_handler corresponding to the connection will be called, / / the read event callback ngx_http_block_reading of the http request object will be called within this callback, and this callback will not do any event. Therefore, it is equivalent to ignoring the read event. Since the request line request header has been received, what we need to do now is to call each http module and / / process the received request line request header r-> read_event_handler = ngx_http_block_reading; / / call each http module to work together to process the request ngx_http_handler (r); / / process the subrequest ngx_http_run_posted_requests (c);}

The ngx_http_process_request function is called only once. If 11 http phases cannot be processed in a single schedule, the callback of read and write events corresponding to the connection object will be set to ngx_http_request_handler. The read event of the request object is set to ngx_http_block_reading, and the write event callback of the request object is set to ngx_http_core_run_phases, which is set in ngx_http_handler. So that when the event comes again, it will not call the

The ngx_http_process_request function handles. What does the read-write event callback of the event event module have to do with the read-write event callback of the http request object?

/ / http requests to handle callbacks for read and write events, which are set in the ngx_http_process_request function. / / the http request object's read and write event callback will be called in this function. Associate the event event module with the http framework static void ngx_http_request_handler (ngx_event_t * ev) {/ / if read and write events occur at the same time, only write events are triggered. Write event priority if (ev- > write) {r-> write_event_handler (r); / / set function ngx_http_handler to: ngx_http_core_run_phases} else {r-> read_event_handler (r); / / set function ngx_http_process_request to: ngx_http_block_reading} / / process sub-request ngx_http_run_posted_requests (c);}

As you can see, the http request object's read event callback is called in the read event callback of the connection object. The write event callback of the connection object invokes the write event callback of the http request object.

As can be seen in the figure, when the read event of event occurs, the callback ngx_http_request_handler of the read event will be called when epoll returns. In this read event callback, the http framework is called again, that is, the read event callback ngx_http_block_reading of the http request object. The read event callback of the http request object does nothing and is equivalent to ignoring the read event. So the http framework will return to the event module. Then why ignore the reading event? Because all the http request lines and request headers have been received, what we need to do now is to schedule the cooperation of various http modules to complete the docking of the received request lines and the processing of the request header. So there is no need to receive any data from the client.

The handling of write events is much more complicated. When the write event of event occurs, epoll will call the callback ngx_http_request_handler of the write event when it returns. In this callback of write event, the http framework will be called, that is, the write event callback ngx_http_core_run_phases of the http request object. The callback of the http framework dispatches the hander methods of each http module involved in the 11 request phases to complete the http request together.

Second, dispatch http module to process requests

In the above code, the ngx_http_core_run_phases function is dispatched so that each http module can intervene in the http request. This function is set in ngx_http_handler.

/ / call each http module to work together to process the request void ngx_http_handler (ngx_http_request_t * r) {/ / No internal jump is required. What is an internal jump? For example, there is a location structure in which / / if (! r-> internal) {/ / sets the array sequence number to 0, indicating that it is important to process the http request / / subscript from the first element of the array, which determines which of the 11 phases are currently being processed, and which http module of this stage processes the request r-> phase_handler = 0 } else {/ / need to do an internal jump cmcf = ngx_http_get_module_main_conf (r, ngx_http_core_module); / / set the sequence number to server_rewrite_index r-> phase_handler = cmcf- > phase_engine.server_rewrite_index } / / set the write event callback of the request object. This callback will schedule each http module involved in 11 http phases / / to complete the processing of the request r-> write_event_handler = ngx_http_core_run_phases; / / start scheduling each http module involved in 11 http phases ngx_http_core_run_phases (r);}

The ngx_http_core_run_phases function is simple enough to schedule the checker methods of all http modules involved in 11 http processing phases.

/ / call each http module to process the request together. The checker function will modify phase_handler void ngx_http_core_run_phases (ngx_http_request_t * r) {cmcf = ngx_http_get_module_main_conf (r, ngx_http_core_module); ph = cmcf- > phase_engine.handlers / / call the checker method of each http module, so that each http module can intervene in the http request while (ph [r-> phase_handler] .checker) {rc = ph [r-> phase_handler] .checker (r, & ph [r-> phase_handler]); / / returning the NGX_OK,http framework from the http module will return all control to the event module if (rc = = NGX_OK) {return }}

Suppose three http modules are involved in the http request in phase 2, one module in phase 3 is involved in the http request, and one module in phase 4 is involved in the request. When you start processing phase 2, all http modules in phase 2 are called for processing, and the phase_handler points to the start of phase 2. Then, each time one of the modules in Phase 2 is processed, phase_handler points to the next module in Phase 2 until the Phase 2 processing is complete.

When all http modules in Phase 2 are processed, phase_handler will point to Phase 3

Since phase 3 has only one http module, when all http modules in phase 3 are processed, the phase_handler will point to phase 4.

So when was this handlers array created? What does the checker callback of each http module do? Next, we will analyze these two problems.

Creation of an array of 11 http request phases

When parsing the nginx.conf configuration file, when the http block is parsed, the function ngx_http_block is called to start parsing the http block. In this function, all http modules that need to be involved in the 11 http request phases are also registered in the array.

/ / start parsing http block static char * ngx_http_block (ngx_conf_t * cf, ngx_command_t * cmd, void * conf) {/ / http configuration parsing is completed, so that each http module can intervene in 11 http phases for (m = 0; ngx_ modules [m]; masks +) {if (ngx_ modules [m]-> type! = NGX_HTTP_MODULE) {continue } module = ngx_ modules [m]-> ctx; if (module- > postconfiguration) {/ / each http module can register itself with 11 http phases if (module- > postconfiguration (cf)! = NGX_OK) {return NGX_CONF_ERROR;} in this postconfiguration function.

For example, the ngx_http_static_module static module sets the NGX_HTTP_CONTENT_PHASE phase callback of 11 http phases to ngx_http_static_handler.

/ / static module registers itself with NGX_HTTP_CONTENT_PHASE phase static ngx_int_t ngx_http_static_init (ngx_conf_t * cf) {cmcf = ngx_http_conf_get_module_main_conf (cf, ngx_http_core_module); h = ngx_array_push (& cmcf- > phass [http _ HTTP_CONTENT_PHASE] .handlers) of the 11 NGX_HTTP_CONTENT_PHASE request phases. / / processing method of static module in NGX_HTTP_CONTENT_PHASE phase * h = ngx_http_static_handler; return NGX_OK;}

For example, the ngx_http_access_module access module sets the NGX_HTTP_ACCESS_PHASE phase callback of 11 http phases to ngx_http_access_handler.

/ / the access module registers itself to the NGX_HTTP_ACCESS_PHASE phase static ngx_int_t ngx_http_access_init (ngx_conf_t * cf) {cmcf = ngx_http_conf_get_module_main_conf (cf, ngx_http_core_module); h = ngx_array_push (& cmcf- > phass [http _ HTTP_ACCESS_PHASE] .handlers) of the 11 NGX_HTTP_ACCESS_PHASE request phases / / processing method of access module in NGX_HTTP_ACCESS_PHASE phase * h = ngx_http_access_handler; return NGX_OK;}

The above operations only save the http modules that need to be involved in 11 http phases to the phases members in ngx_http_core_main_conf_t, not to phase_engine. So when will the contents of phases be saved to phase_engine? Or do it in the ngx_http_block function?

/ / start parsing http block static char * ngx_http_block (ngx_conf_t * cf, ngx_command_t * cmd, void * conf) {/ / initialize each phase of the request if (ngx_http_init_phase_handlers (cf, cmcf)! = NGX_OK) {return NGX_CONF_ERROR;}}

Suppose phase 1 has a http module intervention request, phase 2 has three http module intervention requests, and phase 3 also has an http module intervention request. After the function ngx_http_init_phase_handlers is called, the conversion from the ngx_http_phase_t phases [11] array to the ngx_http_phase_handler_t handlers array is shown in the following figure:

/ / initialize each stage of the request static ngx_int_t ngx_http_init_phase_handlers (ngx_conf_t * cf, ngx_http_core_main_conf_t * cmcf) {/ / 11 http request stages, each of which can have multiple http modules involved. / / there are a total of multiple http modules in 11 nodes. In order to open up the space for (I = 0; I) below

< NGX_HTTP_LOG_PHASE; i++) { n += cmcf->

Cmcf- [I] .handlers.nelts;} / / Open up space for callback ph = ngx_pcalloc (cf- > pool,n * sizeof (ngx_http_phase_handler_t) + sizeof (void *)) of all http modules involved in 11 processing phases; cmcf- > phase_engine.handlers = ph; n = 0; / / for each http processing phase, assign for (I = 0; I) to all http modules involved in that phase

< NGX_HTTP_LOG_PHASE; i++) { h = cmcf->

Switch [I] .handlers.elts; switch (I) {before case NGX_HTTP_SERVER_REWRITE_PHASE:// finds location based on the requested uri, modify the uri phase if of the request (cmcf- > phase_engine.server_rewrite_index = = (ngx_uint_t)-1) {cmcf- > phase_engine.server_rewrite_index = n / / the position of the redirect module in the array} checker = ngx_http_core_rewrite_phase; / / the checker callback of each phase break; case NGX_HTTP_FIND_CONFIG_PHASE:// finds the location phase according to the requested uri (which can only be implemented by the http framework) find_config_index = n; ph- > checker = ngx_http_core_find_config_phase; n + Ph++; continue; case NGX_HTTP_REWRITE_PHASE: / / after finding location based on the requested rui, modify the uri phase if of the request (cmcf- > phase_engine.location_rewrite_index = = (ngx_uint_t)-1) {cmcf- > phase_engine.location_rewrite_index = n;} checker = ngx_http_core_rewrite_phase; break After modifying rul in case NGX_HTTP_POST_REWRITE_PHASE: / / NGX_HTTP_REWRITE_PHASE phase, prevent recursive modification of uri from causing endless loop phase if (use_rewrite) {ph- > checker = ngx_http_core_post_rewrite_phase; ph- > next = find_config_index / / the purpose is to jump to the NGX_HTTP_FIND_CONFIG_PHASE phase after address rewriting, and look up the location nameplate according to / / url rewriting; ph++;} continue; case NGX_HTTP_ACCESS_PHASE: / / whether to allow access to the server phase checker = ngx_http_core_access_phase; nasty + Break; case NGX_HTTP_POST_ACCESS_PHASE: / / construct the response phase if (use_access) {ph- > checker = ngx_http_core_post_access_phase; ph- > next = n; ph++;} continue for the client according to the error code of the ph++; phase Case NGX_HTTP_TRY_FILES_PHASE: / / try_file phase if (cmcf- > try_files) {ph- > checker = ngx_http_core_try_files_phase; nemesis; ph++;} continue Case NGX_HTTP_CONTENT_PHASE: / / processing http request content stage, which most http modules are most willing to intervene in checker = ngx_http_core_content_phase; break Default: / / NGX_HTTP_POST_READ_PHASE, / / NGX_HTTP_PREACCESS_PHASE, / / NGX_HTTP_LOG_PHASE checker method checker = ngx_http_core_generic_phase;} n + = cmcf- > phass [I] .handlers.nelts / / all http modules involved in each phase, all http modules in the same phase have a unique checker callback, / / but handler callback each module implements for (j = cmcf- > phases.handlers.nelts-1; j > = 0; Jmurf -) {ph- > checker = checker; ph- > handler = h [j]; ph- > next = n; ph++ }} return NGX_OK;}

4. Checker callback in http phase

In each of the 11 http processing phases, there is a checker function, although some of the checker functions are the same. For each processing phase, all http modules involved in this phase share the same checker function. The purpose of these checker functions is to schedule the handler methods of all http modules involved in this phase, or to switch to the next http request phase. Let's analyze the checker method of the three stages of NGX_HTTP_POST_READ_PHASE,NGX_HTTP_PREACCESS_PHASE,NGX_HTTP_LOG_PHASE.

/ / checker method of / / NGX_HTTP_POST_READ_PHASE, / / NGX_HTTP_PREACCESS_PHASE, / / NGX_HTTP_LOG_PHASE return value: the NGX_OK,http framework will return control to the epoll module ngx_int_t ngx_http_core_generic_phase (ngx_http_request_t * r _ x _ http _ phasehandlerroomt * ph) {ngx_int_t rc. / / call the processing method of the http module, so that the http module intervenes in the request phase rc = ph- > handler (r); / / jumps to the next http phase to execute if (rc = = NGX_OK) {r-> phase_handler = ph- > next; return NGX_AGAIN } / / the next http module if (rc = = NGX_DECLINED) {r-> phase_handler++; return NGX_AGAIN;} / / means that the newly executed handler cannot finish this phase in this scheduling, / / multiple schedules are required to complete the if (rc = = NGX_AGAIN | | rc = = NGX_DONE) {return NGX_OK } / / return error / * rc = = NGX_ERROR | | rc = = NGX_HTTP_... * / ngx_http_finalize_request (r, rc); return NGX_OK;}

At this point, the http framework dispatches all http modules to complete the http request. It has been analyzed.

Thank you for reading! This is the end of the article on "how nginx handles http requests". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, you can share it for more people to see!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report