static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) { off_t rest; size_t size; ssize_t n; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl, out; ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; c = r->connection; rb = r->request_body; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read client request body"); for ( ;; ) { for ( ;; ) { if (rb->buf->last == rb->buf->end) { if (rb->buf->pos != rb->buf->last) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } else { /* update chains */ rc = ngx_http_request_body_filter(r, NULL); if (rc != NGX_OK) { return rc; } } if (rb->busy != NULL) { if (r->request_body_no_buffering) { if (c->read->timer_set) { ngx_del_timer(c->read); } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_AGAIN; } return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->buf->pos = rb->buf->start; rb->buf->last = rb->buf->start; } size = rb->buf->end - rb->buf->last; rest = rb->rest - (rb->buf->last - rb->buf->pos); if ((off_t) size > rest) { size = (size_t) rest; } n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body recv %z", n); if (n == NGX_AGAIN) { break; } if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client prematurely closed connection"); } if (n == 0 || n == NGX_ERROR) { c->error = 1; return NGX_HTTP_BAD_REQUEST; } rb->buf->last += n; r->request_length += n; if (n == rest) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } if (rb->rest == 0) { break; } if (rb->buf->last < rb->buf->end) { break; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body rest %O", rb->rest); if (rb->rest == 0) { break; } if (!c->read->ready) { if (r->request_body_no_buffering && rb->buf->pos != rb->buf->last) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_add_timer(c->read, clcf->client_body_timeout); if (ngx_handle_read_event(c->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_AGAIN; } } if (c->read->timer_set) { ngx_del_timer(c->read); } if (rb->temp_file || r->request_body_in_file_only) { /* save the last part */ if (ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (rb->temp_file->file.offset != 0) { cl = ngx_chain_get_free_buf(r->pool, &rb->free); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->in_file = 1; b->file_last = rb->temp_file->file.offset; b->file = &rb->temp_file->file; rb->bufs = cl; } else { rb->bufs = NULL; } } if (!r->request_body_no_buffering) { r->read_event_handler = ngx_http_block_reading; rb->post_handler(r); } return NGX_OK; }
static ngx_int_t ngx_http_do_read_non_buffered_client_request_body(ngx_http_request_t *r) { off_t rest; size_t size; ssize_t n; ngx_int_t rc; ngx_chain_t out; ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; ngx_http_request_body_non_buffered_t *nb; c = r->connection; rb = r->request_body; nb = rb->non_buffered; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read non buffered client request body"); for ( ;; ) { for ( ;; ) { if (rb->buf->last == rb->buf->end) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } rb->buf->pos = rb->buf->start; rb->buf->last = rb->buf->start; } if (rb->bufs) { /* copy to non_buffered buffers */ rc = ngx_http_copy_non_buffered_request_body(r); if (rc == NGX_DECLINED) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http no buffered client request body " "request_length: %O, rest: %uz, " "postpone_size: %O", r->request_length, rb->rest, nb->postpone_size); if (nb->postpone_size >= (off_t) clcf->client_body_postpone_size) { if (nb->buffered) { nb->flush = 1; goto read_ok; } } return NGX_DECLINED; } else if (rc == NGX_ERROR) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* update chains */ rc = ngx_http_request_body_filter(r, NULL); if (rc != NGX_OK) { return rc; } if (rb->busy != NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http no buffered client request body " "request_length: %O, rest: %uz, " "postpone_size: %O", r->request_length, rb->rest, nb->postpone_size); if (nb->postpone_size >= (off_t) clcf->client_body_postpone_size) { nb->flush = 1; if (nb->buffered) { goto read_ok; } return NGX_DECLINED; } } size = rb->buf->end - rb->buf->last; rest = rb->rest - (rb->buf->last - rb->buf->pos); if ((off_t) size > rest) { size = (size_t) rest; } n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client non buffered request body recv %z", n); if (n == NGX_AGAIN) { if (nb->postpone_size >= (off_t) clcf->client_body_postpone_size) { if (nb->buffered) { nb->flush = 1; goto read_ok; } } break; } if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client prematurely closed connection"); } if (n == 0 || n == NGX_ERROR) { c->error = 1; return NGX_HTTP_BAD_REQUEST; } rb->buf->last += n; r->request_length += n; if (n == rest) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } if (rb->rest == 0) { break; } if (rb->buf->last < rb->buf->end) { break; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client non buffered request body rest %O", rb->rest); if (rb->rest == 0) { break; } if (!c->read->ready) { ngx_add_timer(c->read, clcf->client_body_timeout); if (ngx_handle_read_event(c->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_AGAIN; } } if (c->read->timer_set) { ngx_del_timer(c->read); } /* save the last part */ rc = ngx_http_copy_non_buffered_request_body(r); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http no buffered client request body " "request_length: %O, rest: %uz, postpone_size: %O", r->request_length, rb->rest, nb->postpone_size); if (rc == NGX_DECLINED) { return NGX_DECLINED; } else if (rc == NGX_ERROR) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } read_ok: r->read_event_handler = ngx_http_block_reading; nb->buffered = 0; return NGX_OK; }
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { size_t preread; ssize_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out, *cl; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; r->main->count++; if (r != r->main || r->request_body || r->discard_body) { r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } if (ngx_http_test_expect(r) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } if (r->request_body_no_buffering) { r->request_body_in_file_only = 0; } rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } /* * set by ngx_pcalloc(): * * rb->bufs = NULL; * rb->buf = NULL; * rb->free = NULL; * rb->busy = NULL; * rb->chunked = NULL; */ rb->rest = -1; rb->post_handler = post_handler; r->request_body = rb; if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) { r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } preread = r->header_in->last - r->header_in->pos; if (preread) { /* there is the pre-read part of the request body */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http client request body preread %uz", preread); out.buf = r->header_in; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { goto done; } r->request_length += preread - (r->header_in->last - r->header_in->pos); if (!r->headers_in.chunked && rb->rest > 0 && rb->rest <= (off_t) (r->header_in->end - r->header_in->last)) { /* the whole request body may be placed in r->header_in */ b = ngx_calloc_buf(r->pool); if (b == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } b->temporary = 1; b->start = r->header_in->pos; b->pos = r->header_in->pos; b->last = r->header_in->last; b->end = r->header_in->end; rb->buf = b; r->read_event_handler = ngx_http_read_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; rc = ngx_http_do_read_client_request_body(r); goto done; } } else { /* set rb->rest */ if (ngx_http_request_body_filter(r, NULL) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } } if (rb->rest == 0) { /* the whole request body was pre-read */ if (r->request_body_in_file_only) { if (ngx_http_write_request_body(r) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } if (rb->temp_file->file.offset != 0) { cl = ngx_chain_get_free_buf(r->pool, &rb->free); if (cl == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->in_file = 1; b->file_last = rb->temp_file->file.offset; b->file = &rb->temp_file->file; rb->bufs = cl; } else { rb->bufs = NULL; } } r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } if (rb->rest < 0) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "negative request body rest"); rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); size = clcf->client_body_buffer_size; size += size >> 2; /* TODO: honor r->request_body_in_single_buf */ if (!r->headers_in.chunked && rb->rest < size) { size = (ssize_t) rb->rest; if (r->request_body_in_single_buf) { size += preread; } } else { size = clcf->client_body_buffer_size; } rb->buf = ngx_create_temp_buf(r->pool, size); if (rb->buf == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } r->read_event_handler = ngx_http_read_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; rc = ngx_http_do_read_client_request_body(r); done: if (r->request_body_no_buffering && (rc == NGX_OK || rc == NGX_AGAIN)) { if (rc == NGX_OK) { r->request_body_no_buffering = 0; } else { /* rc == NGX_AGAIN */ r->reading_body = 1; } r->read_event_handler = ngx_http_block_reading; post_handler(r); } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { r->main->count--; } return rc; }
static ngx_int_t ngx_http_read_non_buffered_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { size_t size; size_t preread; ngx_int_t rc; ngx_chain_t out; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; ngx_http_request_body_non_buffered_t *nb; rb = r->request_body; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); nb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_non_buffered_t)); if (nb == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } rb->non_buffered = nb; nb->last_out = &nb->bufs; nb->read_handler = ngx_http_do_read_non_buffered_client_request_body; nb->update_handler = ngx_http_request_body_update_chains; nb->tag = (ngx_buf_tag_t *) nb->read_handler; preread = r->header_in->last - r->header_in->pos; if (preread) { /* there is the pre-read part of the request body */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http client no buffered request body preread %uz", preread); out.buf = r->header_in; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { goto done; } r->request_length += preread - (r->header_in->last - r->header_in->pos); if (!r->headers_in.chunked && rb->rest > 0 && rb->rest <= (off_t) (r->header_in->end - r->header_in->last)) { /* the whole request body may be placed in r->header_in */ rb->buf = r->header_in; r->read_event_handler = ngx_http_read_non_buffered_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; rc = ngx_http_do_read_non_buffered_client_request_body(r); goto done; } } else { /* set rb->rest */ if (ngx_http_request_body_filter(r, NULL) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } } if (rb->rest == 0) { ngx_http_copy_non_buffered_request_body(r); /* the whole request body was pre-read */ rb->post_handler(r); return NGX_OK; } if (rb->rest < 0) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "negative request body rest"); rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); size = clcf->client_body_buffer_size; size += size >> 2; if (!r->headers_in.chunked && (rb->rest < (off_t) size)) { size = (ssize_t) rb->rest; if (r->request_body_in_single_buf) { size += preread; } } else { size = clcf->client_body_buffer_size; } rb->buf = ngx_create_temp_buf(r->pool, size); if (rb->buf == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } r->read_event_handler = ngx_http_read_non_buffered_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; nb->buffered = 1; nb->postpone_size = preread; rc = ngx_http_do_read_non_buffered_client_request_body(r); done: if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { r->main->count--; } if (rc == NGX_AGAIN) { if (nb->buffered) { r->read_event_handler = ngx_http_read_non_buffered_client_request_body_handler; } } else if (rc == NGX_OK || rc == NGX_DECLINED) { rb->post_handler(r); } return rc; }
// 要求nginx读取请求体,传入一个post_handler // 引用计数器增加,表示此请求还有关联的操作,不能直接销毁 // 所以post_handler里需要调用ngx_http_finalize_request来结束请求 ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { size_t preread; ssize_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; // 引用计数器增加,表示此请求还有关联的操作,不能直接销毁 r->main->count++; // 删除了原spdy的代码 // 子请求不与客户端直接通信,不会有请求体的读取 // 已经设置了discard_body标志,表示已经开始丢弃请求体 // request_body指针不空,表示已经开始读取请求体 if (r != r->main || r->request_body || r->discard_body) { r->request_body_no_buffering = 0; // 不需要再读取数据了,直接回调handler // 相当于触发写事件,继续之前中断的处理流程 post_handler(r); return NGX_OK; } #if (NGX_HTTP_V2) if (r->stream) { rc = ngx_http_v2_read_request_body(r, post_handler); goto done; } #endif // 如果要求不缓存请求体数据 // 那么请求体就不会存在磁盘文件里 // if (r->request_body_no_buffering) { // r->request_body_in_file_only = 0; // } if (ngx_http_test_expect(r) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } // 创建请求体数据结构体 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } /* * set by ngx_pcalloc(): * * rb->bufs = NULL; * rb->buf = NULL; * rb->free = NULL; * rb->busy = NULL; * rb->chunked = NULL; */ // -1表示未初始化 rb->rest = -1; // 当读取完毕后的回调函数 // 即ngx_http_read_client_request_body的第二个参数 rb->post_handler = post_handler; r->request_body = rb; // 数据长度不对,直接回调handler if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) { r->request_body_no_buffering = 0; // 不需要再读取数据了,直接回调handler // 相当于触发写事件,继续之前中断的处理流程 post_handler(r); return NGX_OK; } // 查看已经读取的数据,即缓冲区里头之后的数据 preread = r->header_in->last - r->header_in->pos; // 已经读取了部分body if (preread) { /* there is the pre-read part of the request body */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http client request body preread %uz", preread); // 链表的第一个节点指向r->header_in out.buf = r->header_in; out.next = NULL; // 分为chunked和确定长度两种 // 简单起见只研究确定长度,即ngx_http_request_body_length_filter // // 处理确定长度的请求体数据,参数是已经读取的数据链表 // 先看free里是否有空闲节点,有则直接使用 // 如果没有,就从内存池的空闲链表里获取 // 这里只是指针操作,没有内存拷贝 // 调用请求体过滤链表,对数据进行过滤处理 // 实际上是ngx_http_request_body_save_filter // 拷贝in链表里的buf到rb->bufs里,不是直接连接 // 最后把用完的ngx_chaint_t挂到free里供复用,提高效率 rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { goto done; } // 增加已经读取的数据长度,但因为 // preread = r->header_in->last - r->header_in->pos; // 实际上是没有增加 r->request_length += preread - (r->header_in->last - r->header_in->pos); // 不是chunked,有确定长度 // 还有剩余数据要读取 // header_in缓冲区里还有空间,足够容纳rest字节的数据 // 所以不需要再另外分配内存了,header_in缓冲区可以存下所有请求数据 // 特别优化处理 // 设置读事件handler为ngx_http_read_client_request_body_handler // 要求继续读取 if (!r->headers_in.chunked && rb->rest > 0 && rb->rest <= (off_t) (r->header_in->end - r->header_in->last)) { /* the whole request body may be placed in r->header_in */ // 创建一个缓冲区对象 b = ngx_calloc_buf(r->pool); if (b == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } // 指向header_in里的请求头后的所有空间 b->temporary = 1; b->start = r->header_in->pos; b->pos = r->header_in->pos; b->last = r->header_in->last; b->end = r->header_in->end; // 请求体使用此缓冲区 rb->buf = b; // 设置读事件handler为ngx_http_read_client_request_body_handler // 注意,读事件的handler实际上是ngx_http_request_handler // 但最终会调用r->read_event_handler // 读取请求体的handler // 首先检查超时,实际功能在ngx_http_do_read_client_request_body r->read_event_handler = ngx_http_read_client_request_body_handler; // 写事件阻塞 r->write_event_handler = ngx_http_request_empty_handler; // 在rb->buf里读取数据 // 如果已经读完了所有剩余数据,那么就挂到bufs指针,结束函数 rc = ngx_http_do_read_client_request_body(r); goto done; } // 这里表示rest==0,一次就已经全部读取了header+body // 不需要再关心读事件 // 走下面的if (rb->rest == 0) } else { /* set rb->rest */ // 没有读取body数据 // 分为chunked和确定长度两种 // 简单起见只研究确定长度,即ngx_http_request_body_length_filter // 因为参数是null,所以函数里只会设置rb->rest,即剩余要读取的字节数 if (ngx_http_request_body_filter(r, NULL) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } // 走下面的clcf = ngx_http_get_module_loc_conf } // rb->rest == 0 body已经读取完毕 // preread >= content length if (rb->rest == 0) { /* the whole request body was pre-read */ // body已经读取完毕,可以调用post_handler继续处理流程 r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } // 错误,负数body if (rb->rest < 0) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "negative request body rest"); rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } // 没读到body数据,但知道了确定的body长度 // 取模块的loc配置 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); // 查看body的缓冲区大小 size = clcf->client_body_buffer_size; // 增加1/4的长度 size += size >> 2; /* TODO: honor r->request_body_in_single_buf */ // 长度确定,且在size里可以容纳剩余字节数 if (!r->headers_in.chunked && rb->rest < size) { size = (ssize_t) rb->rest; // 要求body在一块缓冲区里,长度增加 if (r->request_body_in_single_buf) { size += preread; } } else { size = clcf->client_body_buffer_size; } // 内存池里分配一个缓冲区,大小为size rb->buf = ngx_create_temp_buf(r->pool, size); if (rb->buf == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } // 设置读事件handler为ngx_http_read_client_request_body_handler // 注意,读事件的handler实际上是ngx_http_request_handler // 但最终会调用r->read_event_handler // 读取请求体的handler // 首先检查超时,实际功能在ngx_http_do_read_client_request_body r->read_event_handler = ngx_http_read_client_request_body_handler; // 写事件阻塞 r->write_event_handler = ngx_http_request_empty_handler; // 在rb->buf里读取数据 // 如果已经读完了所有剩余数据,那么就挂到bufs指针,结束函数 rc = ngx_http_do_read_client_request_body(r); done: if (r->request_body_no_buffering && (rc == NGX_OK || rc == NGX_AGAIN)) { if (rc == NGX_OK) { r->request_body_no_buffering = 0; } else { /* rc == NGX_AGAIN */ r->reading_body = 1; } r->read_event_handler = ngx_http_block_reading; post_handler(r); } // 出错,减少引用计数 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { r->main->count--; } // 返回错误码 return rc; }
// 在rb->buf里读取数据 // 如果已经读完了所有剩余数据,那么就挂到bufs指针,结束函数 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) { off_t rest; size_t size; ssize_t n; ngx_int_t rc; ngx_chain_t out; ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; // 获取读事件相关的连接对象和请求对象 c = r->connection; rb = r->request_body; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read client request body"); for ( ;; ) { // 在rb->buf里读取数据 // 如果已经读完了所有剩余数据,那么就挂到bufs指针,结束函数 for ( ;; ) { // 检查请求体结构里的缓冲区 // 是否已经满了 if (rb->buf->last == rb->buf->end) { if (rb->buf->pos != rb->buf->last) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } else { /* update chains */ rc = ngx_http_request_body_filter(r, NULL); if (rc != NGX_OK) { return rc; } } if (rb->busy != NULL) { if (r->request_body_no_buffering) { if (c->read->timer_set) { ngx_del_timer(c->read); } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_AGAIN; } return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->buf->pos = rb->buf->start; rb->buf->last = rb->buf->start; } // if (rb->buf->last == rb->buf->end) // 缓冲区没有满,还可以存放数据 // 计算剩余空间的大小 size = rb->buf->end - rb->buf->last; // 减去缓冲区里已经读取的长度 rest = rb->rest - (rb->buf->last - rb->buf->pos); // 计算实际应该读取的长度,两者的小值 if ((off_t) size > rest) { size = (size_t) rest; } // 调用recv,读取数据,放入缓冲区 // <0 出错, =0 连接关闭, >0 接收到数据大小 n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body recv %z", n); // again,暂时无数据,中断内层循环 if (n == NGX_AGAIN) { break; } // 读到了0字节,即连接被客户端关闭,client abort if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client prematurely closed connection"); } // 读到了0字节,即连接被客户端关闭,client abort if (n == 0 || n == NGX_ERROR) { c->error = 1; return NGX_HTTP_BAD_REQUEST; } // n>0,读取了一些数据 // 调整buf的last指针,有效数据增加 rb->buf->last += n; // 总请求数据长度增加 r->request_length += n; // 已经读完了所有剩余数据 if (n == rest) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; // 分为chunked和确定长度两种 // 简单起见只研究确定长度,即ngx_http_request_body_length_filter // // 处理确定长度的请求体数据,参数是已经读取的数据链表 // 先看free里是否有空闲节点,有则直接使用 // 如果没有,就从内存池的空闲链表里获取 // 这里只是指针操作,没有内存拷贝 // 调用请求体过滤链表,对数据进行过滤处理 // 实际上是ngx_http_request_body_save_filter // 拷贝in链表里的buf到rb->bufs里,不是直接连接 // 最后把用完的ngx_chaint_t挂到free里供复用,提高效率 rc = ngx_http_request_body_filter(r, &out); // 出错则结束函数 if (rc != NGX_OK) { return rc; } } // ngx_http_request_body_filter里计算了rest剩余字节数 // 读取完毕则结束内层循环 if (rb->rest == 0) { break; } // 缓冲区没有用完,也结束内层循环 // 在后面调用ngx_http_request_body_filter处理读取到的数据 if (rb->buf->last < rb->buf->end) { break; } // 回到内层循环开头,即缓冲区已满 } // 内层for ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body rest %O", rb->rest); // ngx_http_request_body_filter里计算了rest剩余字节数 // 读取完毕则结束外层循环 if (rb->rest == 0) { break; } // 还有数据要读,且已经无数据可读 if (!c->read->ready) { if (r->request_body_no_buffering && rb->buf->pos != rb->buf->last) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; // 分为chunked和确定长度两种 // 简单起见只研究确定长度,即ngx_http_request_body_length_filter // // 处理确定长度的请求体数据,参数是已经读取的数据链表 // 先看free里是否有空闲节点,有则直接使用 // 如果没有,就从内存池的空闲链表里获取 // 这里只是指针操作,没有内存拷贝 // 调用请求体过滤链表,对数据进行过滤处理 // 实际上是ngx_http_request_body_save_filter // 拷贝in链表里的buf到rb->bufs里,不是直接连接 // 最后把用完的ngx_chaint_t挂到free里供复用,提高效率 rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } // 读取body的超时时间 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_add_timer(c->read, clcf->client_body_timeout); // 读事件加入epoll,可读会调用ngx_http_read_client_request_body_handler // 即再次进入本函数 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_AGAIN; } } // 外层for // 只有rest==0,即读取完毕才会走到这里 if (c->read->timer_set) { ngx_del_timer(c->read); } // 要求缓存请求体 if (!r->request_body_no_buffering) { r->read_event_handler = ngx_http_block_reading; // body已经读取完毕,可以调用post_handler继续处理流程 rb->post_handler(r); } return NGX_OK; }
//只有在连接后端服务器的时候才会读取客户端请求包体,见ngx_http_xxx_handler(proxy fastcgi等) //post_handler在ngx_http_do_read_client_request_body接收完所有包体后执行,或者在本函数能读取完包体后也会执行 //post_handler方法被回调时,务必调用类似ngx_http_finalize_request的方法去结束请求,否则引用计数会始终无法清零,从而导致请求无法释放。 ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { size_t preread; ssize_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out, *cl; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; /* 首先把该请求对应的原始请求的引用计数加1。这同时是在要求每一个HTTP模块在传入的post_handler方法被回调时,务必调用类似 ngx_http_finalize_request的方法去结束请求,否则引用计数会始终无法清零,从而导致请求无法释放。 */ r->main->count++; #if (NGX_HTTP_SPDY) if (r->spdy_stream && r == r->main) { r->request_body_no_buffering = 0; rc = ngx_http_spdy_read_request_body(r, post_handler); goto done; } #endif /* 检查请求ngx_http_request_t结构体中的request_body成员,如果它已经被分配过了,证明已经读取过HTTP包体了,不需要再次读取一遍; 再检查请求ngx_http_request_t结构体中的discard_body标志位,如果discard_body为1,则证明曾经执行过丢弃包体的方法,现在包体正在被丢弃中。 只有这两个条件都不满足,才说明真正需要接收HTTP包体。 */ if (r != r->main || r->request_body || r->discard_body) { r->request_body_no_buffering = 0; post_handler(r); //直接执行各HTTP模块提供的post_handler回调方法 return NGX_OK; } if (ngx_http_test_expect(r) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } if (r->request_body_no_buffering) { //如果不缓存包体,request_body_no_buffering和request_body_in_file_only是互斥的 r->request_body_in_file_only = 0; //设置为不缓存包体,则就不能把包体写道文件中 } /* 分配请求的ngx_http_request_t结构体中的request_body成员(之前request_body是NULL空指针),准备接收包体。 */ rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } /* * set by ngx_pcalloc(): * * rb->bufs = NULL; * rb->buf = NULL; * rb->free = NULL; * rb->busy = NULL; * rb->chunked = NULL; */ rb->rest = -1; rb->post_handler = post_handler; r->request_body = rb; //把创建的ngx_http_request_body_t空间赋值给request_body /* 检查请求的content-length头部,如果指定了包体长度的content-length字段小于或等于0,当然不用继续接收包体: 如果content-length大于0,则意味着继续执行,但HTTP模块定义的post_handler方法不会知道在哪一次事件的触发中会被回调, 所以先把它设置到request_body结构体的post_handler成员中。 */ if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) { r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } /* * 接收HTTP头部的流程中,是有可能接收到HTTP包体的。 * 首先我们需要检查在header_in缓冲区中已经接收到的包体长度,确定其是否大于或者等于content-length头部指定的长度, * 如果大干或等于则说明已经接收到完整的包体 */ preread = r->header_in->last - r->header_in->pos; if (preread) { //注意在ngx_http_wait_request_handler中第一次读的时候默认是读1024字节,有可能ngx_http_wait_request_handler已经把包体读了 /* there is the pre-read part of the request body */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http client request body preread %uz", preread); out.buf = r->header_in;// out.next = NULL; //把最新读取到的buf数据添加到r->request_body->bufs中,并且让free指向该bufs中所有数据中已经解析了的数据节点信息(重复利用ngx_buf_t) //busy链表中的ngx_buf_t节点指向bufs中所有数据中还没有解析完毕的数据 rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { goto done; } r->request_length += preread - (r->header_in->last - r->header_in->pos); /* 当上述条件不满足时,再检查header_in缓冲区里的剩余空闲空间是否可以存放下全部的包体(content-length头部指定),如果可以,就不用分配新的包体缓冲区浪费内存了 */ if (!r->headers_in.chunked && rb->rest > 0 //还需要读取rb->rest才能保证包体读完 && rb->rest <= (off_t) (r->header_in->end - r->header_in->last)) //判断header_in指向的剩余未用空间是否足够存取剩余的rest字节数据 { /* the whole request body may be placed in r->header_in */ //header_in中剩余的未用空间足够,例如还差rest = 1000字节才能读取完包体,但是header_in中剩余空间end - last超过1000,则不需要从新开辟空间 //直接使用header_in剩余空间,开辟新的ngx_buf_t空间,使用新的ngx_buf_t中的各个指针指向header_in中剩余未用空间,用来继续读取 b = ngx_calloc_buf(r->pool); if (b == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } b->temporary = 1; b->start = r->header_in->pos; b->pos = r->header_in->pos; b->last = r->header_in->last; b->end = r->header_in->end; rb->buf = b; r->read_event_handler = ngx_http_read_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; rc = ngx_http_do_read_client_request_body(r); goto done; } } else { /* set rb->rest */ if (ngx_http_request_body_filter(r, NULL) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } } //包体一次读取完毕 if (rb->rest == 0) { /* the whole request body was pre-read */ //如果配置"client_body_in_file_only" on | clean 表示包体存储在磁盘文件中 if (r->request_body_in_file_only) { if (ngx_http_write_request_body(r) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } if (rb->temp_file->file.offset != 0) { cl = ngx_chain_get_free_buf(r->pool, &rb->free); if (cl == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->in_file = 1; b->file_last = rb->temp_file->file.offset; b->file = &rb->temp_file->file; rb->bufs = cl; //如果包体存入临时文件中,则读取包体完成后,bufs指向的ngx_chain_t中的各个指针指向文件中的相关偏移 } else { rb->bufs = NULL; } } r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } //包体一次没有读取完毕 if (rb->rest < 0) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "negative request body rest"); rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); size = clcf->client_body_buffer_size; size += size >> 2; //实际上就是四分之五5/4个client_body_buffer_size /* TODO: honor r->request_body_in_single_buf */ //走到这里之前至少在ngx_http_wait_request_handler函数中读取过一次,也就是读取头部的时候,可能会读取一部分包体,在读取头部的时候 //读取的最大报文长度为client_header_buffer_size,所以包体有可能在那里读取后处理了头部行后,会走到本函数处理包体,这时候可能包体没有读完 if (!r->headers_in.chunked && rb->rest < size) { size = (ssize_t) rb->rest; if (r->request_body_in_single_buf) { //需要缓存到同一个buf中,那么开辟的空间就必须一次分配完,这样可以存储后面所有的。 size += preread; //如果是把读取的网络数据存到同一个single buffer中,则本次读到preread字节,但是还有size字节没读,所以需要相加,表示一共需要这么多空间, } } else { size = clcf->client_body_buffer_size; //如果不是缓存到同一个buf,则一次最多开辟这么多空间,这样可能需要多个buf才能读取完 } /* 说明确实需要分配用于接收包体的缓冲区了。缓冲区长度由nginx.conf丈件中的client_body_buffer_size配置项指定,缓冲区就在ngx_http_request_body_t 结构体的buf成员中存放着,同时,bufs和to_ write这两个缓冲区链表首部也指向该buf。 */ rb->buf = ngx_create_temp_buf(r->pool, size); //这个是为下次读取准备的 if (rb->buf == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } /* 设置请求ngx_http_request_t结构体的read_ event_ handler成员为上面介绍过的ngx_http_read_client_request_body_handler方法, 它意味着如果epoll再次检测到可读事件或者读事件的定时器超时,HTTP框架将调用ngx_http_read_client_request_body_handler方法处理 */ r->read_event_handler = ngx_http_read_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; /* 调用ngx_http_do_read_client_request_body方法接收包体。该方法的意义在于把客户端与Nginx之间TCP连接上套接字缓冲区中的当前字符流全 部读出来,并判断是否需要写入文件,以及是否接收到全部的包体,同时在接收到完整的包体后激活post_handler回调方法 */ rc = ngx_http_do_read_client_request_body(r);//这里面添加ngx_handle_read_event的时候,对应的handler为ngx_http_read_client_request_body_handler done: if (r->request_body_no_buffering && (rc == NGX_OK || rc == NGX_AGAIN)) { if (rc == NGX_OK) { r->request_body_no_buffering = 0; } else { /* rc == NGX_AGAIN */ r->reading_body = 1; } r->read_event_handler = ngx_http_block_reading; post_handler(r); } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {//如果返回出错 r->main->count--; //该函数处理结束后-1,因为该函数开始处理的时候有+1 } return rc; }
/* 调用ngx_http_do_read_client_request_body方法接收包体。该方法的意义在于把客户端与Nginx之间TCP连接上套接字缓冲区中的当前字符流全 部读出来,并判断是否需要写入文件,以及是否接收到全部的包体,同时在接收到完整的包体后激活post_handler回调方法 负责具体的读取包体工作,该函数会在for循环中会反复读直到包体读取完毕,如果内核已经没有数据并且包体还没有读完,则添加读事件,并退出循环,这样HTTP模块还能继续作用其他功能,避免阻塞 读取的时候一个buf装满后,会把buf中存储的数据写到临时文件中(不管有没有配置request_body_in_file_only),然后继续使用该buf读取数据, 存储数据的内存分配地方有两个:1.在读取报文头部的时候ngx_http_wait_request_handler 2.如果在1中读到的内容里面不包括完整包体,则需要在 ngx_http_read_client_request_body中会重新分配内存读取,触发再次读取的地方未ngx_http_read_client_request_body中为读取到完整包体的时候添加的ngx_handle_read_event */ static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) { off_t rest; size_t size; ssize_t n; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl, out; ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; c = r->connection; rb = r->request_body; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read client request body"); for ( ;; ) { for ( ;; ) { /* 首先检查请求的request_body成员中的buf缓冲区,如果缓冲区还有空闲的空间,则跳过该if{}去读取内核中套接字缓冲区里的TCP字符流; 如果缓冲区已经写满,则调用ngx_http_write_request_body方法把缓冲区中的字符流写入文件。不管有没有配置request_body_in_file_only置1 */ if (rb->buf->last == rb->buf->end) { if (rb->buf->pos != rb->buf->last) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; //这里肯定会调用ngx_http_request_body_save_filter->ngx_http_write_request_body写该buf中的内容到临时文件,因为该buf指向的空间 //会重复利用来读取包体内容 rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } else { /* update chains */ rc = ngx_http_request_body_filter(r, NULL); if (rc != NGX_OK) { return rc; } } if (rb->busy != NULL) { //如果头部行中的content-length:LEN中的len长度表示后面的包体大小,如果后面的包体数据长度实际比头部中的LEN大,则会走这里, if (r->request_body_no_buffering) { if (c->read->timer_set) { ngx_del_timer(c->read, NGX_FUNC_LINE); } if (ngx_handle_read_event(c->read, 0, NGX_FUNC_LINE) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_AGAIN; } return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* 为什么能下次还可以直接利用rb->buf空间来读取数据呢? 当一个rb->buf填满后就会通过ngx_http_write_request_body把bufs链表中的所有ngx_chain_t->ngx_buf_t中指向的数据写入到临时文件,因此rb->buf中的内存就可以再次使用了 */ //只需要把缓冲区ngx_buf_t结构体的last指针指向start指针,缓冲区即可复用。 rb->buf->pos = rb->buf->start; rb->buf->last = rb->buf->start; } size = rb->buf->end - rb->buf->last; //buf中还剩余这么多空间 rest = rb->rest - (rb->buf->last - rb->buf->pos); //还有多少字节包体没有读取 if ((off_t) size > rest) { //说明空间够用来存储剩余的没有读取的字节数 size = (size_t) rest; } //负责具体的读取包体工作,该函数会在for循环中会反复读直到包体读取完毕,如果内核已经没有数据并且包体还没有读完,则添加读事件,并退出循环,这样HTTP模块还能继续作用其他功能,避免阻塞 //调用封装了recv的方法从套接字缓冲区中读取包体到缓冲区中。 n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body recv %z", n); if (n == NGX_AGAIN) { break; } if (n == 0) {//如果recv方法返回错误,或者客户端主动关闭了连接 ngx_log_error(NGX_LOG_INFO, c->log, 0, "client prematurely closed connection"); } if (n == 0 || n == NGX_ERROR) {//如果recv方法返回错误,或者客户端主动关闭了连接 c->error = 1; return NGX_HTTP_BAD_REQUEST; } /* 根据接收到的TCP流长度,修改缓冲区参数。例如,把缓冲区ngx_buf_t结构体的last揩针加上接收到的长度,同时更新request_body结 构体中表示待接收的剩余包体长度的rest成员、更新ngx_http_request_t结构体中表示已接收请求长度的request_length成员。 */ //从这里可以看出在多次读取包体的时候,需要先把前面开辟空间buf中没有填充的部分填满,如果buf填满了,则重新利用该buf读取数据 //之前读取到填满buf中的数据取出来存放到临时文件中,参考前面的if (rb->buf->last == rb->buf->end) rb->buf->last += n; r->request_length += n; if (n == rest) {//根据rest成员检查是否接收到完整的包体 /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } if (rb->rest == 0) { break; //所有包体读取处理完毕,则退出for } if (rb->buf->last < rb->buf->end) { break; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body rest %O", rb->rest); if (rb->rest == 0) { break; } /* 如果当前已经没有可读的字符流,同时还没有接收到完整的包体,则说明需要把读事件添加到事件模块,等待可读事件发生时,事件框架可以再次 调度到这个方法接收包体。这一步是调用ngx_add_timer方法将读事件添加到定时器中,超时时间以nginx.conf文件中的client_body_timeout配置项参数为准。 */ //说明前面的 n = c->recv(c, rb->buf->last, size);返回的是NGX_AGAIN,所以在recv中会把ready置0 if (!c->read->ready) { if (r->request_body_no_buffering && rb->buf->pos != rb->buf->last) { /* pass buffer to request body filter chain */ out.buf = rb->buf; out.next = NULL; rc = ngx_http_request_body_filter(r, &out); if (rc != NGX_OK) { return rc; } } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); //当读取到完整的包体后,会删除该定时器,见后面的ngx_del_timer(c->read); ngx_add_timer(c->read, clcf->client_body_timeout, NGX_FUNC_LINE);//handle应该是ngx_http_request_handler /* 这个请求连接上的读事件触发时的回调方法ngx_http_request_handler,从而会调用read_event_handler方法(ngx_http_read_client_request_body_handler) */ if (ngx_handle_read_event(c->read, 0, NGX_FUNC_LINE) != NGX_OK) { //handle应该是ngx_http_request_handler,通过这里触发再次读取包体 return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_AGAIN; //把控制器交给HTTP框架,由框架感知读事件,当读事件发生,也就是数据到来,继续读取包体 } } //只有包体读取完毕,才会从上面的for()循环中退出 /* 表明已经接收到完整的包体,需要做一些收尾工作了。首先不需要检查是否接收HTTP包体超时了,要把读事件从定时器中取出,防止不必要的定时器触发。 这一步会检查读事件的timer set标志位,如果为1,则调用ngx_del_timer方法把读事件从定时器中移除。 */ if (c->read->timer_set) { ngx_del_timer(c->read, NGX_FUNC_LINE); } //如果缓冲区中还有未写入文件的内容,调用ngx_http_write_request_body方法把最后的包体内容也写入文件。 if (rb->temp_file || r->request_body_in_file_only) { //只要之前的内存有写入文件,那么剩余的部分也要写入文件 /* save the last part */ if (ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (rb->temp_file->file.offset != 0) { cl = ngx_chain_get_free_buf(r->pool, &rb->free); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->in_file = 1; b->file_last = rb->temp_file->file.offset; b->file = &rb->temp_file->file; rb->bufs = cl; //读取客户包体即使是存入临时文件中,当所有包体读取完毕后(ngx_http_do_read_client_request_body),还是会让r->request_body->bufs指向文件中的相关偏移内存地址 } else { rb->bufs = NULL; } } /* 在之前read_event_handler成员设置为ngx_http_read_client_request_body_handler方法,现在既然已经接收到完整的包体了,就会把 read_event_handler设为ngx_http_block_reading方法,表示连接上再有读事件将不做任何处理。 */ if (!r->request_body_no_buffering) { r->read_event_handler = ngx_http_block_reading; rb->post_handler(r); //执行ngx_http_read_client_request_body的第二个参数 } return NGX_OK; }