static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) { size_t size; ngx_int_t rc; ngx_http_request_body_t *rb; if (r->headers_in.chunked) { rb = r->request_body; if (rb == NULL) { rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); if (rb->chunked == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->request_body = rb; } for ( ;; ) { rc = ngx_http_parse_chunked(r, b, rb->chunked); if (rc == NGX_OK) { /* a chunk has been parsed successfully */ size = b->last - b->pos; if ((off_t) size > rb->chunked->size) { b->pos += (size_t) rb->chunked->size; rb->chunked->size = 0; } else { rb->chunked->size -= size; b->pos = b->last; } continue; } if (rc == NGX_DONE) { /* a whole response has been parsed successfully */ r->headers_in.content_length_n = 0; break; } if (rc == NGX_AGAIN) { /* set amount of data we want to see next time */ r->headers_in.content_length_n = rb->chunked->length; break; } /* invalid */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid chunked body"); return NGX_HTTP_BAD_REQUEST; } } else { size = b->last - b->pos; if ((off_t) size > r->headers_in.content_length_n) { b->pos += (size_t) r->headers_in.content_length_n; r->headers_in.content_length_n = 0; } else { b->pos = b->last; r->headers_in.content_length_n -= size; } } return NGX_OK; }
static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) { size_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl, *out, *tl, **ll; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; rb = r->request_body; if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http request body chunked filter"); rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); if (rb->chunked == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_in.content_length_n = 0; rb->rest = 3; } out = NULL; ll = &out; for (cl = in; cl; cl = cl->next) { for ( ;; ) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body chunked buf " "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O", cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked); if (rc == NGX_OK) { /* a chunk has been parsed successfully */ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->client_max_body_size && clcf->client_max_body_size - r->headers_in.content_length_n < rb->chunked->size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client intended to send too large chunked " "body: %O+%O bytes", r->headers_in.content_length_n, rb->chunked->size); r->lingering_close = 1; return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; } tl = ngx_chain_get_free_buf(r->pool, &rb->free); if (tl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = tl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->temporary = 1; b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body; b->start = cl->buf->pos; b->pos = cl->buf->pos; b->last = cl->buf->last; b->end = cl->buf->end; b->flush = r->request_body_no_buffering; *ll = tl; ll = &tl->next; size = cl->buf->last - cl->buf->pos; if ((off_t) size > rb->chunked->size) { cl->buf->pos += (size_t) rb->chunked->size; r->headers_in.content_length_n += rb->chunked->size; rb->chunked->size = 0; } else { rb->chunked->size -= size; r->headers_in.content_length_n += size; cl->buf->pos = cl->buf->last; } b->last = cl->buf->pos; continue; } if (rc == NGX_DONE) { /* a whole response has been parsed successfully */ rb->rest = 0; tl = ngx_chain_get_free_buf(r->pool, &rb->free); if (tl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = tl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->last_buf = 1; *ll = tl; ll = &tl->next; break; } if (rc == NGX_AGAIN) { /* set rb->rest, amount of data we want to see next time */ rb->rest = rb->chunked->length; break; } /* invalid */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid chunked body"); return NGX_HTTP_BAD_REQUEST; } } rc = ngx_http_top_request_body_filter(r, out); ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, (ngx_buf_tag_t) &ngx_http_read_client_request_body); return rc; }
// 检查请求结构体里的缓冲区数据,丢弃 // 有content_length_n指定确切长度,那么只接收,不处理,移动缓冲区指针 // chunked数据需要解析数据 // content_length_n==0表示数据已经全部读完 // 就已经完成了丢弃任务,否则就要加入epoll读事件继续读 static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) { size_t size; ngx_int_t rc; ngx_http_request_body_t *rb; // chunked数据长度不确定,需要特殊处理 if (r->headers_in.chunked) { // 获取专门的请求体数据结构 rb = r->request_body; // 如果还没有就创建 if (rb == NULL) { rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); if (rb->chunked == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->request_body = rb; } for ( ;; ) { // in ngx_http_parse.c // 解析chunked数据 rc = ngx_http_parse_chunked(r, b, rb->chunked); // ok表示一个chunk解析完成 if (rc == NGX_OK) { /* a chunk has been parsed successfully */ // 计算实际数据的长度 size = b->last - b->pos; // 实际长度大于chunk长度,可能有下一个的数据已经读了 if ((off_t) size > rb->chunked->size) { // 移动缓冲区指针,消费读取的chunk数据 b->pos += (size_t) rb->chunked->size; // chunk长度归0 rb->chunked->size = 0; } else { // chunk数据不完整,没读取完 // 减去已经读取的长度,剩下的就是还要读取的长度 rb->chunked->size -= size; b->pos = b->last; } // 继续解析读取的数据,直至非ok continue; } // done所有的chunk数据均读取完毕 // content_length_n置0,表示无数据,丢弃成功 if (rc == NGX_DONE) { /* a whole response has been parsed successfully */ r->headers_in.content_length_n = 0; break; } // again表示数据不完整,需要继续读取 if (rc == NGX_AGAIN) { /* set amount of data we want to see next time */ r->headers_in.content_length_n = rb->chunked->length; break; } /* invalid */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid chunked body"); return NGX_HTTP_BAD_REQUEST; } } else { // 不是chunked,请求体数据有确定的长度 // 检查缓冲区里头之后的数据,即收到的请求体数据 size = b->last - b->pos; // 收到的数据大于头里的content_length_n if ((off_t) size > r->headers_in.content_length_n) { // 缓冲区指针移动,即消费content_length_n的数据 b->pos += (size_t) r->headers_in.content_length_n; // content_length_n置0,表示无数据,丢弃成功 r->headers_in.content_length_n = 0; } else { // 收到的数据不足,即还没有收完content_length_n字节数 // 如果正好收完,也是在这里处理 // 指针直接移动到最后,即消费所有收到的数据 b->pos = b->last; // 头里的content_length_n减少,即还将要收多少数据 // 如果正好收完,那么值就是0,丢弃成功 r->headers_in.content_length_n -= size; } } return NGX_OK; }