ngx_int_t ngx_http_do_read_non_buffered_client_request_body(ngx_http_request_t *r) { size_t size; ssize_t n; ngx_buf_t buf; ngx_int_t rc; ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; c = r->connection; rb = r->request_body; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read no buffered client request body"); for ( ;; ) { for ( ;; ) { if ((rb->buf == NULL) || (rb->buf->end == rb->buf->last)) { rc = ngx_http_request_body_get_buf(r); if (rc == NGX_ERROR) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } else if (rc == NGX_DECLINED) { /* The buffers are full */ return NGX_DECLINED; } } size = rb->buf->end - rb->buf->last; if ((off_t) size > rb->rest) { size = (size_t) rb->rest; } n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http no buffered 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; } if (rb->last) { *rb->last_out = rb->last; rb->last_out = &rb->last->next; rb->last = NULL; } buf.start = rb->buf->last; buf.pos = rb->buf->last; buf.last = buf.start + n; buf.end = buf.last; rc = ngx_http_top_input_body_filter(r, &buf); if (rc != NGX_OK) { return rc; } rb->buf->last += n; rb->rest -= n; r->request_length += n; rb->postpone_size += n; 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, rb->postpone_size); if (rb->rest == 0) { rb->buf->last_buf = 1; goto read_ok; } if (rb->postpone_size >= (off_t) clcf->client_body_postpone_size) { rb->flush = 1; if (rb->buffered) { goto read_ok; } return NGX_DECLINED; } } 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; } } read_ok: /* * All the request body is read or the postpone_size is larger than the * client_body_postpone_size, we should call the post_handler if this * request is still buffered. */ if (c->read->timer_set) { ngx_del_timer(c->read); } r->read_event_handler = ngx_http_block_reading; rb->buffered = 0; return NGX_OK; }
/* * TODO: This the simplest way to add this patch. But it introduces * memory copy. Change me. */ static ngx_int_t ngx_http_copy_non_buffered_request_body(ngx_http_request_t *r) { ssize_t size; ngx_int_t rc; ngx_chain_t *cl; ngx_http_request_body_t *rb; ngx_http_request_body_non_buffered_t *nb; rb = r->request_body; nb = rb->non_buffered; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy client request body, non buffered bufs %p", rb->bufs); if (rb->bufs == NULL) { return NGX_OK; } #if (NGX_DEBUG) for (cl = rb->bufs; cl; cl = cl->next) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http rb->bufs before t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %z", 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); } #endif for (cl = rb->bufs; cl;) { if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { cl = cl->next; continue; } if ((nb->buf == NULL) || (nb->buf->end == nb->buf->last)) { rc = ngx_http_request_body_get_buf(r); if (rc == NGX_ERROR) { return NGX_ERROR; } else if (rc == NGX_DECLINED) { /* The buffers are full */ return NGX_DECLINED; } } size = nb->buf->end - nb->buf->last; if (size > ngx_buf_size(cl->buf)) { size = ngx_buf_size(cl->buf); } if (size) { ngx_memcpy(nb->buf->last, cl->buf->pos, size); cl->buf->pos += size; nb->buf->last += size; nb->postpone_size += size; } if (cl->buf->pos == cl->buf->last) { /* TODO: honor other tags */ nb->buf->last_buf = cl->buf->last_buf; cl = cl->next; } } #if (NGX_DEBUG) for (cl = nb->bufs; cl; cl = cl->next) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http nb->bufs t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %z", 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); } for (cl = rb->bufs; cl; cl = cl->next) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http rb->bufs t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %z", 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); } #endif rb->bufs = NULL; return NGX_OK; }