ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); ssize_t size; ngx_event_t *rev; if (r != r->main || r->discard_body) { return NGX_OK; } 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; } } if (ngx_http_read_discarded_request_body(r) == NGX_OK) { r->lingering_close = 0; return NGX_OK; } /* == NGX_AGAIN */ 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; } r->count++; r->discard_body = 1; return NGX_OK; }
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; } 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->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; } } r->discard_body = 1; r->read_event_handler = ngx_http_read_discarded_request_body_handler; if (ngx_handle_read_event(rev, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->count++; (void) ngx_http_read_discarded_request_body(r); 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; } if (r->lingering_time) { timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); if ((ngx_msec_int_t) 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; } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); 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); } }
ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r) { ssize_t size; ngx_int_t rc; ngx_event_t *rev; if (r != r->main || r->discard_body || r->request_body) { return NGX_OK; } 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->headers_in.chunked) { return NGX_OK; } size = r->header_in->last - r->header_in->pos; if (size || r->headers_in.chunked) { rc = ngx_http_discard_request_body_filter(r, r->header_in); if (rc != NGX_OK) { return rc; } if (r->headers_in.content_length_n == 0) { return NGX_OK; } } rc = ngx_http_read_discarded_request_body(r); if (rc == NGX_OK) { r->lingering_close = 0; return NGX_OK; } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } /* rc == NGX_AGAIN */ 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; } r->count++; r->discard_body = 1; return NGX_OK; }
void ngx_http_discarded_request_body_handler(ngx_http_request_t *r) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); 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; } 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); } }
// 丢弃请求体读事件处理,在epoll里加入读事件和handler // 这时epoll通知socket上有数据可以读取 // ngx_http_read_discarded_request_body ok表示数据已经读完 // 传递done给ngx_http_finalize_request,并不是真正结束请求 // 因为有引用计数器r->count,所以在ngx_http_close_request里只是减1的效果 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; // 检查超时,使用的是lingering_timeout // 普通的丢弃不会进入这里 // 用在keepalive,见ngx_http_set_keepalive if (rev->timedout) { c->timedout = 1; c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); return; } // 设置延时关闭时间,那么就会设置超时时间timer // 如果是一开始就丢弃请求体,那么就不会走这里, timer=0 if (r->lingering_time) { // 计算当前事件,是否要关闭 timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); // 延时关闭时间已到,不需要再接收数据了 // 清除标志,调用ngx_http_finalize_request结束请求 if ((ngx_msec_int_t) timer <= 0) { r->discard_body = 0; r->lingering_close = 0; ngx_http_finalize_request(r, NGX_ERROR); return; } } else { timer = 0; } // 这时epoll通知socket上有数据可以读取 // 读取请求体数据并丢弃 // 使用固定的4k缓冲区接受丢弃的数据 // 一直读数据并解析,检查content_length_n,如果无数据可读就返回NGX_AGAIN rc = ngx_http_read_discarded_request_body(r); // ok表示数据已经读完 // 传递done给ngx_http_finalize_request,并不是真正结束请求 // 因为有引用计数器r->count,所以在ngx_http_close_request里只是减1的效果 if (rc == NGX_OK) { r->discard_body = 0; r->lingering_close = 0; ngx_http_finalize_request(r, NGX_DONE); return; } // 出错 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); return; } /* rc == NGX_AGAIN */ // again则需要再次加入epoll事件,等有数据来再次进入 // rev的handler不变,直接加入 // 注意,读事件的handler实际上是ngx_http_request_handler // 但最终会调用r->read_event_handler,即本函数 if (ngx_handle_read_event(rev, 0) != NGX_OK) { c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); return; } // 如果是一开始就丢弃请求体,那么就不会走这里, timer=0 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); } }
// 要求nginx丢弃请求体数据 // 子请求不与客户端直接通信,不会有请求体的读取 // 已经设置了discard_body标志,表示已经调用了此函数 // request_body指针不空,表示已经调用了此函数 // 这三种情况就无需再启动读取handler,故直接返回成功 // 因为要丢弃数据,所以不需要检查超时,也就是说即使超时也不算是错误 // 如果头里的长度是0且不是chunked // 说明没有请求体数据,那么就无需再读,直接返回成功 // *一直*读数据并解析,检查content_length_n,如果无数据可读就返回NGX_AGAIN // 因为使用的是et模式,所以必须把数据读完 // 调用ngx_http_discard_request_body_filter检查收到的数据 // 使用回调ngx_http_discarded_request_body_handler读取数据 ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r) { ssize_t size; ngx_int_t rc; ngx_event_t *rev; // 子请求不与客户端直接通信,不会有请求体的读取 // 已经设置了discard_body标志,表示已经调用了此函数 // request_body指针不空,表示已经调用了此函数 // 这三种情况就无需再启动读取handler,故直接返回成功 // discard_body在本函数最末尾设置,防止重入 if (r != r->main || r->discard_body || r->request_body) { return NGX_OK; } #if (NGX_HTTP_V2) if (r->stream) { r->stream->skip_data = 1; return NGX_OK; } #endif 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); } // 如果头里的长度未设置、或者是0且不是chunked // 说明没有请求体数据,那么就无需再读,直接返回成功 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { return NGX_OK; } // 检查缓冲区里在解析完头后是否还有数据 // 也就是说之前可能读取了部分请求体数据 size = r->header_in->last - r->header_in->pos; // 有数据,或者是chunked数据 // 有可能已经读取了一些请求体数据,所以先检查一下 if (size || r->headers_in.chunked) { // 检查请求结构体里的缓冲区数据,丢弃 // 有content_length_n指定确切长度,那么只接收,不处理,移动缓冲区指针 // chunked数据需要解析数据 rc = ngx_http_discard_request_body_filter(r, r->header_in); // 不是ok表示出错,不能再读取数据 if (rc != NGX_OK) { return rc; } // content_length_n==0表示数据已经全部读完 // 就已经完成了丢弃任务,否则就要加入epoll读事件继续读 if (r->headers_in.content_length_n == 0) { return NGX_OK; } } // 走到这里,表明content_length_n>=0,还有数据要读取 // 接下来就读取请求体数据并丢弃 // 使用固定的4k缓冲区接受丢弃的数据 // 一直读数据并解析,检查content_length_n,如果无数据可读就返回NGX_AGAIN // 因为使用的是et模式,所以必须把数据读完 // 需要使用回调ngx_http_discarded_request_body_handler读取数据 rc = ngx_http_read_discarded_request_body(r); if (rc == NGX_OK) { r->lingering_close = 0; return NGX_OK; } // 出错 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } /* rc == NGX_AGAIN */ // 读事件not ready,无数据可读,那么就要在epoll里加入读事件和handler // 注意,不再需要加入定时器 // 之后再有数据来均由ngx_http_discarded_request_body_handler处理 // 里面还是调用ngx_http_read_discarded_request_body读数据 r->read_event_handler = ngx_http_discarded_request_body_handler; // 注意,读事件的handler实际上是ngx_http_request_handler // 但最终会调用r->read_event_handler if (ngx_handle_read_event(rev, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } // 引用计数器增加,表示此请求还有关联的操作,不能直接销毁 r->count++; // 设置丢弃标志,防止再次进入本函数 r->discard_body = 1; 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; //首先检查TCP连接上的读事件的timedout标志位,为1时表示已经超时,这时调用ngx_http_finalize_request方法结束请求,传递的参数是NGX_ERROR,流程结束 if (rev->timedout) { c->timedout = 1; c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); return; } if (r->lingering_time) { timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); if ((ngx_msec_int_t) timer <= 0) { r->discard_body = 0; r->lingering_close = 0; ngx_http_finalize_request(r, NGX_ERROR); return; } } else { timer = 0; } //调用ngx_http_read_discarded_request_body方法接收包体,检测其返回值。 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; } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); return; } /* rc == NGX_AGAIN */ if (ngx_handle_read_event(rev, 0, NGX_FUNC_LINE) != 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, NGX_FUNC_LINE); } }
ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r) { ssize_t size; ngx_int_t rc; ngx_event_t *rev; #if (NGX_HTTP_SPDY) if (r->spdy_stream && r == r->main) { r->spdy_stream->skip_data = NGX_SPDY_DATA_DISCARD; return NGX_OK; } #endif /* 首先检查当前请求是一个子请求还是原始请求。为什么要检查这个呢?因为对于子请求而言,它木是来自客户端的请求,所以不存在处理HTTP 请求包体的概念。如果当前请求是原始请求,则继续执行;如果它是子请求,则直接返回NGX_OK表示丢弃包体成功。检查ngx_http_request_t结构 体的request_body成员,如果它已经被赋值过且不再为NULL空指针,则说明已经接收过包体了,这时也需要返回NGX_OK表示成功。 */ if (r != r->main || r->discard_body || r->request_body) { return NGX_OK; } 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"); /* 检查请求连接上的读事件是否在定时器中,这是因为丢弃包体不用考虑超时问题(linger_timer例外,本章不考虑此情况)。如果读事件 的timer set标志位为1,则从定时器中移除此事件。还要检查content-length头部,如果它的值小于或等于0,同样意味着可以直接返回 NGX一OK,表示成功丢弃了全部包体。 */ if (rev->timer_set) { ngx_del_timer(rev, NGX_FUNC_LINE); } if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { return NGX_OK; } size = r->header_in->last - r->header_in->pos; if (size || r->headers_in.chunked) { rc = ngx_http_discard_request_body_filter(r, r->header_in); if (rc != NGX_OK) { return rc; } if (r->headers_in.content_length_n == 0) { return NGX_OK; } } /* 在接收HTTP头部时,还是要检查是否凑巧已经接收到完整的包体(如果包体很小,那么这是非常可能发生的事),如果已经接收到完整的包 体,则直接返回NGX OK,表示丢弃包体成功,否则,说明需要多次的调度才能完成丢弃包体这一动作,此时把请求的read_event_handler 成员设置为ngx_http_discarded_request_body_handler方法。 */ rc = ngx_http_read_discarded_request_body(r); if (rc == NGX_OK) { /* 返回NGX一OK表示已经接收到完整的包体了,这时将请求的lingering_close延时关闭标志位设为0,表示不需要为了包体的接收而 延时关闭了,同时返回NGX―OK表示丢弃包体成功。 */ r->lingering_close = 0; return NGX_OK; } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } //返回非NGX_OK表示Nginx的事件框架触发事件需要多次调度才能完成丢弃包体这一动作 /* rc == NGX_AGAIN */ r->read_event_handler = ngx_http_discarded_request_body_handler; //下次读事件到来时通过ngx_http_request_handler来调用 if (ngx_handle_read_event(rev, 0, NGX_FUNC_LINE) != NGX_OK) { //调用ngx_handle_read_event方法把读事件添加到epoll中 handle为ngx_http_request_handler return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* 返回非NGX_ OK表示Nginx的事件框架触发事件需要多次调度才能完成丢弃包体这一动作,于是先把引用计数加1,防止这边还在丢弃包体, 而其他事件却已让请求意外销毁,引发严重错误。同时把ngx_http_request_t结构体的discard_body标志位置为1,表示正在丢弃包体,并 返回NGX―OK,当然,达时的NGX OK绝不表示已经成功地接收完包体,只是说明ngx_http_discard_request_body执行完毕而已。 */ r->count++; r->discard_body = 1; return NGX_OK; }
static void ngx_http_read_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, 0); return; } if (r->lingering_time) { timer = (ngx_msec_t) (r->lingering_time - ngx_time()); if (timer <= 0) { r->discard_body = 0; ngx_http_finalize_request(r, 0); return; } } else { timer = 0; } rc = ngx_http_read_discarded_request_body(r); if (rc == NGX_OK) { r->discard_body = 0; if (r->done) { ngx_http_finalize_request(r, 0); } return; } /* rc == NGX_AGAIN */ if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { c->error = 1; ngx_http_finalize_request(r, rc); 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); } }
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) { //定时器是在处理完请求,但请求体没有完全丢弃时挂载的 //在ngx_http_finalize_connection()函数中,如果检查到还有未丢弃的请求体时,nginx会添加一个读事件定时器 //超时则直接返回并断开连接 c->timedout = 1; c->error = 1; ngx_http_finalize_request(r, NGX_ERROR); return; } 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); } }
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; } 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; } } //设置读事件回调函数并挂在读事件 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 { //客户端没有一次发完请求体,在下一次读事件是,通过ngx_http_discarded_request_body_handler函数处理 r->count++; //可能在请求处理完后仍未发送完请求体,防止处理完请求后直接释放请求 r->discard_body = 1; } return NGX_OK; }