First, the read request body has entered the HTTP request 11 phase, we need to do some modules of the request body part, so this module needs to register the function at this stage, in the reading function requirements of the body ngx_http_read_client_request_body () is present. Just a different module may handle the request body differently. The function to read the whole is included in the Conent_handler function of a module. For example, proxy modules, fastcgi modules, UWSGI modules and other modules are interested in the request body, then the function of the read request body is registered in the Content_handler of these modules.
The previous section said Nginx core itself will not actively read the request body, this work is to the request processing phase of the module to do, but Nginx core provides the Ngx_http_read_client_request_body () interface to read the request body, An interface-ngx_http_discard_request_body () that discards the request body is also provided, in each phase of the request run. No matter what phase of the module assumes interest in the request body or want to lose the client sent over the request body. The two interfaces can be called separately to complete.
These two interfaces are standard interfaces provided by the Nginx core to handle the request body. Let's say you want some request-body-related instructions (such as client_body_in_file_only,client_body_buffer_size, etc.) in the configuration file to work as expected.
as well as the normal use of nginx built-in and the request body related variables (such as $request_body and $request_body_file). in general, all modules must call these interfaces to complete the corresponding operation, assuming that they need to define the interface to handle the request body, should also be compatible with nginx default behavior.
1, read the request body
The read of the request body generally occurs in the Nginx content handler. Some nginx built-in modules. For example, the proxy module, fastcgi module. UWSGI module and so on. The behavior of these modules must be the client's request body (if any) to the corresponding protocol complete forwarding to the back-end service process, all of these modules are called the Ngx_http_read_client_request_body () interface to complete the request body read.
It is worth noting that these modules will fully read the client's request body before beginning to forward the data back end.
Because of the memory limitations, the Ngx_http_read_client_request_body () interface reads requests that are partially or all written to a temporary file, depending on the size of the request body and the associated instruction configuration, the request body may be completely placed in a contiguous memory. may also be placed in two different memory, may also have a temporary file, and finally may be part of the memory, the remainder in the temporary file. Here are some instructions related to these different storage behaviors:
Client_body_buffer_size: Sets the buffer size of the cache request body. Default to the system page size of twice times, when the size of the request body exceeds this size, Nginx will write the request body to the temporary file. ability to set the right size based on business requirements. Try to avoid disk IO operations;
Client_body_in_single_buffer: Indicates whether the request body is stored intact in a contiguous memory and defaults to off, assuming this instruction is set to ON. The nginx will ensure that the request body is not larger than the value set by the Client_body_buffer_size, is stored in a contiguous memory, but more than the size of the whole will be written to a temporary file;
Client_body_in_file_only: Sets whether the request body is always stored in a temporary file, default feel off, when this designation is set to ON, even if the client display indicates that the request body length is 0 o'clock. Nginx will still create a temporary file for the request.
We then introduce the implementation of the Ngx_http_read_client_request_body () interface, which is defined as the following:
[CPP]View Plaincopy
- <span style= "FONT-FAMILY:SIMSUN;FONT-SIZE:18PX;" >ngx_int_t
- Ngx_http_read_client_request_body (ngx_http_request_t *r,
- Ngx_http_client_body_handler_pt Post_handler) </span>
The interface has 2 parameters, and the 1th is a pointer to the request structure. The 2nd one is a function pointer. When the request body is finished reading. It will be called. Previously, the module logic will run after the request body has been read, based on the existing behavior of Nginx. This callback function is usually the logical processing function of the module. The ngx_http_read_client_request_body () function first adds 1 to the reference of the corresponding main request of the parameter R. The purpose of doing this is related to the context in which the interface is invoked. Generally speaking. The module is calling this interface in the content handler, a typical invocation such as the following:
[CPP]View Plaincopy
- <span style= "FONT-FAMILY:SIMSUN;FONT-SIZE:18PX;" > Static ngx_int_t
- Ngx_http_proxy_handler (ngx_http_request_t *r)
- {
- ...
- rc = Ngx_http_read_client_request_body (R, Ngx_http_upstream_init);
- if (RC >= ngx_http_special_response) {
- return RC;
- }
- return Ngx_done;
- }</span>
The code above is called ngx_http_read_client_request_body () in the content Handler,ngx_http_proxy_handler () of the Porxy module. function, where Ngx_http_upstream_init () is passed into the interface as a callback function. In addition the context of the content handler call of the Nginx module is as follows:
[CPP]View Plaincopy
- <span style= "FONT-FAMILY:SIMSUN;FONT-SIZE:18PX;" >ngx_int_t
- Ngx_http_core_content_phase (ngx_http_request_t *r,
- ngx_http_phase_handler_t *ph)
- {
- ...
- if (r->content_handler) {
- R->write_event_handler = Ngx_http_request_empty_handler;
- Ngx_http_finalize_request (R, R->content_handler (r));
- return NGX_OK;
- }
- ...
- }</span>
In the above code, after the content handler call, its return value calls the ngx_http_finalize_request () function as ngx_http_read_client_request_body () The return value of the function is Ngx_again. At this point the content handler, for example Ngx_http_proxy_handler () will return Ngx_done, and Ngx_done as a reference to ngx_ The Http_finalize_request () function causes the reference count of the master request to be reduced by 1, so it offsets the ngx_http_read_client_request_ The body () function begins by adding 1 to the master request count.
Next, go back to the ngx_http_read_client_request_body () function. It checks whether the requested body of the request has been read or discarded, assuming it is. Call the callback function directly and return NGX_OK, here is actually for the sub-request check, the sub-request is a concept in Nginx, Nginx in the current request to initiate another or more new sub-request to access other location, A detailed description of the sub-request will be analyzed in a later section, in general the request does not need to be read by the child request body.
The function then calls Ngx_http_test_expect () to check if the client sent the Expect:100-continue header, and then replies "http/1.1 Continue" to the client. . Based on the HTTP 1.1 protocol, the client is able to send a expect header to indicate to the server the expected sending request body, and the server assumes that the client is sending the request body. Will reply "http/1.1 Continue" when the client receives it. The sending request body is only started.
Then continue to prepare for receiving the request body. Assign a ngx_http_request_body_t structure and save it in R->request_body, which is used to hold the request body read process to use the cache reference, temporary file reference, the remaining request body size and other information, its definition such as the following.
[CPP]View Plaincopy
- <span style= "FONT-FAMILY:SIMSUN;FONT-SIZE:18PX;" > typedef struct {
- ngx_temp_file_t *temp_file;
- Ngx_chain_t *bufs;
- ngx_buf_t *buf;
- off_t rest;
- Ngx_chain_t *to_write;
- Ngx_http_client_body_handler_pt Post_handler;
- } ngx_http_request_body_t;</span>
Temp_file: A pointer to a temporary file that stores the request body;
Bufs: The chain header that points to the save request body;
BUF: Points to the memory cache that is currently used to hold the request body.
Rest: The current size of the remaining request body;
Post_handler: Saves the callback function passed to the Ngx_http_read_client_request_body () function.
After the preparation is done, the function starts to check whether the request has a content_length header. Assuming that the header is not available or the client sends a CONTENT_LENGTH header with a value of 0 indicating that there is no request body, call the callback function directly and return to NGX_OK. Of course , suppose the client_body_in_file_only instruction is set to on, and content_length is 0 o'clock . The function precedes the call to the callback function. An empty temporary file is created.
Entering the lower part of the function indicates that the client request does indicate that the request body is being sent, and that the function checks whether the request body was read before the request header was read. The check here is to infer if there are any unhandled data in the cache (R->HEADER_IN) that holds the request header. Suppose you have read-ahead data. The ngx_buf_t structure is allocated and the pre-read data in the r->header_in is stored in it, assuming that there is still space in the r->header_in, and that the remaining unread request body can be contained. These spaces will continue to be used. Instead of allocating a new cache, and of course even assuming that the request body has been read-ahead, there is no need to continue processing, when the callback function is called back.
Assuming no pre-read data or incomplete read-ahead, the function allocates a new piece of memory (unless r->header_in has enough space left). Also assume that the request_body_in_single_buf instruction is set to No. The pre-read data is copied into the newly opened memory block, and the actual read request body operation is in the Ngx_http_do_read_client_request_body () function, which loops the read request body and saves it in the cache. Assume that the cache is fully written. The data will be emptied and written back to the temporary file. Of course, there might not be a chance to read the data at once. The function mounts the read event and sets the read event handler to Ngx_http_read_client_request_body_handler. In addition Nginx core to two times the request body of the Read event also made a time-out setting, client_body_timeout instruction can set this timeout time, default feel 60s, assuming the next read event timeout, Nginx will return 408 to the client.
Finally after reading the request body. Ngx_http_do_read_client_request_body () adjusts the request body to the desired location (memory or file), depending on the configuration. In all cases the request from the principal is able to r->request_body the bufs to get the list, the list can be up to 2 nodes, each node is a buffer, but the contents of this buffer can be stored in memory. It can be stored in a disk file.
Another $request_body variable is available only when the request body has been read out and stored in memory for all, the ability to obtain the corresponding data.
Nginx Source Code Analysis--Read request body (1)