static ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_connection_t *c; ngx_output_chain_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; ngx_http_copy_filter_conf_t *conf; c = r->connection; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http copy filter: \"%V?%V\"", &r->uri, &r->args); ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module); conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ctx->sendfile = c->sendfile; ctx->need_in_memory = r->main_filter_need_in_memory || r->filter_need_in_memory; ctx->need_in_temp = r->filter_need_temporary; ctx->alignment = clcf->directio_alignment; ctx->pool = r->pool; ctx->bufs = conf->bufs; ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module; ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter; ctx->filter_ctx = r; #if (NGX_HAVE_FILE_AIO) if (ngx_file_aio && clcf->aio) { ctx->aio_handler = ngx_http_copy_aio_handler; #if (NGX_HAVE_AIO_SENDFILE) c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE); #endif } #endif r->request_output = 1; } #if (NGX_HAVE_FILE_AIO) ctx->aio = r->aio; #endif for ( ;; ) { rc = ngx_output_chain(ctx, in); if (ctx->in == NULL) { r->buffered &= ~NGX_HTTP_COPY_BUFFERED; } else { r->buffered |= NGX_HTTP_COPY_BUFFERED; } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); #if (NGX_HAVE_FILE_AIO && NGX_HAVE_AIO_SENDFILE) if (c->busy_sendfile) { ssize_t n; off_t offset; ngx_file_t *file; ngx_http_ephemeral_t *e; file = c->busy_sendfile->file; offset = c->busy_sendfile->file_pos; if (file->aio) { c->aio_sendfile = (offset != file->aio->last_offset); file->aio->last_offset = offset; if (c->aio_sendfile == 0) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "sendfile(%V) returned busy again", &file->name); } } c->busy_sendfile = NULL; e = (ngx_http_ephemeral_t *) &r->uri_start; n = ngx_file_aio_read(file, &e->aio_preload, 1, offset, r->pool); if (n > 0) { in = NULL; continue; } rc = n; if (file->aio) { file->aio->data = r; file->aio->handler = ngx_http_copy_aio_sendfile_event_handler; r->main->blocked++; r->aio = 1; } } #endif return rc; } }
static ngx_int_t ngx_http_upstream_send_request_body(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_int_t rc; ngx_chain_t *cl; ajp_msg_t *msg, local_msg; ngx_connection_t *c; ngx_http_ajp_ctx_t *a; ngx_http_ajp_loc_conf_t *alcf; c = u->peer.connection; a = ngx_http_get_module_ctx(r, ngx_http_ajp_module); alcf = ngx_http_get_module_loc_conf(r, ngx_http_ajp_module); if (a->state > ngx_http_ajp_st_request_body_data_sending) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "ngx_http_upstream_send_request_body: bad state(%d)", a->state); } cl = ajp_data_msg_send_body(r, alcf->max_ajp_data_packet_size_conf, &a->body); if (u->output.in == NULL && u->output.busy == NULL) { if (cl == NULL) { /* If there is no more data in the body (i.e. the servlet * container is trying to read past the end of the body), * the server will send back an "empty" packet, which is * a body packet with a payload length of 0. * (0x12,0x34,0x00,0x00) */ msg = ajp_msg_reuse(&local_msg); if (ajp_alloc_data_msg(r->pool, msg) != NGX_OK) { return NGX_ERROR; } ajp_data_msg_end(msg, 0); cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = msg->buf; cl->next = NULL; } } if (a->body) { a->state = ngx_http_ajp_st_request_body_data_sending; } else { a->state = ngx_http_ajp_st_request_send_all_done; } c->log->action = "sending request body again to upstream"; rc = ngx_output_chain(&u->output, cl); if (rc == NGX_ERROR) { return NGX_ERROR; } if (c->write->timer_set) { ngx_del_timer(c->write); } if (rc == NGX_AGAIN) { ngx_add_timer(c->write, u->conf->send_timeout); if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) { return NGX_ERROR; } u->write_event_handler = ngx_http_upstream_send_request_body_handler; return NGX_AGAIN; } /* rc == NGX_OK */ if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { if (ngx_tcp_push(c->fd) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, ngx_tcp_push_n " failed"); return NGX_ERROR; } c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; } ngx_add_timer(c->read, u->conf->read_timeout); if (ngx_handle_write_event(c->write, 0) != NGX_OK) { return NGX_ERROR; } u->write_event_handler = ngx_http_upstream_dummy_handler; return NGX_OK; }
static ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_connection_t *c; ngx_output_chain_ctx_t *ctx; ngx_http_copy_filter_conf_t *conf; c = r->connection; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "copy filter: \"%V?%V\"", &r->uri, &r->args); ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); if (ctx == NULL) { conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module); ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module); ctx->sendfile = c->sendfile; ctx->need_in_memory = r->main_filter_need_in_memory || r->filter_need_in_memory; ctx->need_in_temp = r->filter_need_temporary; ctx->pool = r->pool; ctx->bufs = conf->bufs; ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module; ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter; ctx->filter_ctx = r; r->request_output = 1; } rc = ngx_output_chain(ctx, in); if (!c->destroyed) { if (ctx->in == NULL) { r->buffered &= ~NGX_HTTP_COPY_BUFFERED; } else { r->buffered |= NGX_HTTP_COPY_BUFFERED; } if (r != r->main) { r->out = ctx->in; } #if (NGX_DEBUG) ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); #endif } return rc; }
static ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_connection_t *c; ngx_output_chain_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; ngx_http_copy_filter_conf_t *conf; c = r->connection; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http copy filter: \"%V?%V\"", &r->uri, &r->args); ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module); conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ctx->sendfile = c->sendfile; ctx->need_in_memory = r->main_filter_need_in_memory || r->filter_need_in_memory; ctx->need_in_temp = r->filter_need_temporary; ctx->alignment = clcf->directio_alignment; ctx->pool = r->pool; ctx->bufs = conf->bufs; ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module; ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_body_filter; ctx->filter_ctx = r; #if (NGX_HAVE_FILE_AIO) if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { ctx->aio_handler = ngx_http_copy_aio_handler; #if (NGX_HAVE_AIO_SENDFILE) ctx->aio_preload = ngx_http_copy_aio_sendfile_preload; #endif } #endif #if (NGX_THREADS) if (clcf->aio == NGX_HTTP_AIO_THREADS) { ctx->thread_handler = ngx_http_copy_thread_handler; } #endif if (in && in->buf && ngx_buf_size(in->buf)) { r->request_output = 1; } } #if (NGX_HAVE_FILE_AIO || NGX_THREADS) ctx->aio = r->aio; #endif rc = ngx_output_chain(ctx, in); if (ctx->in == NULL) { r->buffered &= ~NGX_HTTP_COPY_BUFFERED; } else { r->buffered |= NGX_HTTP_COPY_BUFFERED; } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); return rc; }
//in为需要发送的chain链,上面存储的是实际要发送的数据 static ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) { //实际上在接受完后端数据后,在想客户端发送包体部分的时候,会两次调用该函数,一次是ngx_event_pipe_write_to_downstream-> p->output_filter(), //另一次是ngx_http_upstream_finalize_request->ngx_http_send_special,可以参考上面的日志打印注释 ngx_int_t rc; ngx_connection_t *c; ngx_output_chain_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; ngx_http_copy_filter_conf_t *conf; int aio = r->aio; c = r->connection; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http copy filter: \"%V?%V\", r->aio:%d", &r->uri, &r->args, aio); ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module); conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /* 和后端的ngx_connection_t在ngx_event_connect_peer这里置为1,但在ngx_http_upstream_connect中c->sendfile &= r->connection->sendfile;, 和客户端浏览器的ngx_connextion_t的sendfile需要在ngx_http_update_location_config中判断,因此最终是由是否在configure的时候是否有加 sendfile选项来决定是置1还是置0 */ ctx->sendfile = c->sendfile; ctx->need_in_memory = r->main_filter_need_in_memory || r->filter_need_in_memory; ctx->need_in_temp = r->filter_need_temporary; ctx->alignment = clcf->directio_alignment; ctx->pool = r->pool; ctx->bufs = conf->bufs; // 默认值output_buffers 1 32768 ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module; ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_body_filter; ctx->filter_ctx = r; #if (NGX_HAVE_FILE_AIO) if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { //./configure的时候加上--with-file-aio并且配置文件中aio on的时候才有效 ctx->aio_handler = ngx_http_copy_aio_handler; #if (NGX_HAVE_AIO_SENDFILE) //只有freebsd系统才有效 auto/os/freebsd: have=NGX_HAVE_AIO_SENDFILE . auto/have ctx->aio_preload = ngx_http_copy_aio_sendfile_preload; #endif } #endif #if (NGX_THREADS) if (clcf->aio == NGX_HTTP_AIO_THREADS) { //ngx_output_chain_as_is中赋值给buf->file->thread_handler ctx->thread_handler = ngx_http_copy_thread_handler; } #endif //一般在调用filter函数的源头,会在in中指定需要发送的数据长度,可以参考ngx_http_cache_send if (in && in->buf && ngx_buf_size(in->buf)) { //判断in链中是否有数据 r->request_output = 1; } } #if (NGX_HAVE_FILE_AIO || NGX_THREADS) //实际上在接受完后端数据后,在想客户端发送包体部分的时候,会两次调用该函数,一次是ngx_event_pipe_write_to_downstream-> p->output_filter(), //另一次是ngx_http_upstream_finalize_request->ngx_http_send_special, //如果是aio方式,则第一次该值为0,但是第二次从ngx_http_send_special走到这里的时候已经在ngx_output_chain->ngx_file_aio_read->ngx_http_copy_aio_handler置1 //aio方式,当aio读事件完成,会通过ngx_http_copy_aio_event_handler->ngx_http_writer再次走到这里,这时候ngx_http_copy_aio_event_handler已经把r->aio置0 //可以参考上面的日志备注信息 ctx->aio = r->aio; #endif rc = ngx_output_chain(ctx, in);//aio on | thread_pool,这里肯定返回NGX_AGAIN,因为他们是由对应的epoll触发读取数据完毕,然后发送。 //sendfile或者内存数据这里返回NGX_OK,通过后面的ngx_linux_sendfile_chain->(ngx_linux_sendfile,ngx_writev)把数据发送出去 if (ctx->in == NULL) { r->buffered &= ~NGX_HTTP_COPY_BUFFERED; } else {//说明还有数据未发送到客户端r //ngx_http_finalize_request->ngx_http_set_write_handler->ngx_http_writer通过这种方式把未发送完毕的响应报文发送出去 r->buffered |= NGX_HTTP_COPY_BUFFERED; //说明ctx->in上还有未发送的数据,函数参数in中指向在ngx_output_chain中已经赋值给了ctx->in } ngx_int_t buffered = r->buffered; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, "http copy filter rc: %i, buffered:%i \"%V?%V\"", rc, buffered, &r->uri, &r->args); return rc; }