Пример #1
0
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;
    }
}
Пример #2
0
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;
}
Пример #4
0
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;
}