📜 ⬆️ ⬇️

POST body processing in developed modules

Today there are enough manuals and descriptions how to develop your own module under nginx. For those on the tank, links can be found on the nginx website.
But, how to use the POST data, unfortunately the information was not enough.


To begin with, Igor Sysoev (by nginx ) is very careful about using POST data in modules. And this is, in principle, reasonable: as a rule, in POST data occupy a large amount compared to the volume of the header, therefore, the processing mechanism is different. And processing excess data can always indirectly affect performance. Processes in nginx should be as easy as possible so that the poker will process the connection as quickly as possible and begin processing the next one.

Consider the processing cycle:

')
As a rule, all http modules are hung on the response generation phase. The exception, of course, is upstream modules and filters. More details at Emiller

In the case of POST, everything is different; it may not be processed at all. If we look at the structure of the ngx_http_request_t * r request, which runs through all http modules as a red thread, then in the content handler, the value of the fields:
r-> request_body-> buf is the current buffer and
r-> request_body-> bufs - the chain of data buffers of the POST request will be empty (NULL). This is because it did not begin to be processed.

Processing a POST request is done by setting up a kelbeck "body handler" in ngx_http_read_client_request_body (a function defined in http_request_body.c).
There should be a code like this:
rc = ngx_http_read_client_request_body ( r, ngx_http_mymodule_body_handler ) ; // " " <br/>
// , , NGX_AGAIN, <br/>
<br/>
if ( rc >= NGX_HTTP_SPECIAL_RESPONSE ) { <br/>
return rc ; <br/>
} <br/>
<br/>
return NGX_DONE ;
rc = ngx_http_read_client_request_body ( r, ngx_http_mymodule_body_handler ) ; // " " <br/>
// , , NGX_AGAIN, <br/>
<br/>
if ( rc >= NGX_HTTP_SPECIAL_RESPONSE ) { <br/>
return rc ; <br/>
} <br/>
<br/>
return NGX_DONE ;

ngx_http_mymodule_body_handler is the handler for handling the POST request body. In the body handler, the handler phase is called. The body handler code should look like this:
static void ngx_http_mymodule_body_handler ( request_body * r ) { <br/>
ngx_int_t rc = NGX_OK ; <br/>
<br/>
rc = ngx_http_mymodule_phase_handler ( r ) ; // <br/>
if ( rc >= NGX_HTTP_SPECIAL_RESPONSE ) { <br/>
ngx_http_finalize_request ( f, 0 ) ; // , , . <br/>
} <br/>
return ; <br/>
} <br/>

static void ngx_http_mymodule_body_handler ( request_body * r ) { <br/>
ngx_int_t rc = NGX_OK ; <br/>
<br/>
rc = ngx_http_mymodule_phase_handler ( r ) ; // <br/>
if ( rc >= NGX_HTTP_SPECIAL_RESPONSE ) { <br/>
ngx_http_finalize_request ( f, 0 ) ; // , , . <br/>
} <br/>
return ; <br/>
} <br/>



In the handler phase, processing of chunks containing POST data is performed. The phase handler processes the data and sets the callback back to processing the body. The Handler Phase Code should be approximately as follows:
<br/>
ngx_int_t ngx_http_mymodule_phase_handler ( request_body * r ) { <br/>
<br/>
ngx_int_t rc = NGX_OK ; <br/>
if ( r - > request_body == NULL ) { <br/>
// POST , <br/>
rc = ngx_http_read_client_request_body ( r, ngx_http_mymodule_body_handler ) ; <br/>
<br/>
if ( rc >= NGX_HTTP_SPECIAL_RESPONSE ) { <br/>
return rc ; <br/>
} <br/>
<br/>
return NGX_DONE ; <br/>
} <br/>
<br/>
// ? <br/>
if ( r - > request_body - > rest ) { <br/>
return NGX_DONE ; <br/>
} <br/>
return rc ; <br/>
} <br/>


<br/>
ngx_int_t ngx_http_mymodule_phase_handler ( request_body * r ) { <br/>
<br/>
ngx_int_t rc = NGX_OK ; <br/>
if ( r - > request_body == NULL ) { <br/>
// POST , <br/>
rc = ngx_http_read_client_request_body ( r, ngx_http_mymodule_body_handler ) ; <br/>
<br/>
if ( rc >= NGX_HTTP_SPECIAL_RESPONSE ) { <br/>
return rc ; <br/>
} <br/>
<br/>
return NGX_DONE ; <br/>
} <br/>
<br/>
// ? <br/>
if ( r - > request_body - > rest ) { <br/>
return NGX_DONE ; <br/>
} <br/>
return rc ; <br/>
} <br/>




POSt request data is in the ngx_http_request_body_t structure defined in ngx_http_request.h
typedef struct { <br/>
ngx_temp_file_t * temp_file ; // ( ) <br/>
ngx_chain_t * bufs ; // . <br/>
ngx_buf_t * buf ; // <br/>
off_t rest ; <br/>
ngx_chain_t * to_write ; <br/>
ngx_http_client_body_handler_pt post_handler ; <br/>
} ngx_http_request_body_t ; <br/>

typedef struct { <br/>
ngx_temp_file_t * temp_file ; // ( ) <br/>
ngx_chain_t * bufs ; // . <br/>
ngx_buf_t * buf ; // <br/>
off_t rest ; <br/>
ngx_chain_t * to_write ; <br/>
ngx_http_client_body_handler_pt post_handler ; <br/>
} ngx_http_request_body_t ; <br/>


A pointer to this structure is defined in the ngx_http_request_s request structure:
r-> request_body;

The data of the current window is determined by the buffer frame:
r-> request_body-> buf-> start
r-> request_body-> buf-> end
or for large POST request sizes, the data is retrieved from the buffer chain r-> request_body-> bufs-> buf-> start ... end and the next buffer is then extracted, the address of which is in the next field. see the ngx_chain_s structure:
// core/ngx_buf.h
struct ngx_chain_s {
ngx_buf_t * buf ;
ngx_chain_t * next ;
} ;

size -- ( start end) Content-Length r->headers_in->off_t ;
- .

.
// core/ngx_buf.h
struct ngx_chain_s {
ngx_buf_t * buf ;
ngx_chain_t * next ;
} ;

size -- ( start end) Content-Length r->headers_in->off_t ;
- .

.

Source: https://habr.com/ru/post/76963/


All Articles