当一个模块想要主动的丢弃客户端发过的请求体body,可以调用nginx核心提供的ngx_http_discard_request_body()接口,主动丢弃的原因可能有很多种,如模块的业务逻辑压根不需要请求体 ,客户端发送的请求体是非法的等。下面开始分析ngx_http_discard_request_body()函数:
ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r) { ssize_t size; ngx_event_t *rev; //子请求或者已经调用过本函数,则不需要处理 if (r != r->main || r->discard_body) { return NGX_OK; } //ngx_http_test_expect函数是处理http1.1 expect的情况, //根据http1.1的expect机制,如果客户端发送了expect头, //而服务端不希望接收请求体时,必须返回417(Expectation Failed)错误。 if (ngx_http_test_expect(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rev = r->connection->read; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body"); //删掉读事件上的定时器,因为这时本身就不需要请求体,所以也无所谓客户端发送的快还是慢了。 if (rev->timer_set) { ngx_del_timer(rev); } if (r->headers_in.content_length_n <= 0 || r->request_body) { return NGX_OK; } //检查是否已经读取了数据 size = r->header_in->last - r->header_in->pos; if (size) { if (r->headers_in.content_length_n > size) {//数据还没有读取完毕 r->header_in->pos += size; r->headers_in.content_length_n -= size; } else {//数据已经读取完毕 r->header_in->pos += (size_t) r->headers_in.content_length_n; r->headers_in.content_length_n = 0; return NGX_OK; } } //数据还没有读取完毕,则挂载ngx_http_discarded_request_body_handler处理函数 r->read_event_handler = ngx_http_discarded_request_body_handler; //挂载读事件 if (ngx_handle_read_event(rev, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; }
//读取的数据会直接丢弃 if (ngx_http_read_discarded_request_body(r) == NGX_OK) { r->lingering_close = 0;//要读取的数据已经读取完毕并丢弃,置关闭标志 } else { r->count++; r->discard_body = 1; //数据还没有读取完毕,置变量,read_event_handler会下次处理 } return NGX_OK; }
void ngx_http_discarded_request_body_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_msec_t timer; ngx_event_t *rev; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; c = r->connection; rev = c->read; //检测是否超时,超时则直接断开连接 if (rev->timedout) { c->timedout = 1; c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); return; } //在ngx_http_finalize_connection()函数中,如果检查到还有未丢弃的请求体时, //nginx会添加一个读事件定时器,它的时长为lingering_timeout指令所指定, //默认为5秒,不过这个时间仅仅两次读事件之间的超时时间, //等待请求体的总时长为lingering_time指令所指定,默认为30秒。 if (r->lingering_time) { timer = (ngx_msec_t) (r->lingering_time - ngx_time()); if (timer <= 0) { r->discard_body = 0; r->lingering_close = 0; ngx_http_finalize_request(r, NGX_ERROR); return; } } else { timer = 0; } rc = ngx_http_read_discarded_request_body(r); if (rc == NGX_OK) { r->discard_body = 0; r->lingering_close = 0; ngx_http_finalize_request(r, NGX_DONE); return; } /* rc == NGX_AGAIN */ if (ngx_handle_read_event(rev, 0) != NGX_OK) { c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); return; } if (timer) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); timer *= 1000; if (timer > clcf->lingering_timeout) { timer = clcf->lingering_timeout; } ngx_add_timer(rev, timer); } }