1. ngx_http_top_body_filter

该链表用于构造响应消息的响应正文.

大致有以下模块在该链表中插入了自己的函数:

  1. ngx_http_range_filter_module: ngx_http_range_body_filter
  2. ngx_http_copy_filter_module: ngx_http_copy_filter
  3. ngx_http_headers_filter_module: ngx_http_trailers_filter
  4. ngx_http_charset_filter_module: ngx_http_charset_body_filter
  5. ngx_http_ssi_filter_module: ngx_http_ssi_body_filter
  6. ngx_http_postpone_filter_module: ngx_http_postpone_filter
  7. ngx_http_gzip_filter_module:ngx_http_gzip_body_filter
  8. ngx_http_chunked_filter_module:ngx_http_chunked_body_filter
  9. ngx_http_write_filter_module:ngx_http_write_filter

1.1 ngx_http_range_body_filter

static ngx_int_t
ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_range_filter_ctx_t *ctx; if (in == NULL) {
return ngx_http_next_body_filter(r, in);
} /* 获取 ngx_http_range_body_filter_module 模块的上下文结构体 */
ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module); /* 若为 NULL 则执行链表的下一个函数 */
if (ctx == NULL) {
return ngx_http_next_body_filter(r, in);
} if (ctx->ranges.nelts == 1) {
return ngx_http_range_singlepart_body(r, ctx, in);
} /*
* multipart ranges are supported only if whole body is in a single buffer
*/ if (ngx_buf_special(in->buf)) {
return ngx_http_next_body_filter(r, in);
} if (ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) {
return NGX_ERROR;
} return ngx_http_range_multipart_body(r, ctx, in);
}

1.2 ngx_http_copy_filter

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); /* 获取 ngx_http_copy_filter_module 模块的上下文结构体 */
ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); /* 若为 NULL,则分配 */
if (ctx == NULL) {
ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
} /* 将该 ngx_http_copy_filter_module 模块的上下文结构体
* ngx_output_chain_ctx_t 存放到 ngx_http_request_t 结构体
* 中的 ctx 数组中,下标为单前模块的 ctx_index */
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); /* 标志位,为 1 表示使用 sendfile 系统调用发送文件 */
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;
}

1.2.1 ngx_output_chain

ngx_int_t
ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
{
off_t bsize;
ngx_int_t rc, last;
ngx_chain_t *cl, *out, **last_out; if (ctx->in == NULL && ctx->busy == NULL
#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
&& !ctx->aio
#endif
)
{
/*
* the short path for the case when the ctx->in and ctx->busy chains
* are empty, the incoming chain is empty too or has the single buf
* that does not require the copy
*/ if (in == NULL) {
return ctx->output_filter(ctx->filter_ctx, in);
} if (in->next == NULL
#if (NGX_SENDFILE_LIMIT)
&& !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
#endif
&& ngx_output_chain_as_is(ctx, in->buf))
{
return ctx->output_filter(ctx->filter_ctx, in);
}
} /* add the incoming buf to the chain ctx->in */ if (in) {
if (ngx_output_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
return NGX_ERROR;
}
} out = NULL;
last_out = &out;
last = NGX_NONE; for ( ;; ) { #if (NGX_HAVE_FILE_AIO || NGX_THREADS)
if (ctx->aio) {
return NGX_AGAIN;
}
#endif while (ctx->in) { /*
* cycle while there are the ctx->in bufs
* and there are the free output bufs to copy in
*/ bsize = ngx_buf_size(ctx->in->buf); if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
"zero size buf in output "
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
ctx->in->buf->temporary,
ctx->in->buf->recycled,
ctx->in->buf->in_file,
ctx->in->buf->start,
ctx->in->buf->pos,
ctx->in->buf->last,
ctx->in->buf->file,
ctx->in->buf->file_pos,
ctx->in->buf->file_last); ngx_debug_point(); ctx->in = ctx->in->next; continue;
} if (ngx_output_chain_as_is(ctx, ctx->in->buf)) { /* move the chain link to the output chain */ cl = ctx->in;
ctx->in = cl->next; *last_out = cl;
last_out = &cl->next;
cl->next = NULL; continue;
} if (ctx->buf == NULL) { rc = ngx_output_chain_align_file_buf(ctx, bsize); if (rc == NGX_ERROR) {
return NGX_ERROR;
} if (rc != NGX_OK) { if (ctx->free) { /* get the free buf */ cl = ctx->free;
ctx->buf = cl->buf;
ctx->free = cl->next; ngx_free_chain(ctx->pool, cl); } else if (out || ctx->allocated == ctx->bufs.num) { break; } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
return NGX_ERROR;
}
}
} rc = ngx_output_chain_copy_buf(ctx); if (rc == NGX_ERROR) {
return rc;
} if (rc == NGX_AGAIN) {
if (out) {
break;
} return rc;
} /* delete the completed buf from the ctx->in chain */ if (ngx_buf_size(ctx->in->buf) == 0) {
ctx->in = ctx->in->next;
} cl = ngx_alloc_chain_link(ctx->pool);
if (cl == NULL) {
return NGX_ERROR;
} cl->buf = ctx->buf;
cl->next = NULL;
*last_out = cl;
last_out = &cl->next;
ctx->buf = NULL;
} if (out == NULL && last != NGX_NONE) { if (ctx->in) {
return NGX_AGAIN;
} return last;
} last = ctx->output_filter(ctx->filter_ctx, out); if (last == NGX_ERROR || last == NGX_DONE) {
return last;
} ngx_chain_update_chains(ctx->pool, &ctx->free, &ctx->busy, &out,
ctx->tag);
last_out = &out;
}
}

1.3 ngx_http_trailers_filter

static ngx_int_t
ngx_http_trailers_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_str_t value;
ngx_uint_t i, safe_status;
ngx_chain_t *cl;
ngx_table_elt_t *t;
ngx_http_header_val_t *h;
ngx_http_headers_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); /* 若 trailers 为 NULL 或其他,则下一个 */
if (in == NULL
|| conf->trailers == NULL
|| !r->expect_trailers
|| r->header_only)
{
return ngx_http_next_body_filter(r, in);
} for (cl = in; cl; cl = cl->next) {
if (cl->buf->last_buf) {
break;
}
} if (cl == NULL) {
return ngx_http_next_body_filter(r, in);
} switch (r->headers_out.status) { case NGX_HTTP_OK:
case NGX_HTTP_CREATED:
case NGX_HTTP_NO_CONTENT:
case NGX_HTTP_PARTIAL_CONTENT:
case NGX_HTTP_MOVED_PERMANENTLY:
case NGX_HTTP_MOVED_TEMPORARILY:
case NGX_HTTP_SEE_OTHER:
case NGX_HTTP_NOT_MODIFIED:
case NGX_HTTP_TEMPORARY_REDIRECT:
case NGX_HTTP_PERMANENT_REDIRECT:
safe_status = 1;
break; default:
safe_status = 0;
break;
} h = conf->trailers->elts;
for (i = 0; i < conf->trailers->nelts; i++) { if (!safe_status && !h[i].always) {
continue;
} if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {
return NGX_ERROR;
} if (value.len) {
t = ngx_list_push(&r->headers_out.trailers);
if (t == NULL) {
return NGX_ERROR;
} t->key = h[i].key;
t->value = value;
t->hash = 1;
}
} return ngx_http_next_body_filter(r, in);
}

1.4 ngx_http_charset_body_filter

暂略

1.5 ngx_http_ssi_body_filter

暂略

1.6 ngx_http_postpone_filter

暂略

1.7 ngx_http_gzip_body_filter

暂略

1.8 ngx_http_chunked_body_filter

暂略

1.9 ngx_http_write_filter

ngx_int_t
ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
off_t size, sent, nsent, limit;
ngx_uint_t last, flush, sync;
ngx_msec_t delay;
ngx_chain_t *cl, *ln, **ll, *chain;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf; c = r->connection; if (c->error) {
return NGX_ERROR;
} size = 0;
flush = 0;
sync = 0;
last = 0;
/* 指向 r->out 链表的第一个元素 */
ll = &r->out; /* find the size, the flush point and the last link of the saved chain */ /* 若此时缓存的是 body,则此时 r->out 链表中已经缓存响应消息的消息报头 */
for (cl = r->out; cl; cl = cl->next) {
ll = &cl->next; ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
"write old 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); #if 1
if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"zero size buf in writer "
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
cl->buf->temporary,
cl->buf->recycled,
cl->buf->in_file,
cl->buf->start,
cl->buf->pos,
cl->buf->last,
cl->buf->file,
cl->buf->file_pos,
cl->buf->file_last); ngx_debug_point();
return NGX_ERROR;
}
#endif size += ngx_buf_size(cl->buf); if (cl->buf->flush || cl->buf->recycled) {
flush = 1;
} if (cl->buf->sync) {
sync = 1;
} if (cl->buf->last_buf) {
last = 1;
}
} /* add the new chain to the existent one */ for (ln = in; ln; ln = ln->next) {
/* 生成一个 ngx_chain_t */
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
} cl->buf = ln->buf;
/* 将该新生成的 ngx_chain_t 添加到 r->out 链表尾部 */
*ll = cl;
ll = &cl->next; ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
"write new 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); #if 1
if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"zero size buf in writer "
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
cl->buf->temporary,
cl->buf->recycled,
cl->buf->in_file,
cl->buf->start,
cl->buf->pos,
cl->buf->last,
cl->buf->file,
cl->buf->file_pos,
cl->buf->file_last); ngx_debug_point();
return NGX_ERROR;
}
#endif size += ngx_buf_size(cl->buf); if (cl->buf->flush || cl->buf->recycled) {
flush = 1;
} if (cl->buf->sync) {
sync = 1;
} /* 若 last_buf 为 1,表明这个最后一个 buf 了 */
if (cl->buf->last_buf) {
last = 1;
}
} *ll = NULL; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http write filter: l:%ui f:%ui s:%O", last, flush, size); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /*
* avoid the output if there are no last buf, no flush point,
* there are the incoming bufs and the size of all bufs
* is smaller than "postpone_output" directive
*/ if (!last && !flush && in && size < (off_t) clcf->postpone_output) {
return NGX_OK;
} if (c->write->delayed) {
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
} if (size == 0
&& !(c->buffered & NGX_LOWLEVEL_BUFFERED)
&& !(last && c->need_last_buf))
{
if (last || flush || sync) {
for (cl = r->out; cl; /* void */) {
ln = cl;
cl = cl->next;
ngx_free_chain(r->pool, ln);
} r->out = NULL;
c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; return NGX_OK;
} ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"the http output chain is empty"); ngx_debug_point(); return NGX_ERROR;
} if (r->limit_rate) {
if (r->limit_rate_after == 0) {
r->limit_rate_after = clcf->limit_rate_after;
} limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1)
- (c->sent - r->limit_rate_after); if (limit <= 0) {
c->write->delayed = 1;
delay = (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1);
ngx_add_timer(c->write, delay); c->buffered |= NGX_HTTP_WRITE_BUFFERED; return NGX_AGAIN;
} if (clcf->sendfile_max_chunk
&& (off_t) clcf->sendfile_max_chunk < limit)
{
limit = clcf->sendfile_max_chunk;
} } else {
limit = clcf->sendfile_max_chunk;
} /* 当前已经发送的字节数 */
sent = c->sent; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http write filter limit %O", limit); /* 指向 ngx_linux_sendfile_chain 函数, 将响应消息发送给客户端 */
chain = c->send_chain(c, r->out, limit); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http write filter %p", chain); if (chain == NGX_CHAIN_ERROR) {
c->error = 1;
return NGX_ERROR;
} if (r->limit_rate) { nsent = c->sent; if (r->limit_rate_after) { sent -= r->limit_rate_after;
if (sent < 0) {
sent = 0;
} nsent -= r->limit_rate_after;
if (nsent < 0) {
nsent = 0;
}
} delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); if (delay > 0) {
limit = 0;
c->write->delayed = 1;
ngx_add_timer(c->write, delay);
}
} if (limit
&& c->write->ready
&& c->sent - sent >= limit - (off_t) (2 * ngx_pagesize))
{
c->write->delayed = 1;
ngx_add_timer(c->write, 1);
} /* 将 r->out 链表中的元素(即 ngx_chain_t)插入到 r->pool->chain 链表中 */
for (cl = r->out; cl && cl != chain; /* void */) {
ln = cl;
cl = cl->next;
ngx_free_chain(r->pool, ln);
} r->out = chain; if (chain) {
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
} c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
return NGX_AGAIN;
} return NGX_OK;
}

1.9.1 c->send_chain: ngx_linux_sendfile_chain

ngx_chain_t *
ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
{
int tcp_nodelay;
off_t send, prev_send;
size_t file_size, sent;
ssize_t n;
ngx_err_t err;
ngx_buf_t *file;
ngx_event_t *wev;
ngx_chain_t *cl;
ngx_iovec_t header;
struct iovec headers[NGX_IOVS_PREALLOCATE]; /* 获取该连接的写事件 */
wev = c->write; if (!wev->ready) {
return in;
} /* the maximum limit size is 2G-1 - the page size */ if (limit == 0 || limit > (off_t) (NGX_SENDFILE_MAXSIZE - ngx_pagesize)) {
limit = NGX_SENDFILE_MAXSIZE - ngx_pagesize;
} send = 0; header.iovs = headers;
header.nalloc = NGX_IOVS_PREALLOCATE; for ( ;; ) {
prev_send = send; /* create the iovec and coalesce the neighbouring bufs */ /* 将 in 中的数据(除在文件中的数据外)构造成 iovec */
cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); if (cl == NGX_CHAIN_ERROR) {
return NGX_CHAIN_ERROR;
} send += header.size; /* set TCP_CORK if there is a header before a file */ if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET
&& header.count != 0
&& cl
&& cl->buf->in_file)
{
/* the TCP_CORK and TCP_NODELAY are mutually exclusive */ if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) { tcp_nodelay = 0; if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
(const void *) &tcp_nodelay, sizeof(int)) == -1)
{
err = ngx_socket_errno; /*
* there is a tiny chance to be interrupted, however,
* we continue a processing with the TCP_NODELAY
* and without the TCP_CORK
*/ if (err != NGX_EINTR) {
wev->error = 1;
ngx_connection_error(c, err,
"setsockopt(TCP_NODELAY) failed");
return NGX_CHAIN_ERROR;
} } else {
c->tcp_nodelay = NGX_TCP_NODELAY_UNSET; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"no tcp_nodelay");
}
} if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
err = ngx_socket_errno; /*
* there is a tiny chance to be interrupted, however,
* we continue a processing without the TCP_CORK
*/ if (err != NGX_EINTR) {
wev->error = 1;
ngx_connection_error(c, err,
ngx_tcp_nopush_n " failed");
return NGX_CHAIN_ERROR;
} } else {
c->tcp_nopush = NGX_TCP_NOPUSH_SET; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"tcp_nopush");
}
}
} /* get the file buf */ /* 这里开始获取文件中的数据 */
if (header.count == 0 && cl && cl->buf->in_file && send < limit) {
file = cl->buf; /* coalesce the neighbouring file bufs */ /* 统计该文件的大小 */
file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); send += file_size;
#if 1
if (file_size == 0) {
ngx_debug_point();
return NGX_CHAIN_ERROR;
}
#endif /* 将该文件中的数据发送出去 */
n = ngx_linux_sendfile(c, file, file_size); if (n == NGX_ERROR) {
return NGX_CHAIN_ERROR;
} if (n == NGX_DONE) {
/* thread task posted */
return in;
} sent = (n == NGX_AGAIN) ? 0 : n; } else {
n = ngx_writev(c, &header); if (n == NGX_ERROR) {
return NGX_CHAIN_ERROR;
} sent = (n == NGX_AGAIN) ? 0 : n;
} /* 更新已经发送的字节数 */
c->sent += sent; in = ngx_chain_update_sent(in, sent); if (n == NGX_AGAIN) {
wev->ready = 0;
return in;
} if ((size_t) (send - prev_send) != sent) { /*
* sendfile() on Linux 4.3+ might be interrupted at any time,
* and provides no indication if it was interrupted or not,
* so we have to retry till an explicit EAGAIN
*
* sendfile() in threads can also report less bytes written
* than we are prepared to send now, since it was started in
* some point in the past, so we again have to retry
*/ send = prev_send + sent;
continue;
} if (send >= limit || in == NULL) {
return in;
}
}
}

1.9.2 ngx_output_chain_to_iovec

ngx_chain_t *
ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, size_t limit,
ngx_log_t *log)
{
size_t total, size;
u_char *prev;
ngx_uint_t n;
struct iovec *iov; iov = NULL;
prev = NULL;
total = 0;
n = 0; for ( /* void */ ; in && total < limit; in = in->next) { if (ngx_buf_special(in->buf)) {
continue;
} /* 若该buf中的数据是在文件中,则跳出该循环 */
if (in->buf->in_file) {
break;
} if (!ngx_buf_in_memory(in->buf)) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
"bad buf in output chain "
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
in->buf->temporary,
in->buf->recycled,
in->buf->in_file,
in->buf->start,
in->buf->pos,
in->buf->last,
in->buf->file,
in->buf->file_pos,
in->buf->file_last); ngx_debug_point(); return NGX_CHAIN_ERROR;
} size = in->buf->last - in->buf->pos; if (size > limit - total) {
size = limit - total;
} if (prev == in->buf->pos) {
iov->iov_len += size; } else {
if (n == vec->nalloc) {
break;
} iov = &vec->iovs[n++]; iov->iov_base = (void *) in->buf->pos;
iov->iov_len = size;
} prev = in->buf->pos + size;
total += size;
} vec->count = n;
vec->size = total; return in;
}

1.9.3 ngx_writev

ssize_t
ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec)
{
ssize_t n;
ngx_err_t err; eintr: n = writev(c->fd, vec->iovs, vec->count); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"writev: %z of %uz", n, vec->size); if (n == -1) {
err = ngx_errno; switch (err) {
case NGX_EAGAIN:
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
"writev() not ready");
return NGX_AGAIN; case NGX_EINTR:
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
"writev() was interrupted");
goto eintr; default:
c->write->error = 1;
ngx_connection_error(c, err, "writev() failed");
return NGX_ERROR;
}
} return n;
}

1.9.4 ngx_chain_update_sent

ngx_chain_t *
ngx_chain_update_sent(ngx_chain_t *in, off_t sent)
{
off_t size; for ( /* void */ ; in; in = in->next) { if (ngx_buf_special(in->buf)) {
continue;
} if (sent == 0) {
break;
} size = ngx_buf_size(in->buf); /* 若已将 buf 中的数据都发送出去 */
if (sent >= size) {
sent -= size; if (ngx_buf_in_memory(in->buf)) {
/* 则更新 pos 指针的位置 */
in->buf->pos = in->buf->last;
} if (in->buf->in_file) {
in->buf->file_pos = in->buf->file_last;
} continue;
} if (ngx_buf_in_memory(in->buf)) {
in->buf->pos += (size_t) sent;
} if (in->buf->in_file) {
in->buf->file_pos += sent;
} break;
} return in;
}

1.9.5 ngx_chain_coalesce_file

off_t
ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit)
{
off_t total, size, aligned, fprev;
ngx_fd_t fd;
ngx_chain_t *cl; total = 0; cl = *in;
fd = cl->buf->file->fd; do {
/* 计算当前需要发送的字节数 */
size = cl->buf->file_last - cl->buf->file_pos; if (size > limit - total) {
size = limit - total; aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
& ~((off_t) ngx_pagesize - 1); if (aligned <= cl->buf->file_last) {
size = aligned - cl->buf->file_pos;
} total += size;
break;
} total += size;
fprev = cl->buf->file_pos + size;
cl = cl->next; } while (cl
&& cl->buf->in_file
&& total < limit
&& fd == cl->buf->file->fd
&& fprev == cl->buf->file_pos); *in = cl; return total;
}

1.9.6 ngx_linux_sendfile

static ssize_t
ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size)
{
#if (NGX_HAVE_SENDFILE64)
off_t offset;
#else
int32_t offset;
#endif
ssize_t n;
ngx_err_t err; #if (NGX_THREADS) if (file->file->thread_handler) {
return ngx_linux_sendfile_thread(c, file, size);
} #endif #if (NGX_HAVE_SENDFILE64)
offset = file->file_pos;
#else
offset = (int32_t) file->file_pos;
#endif eintr: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"sendfile: @%O %uz", file->file_pos, size); n = sendfile(c->fd, file->file->fd, &offset, size); if (n == -1) {
err = ngx_errno; switch (err) {
case NGX_EAGAIN:
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
"sendfile() is not ready");
return NGX_AGAIN; case NGX_EINTR:
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
"sendfile() was interrupted");
goto eintr; default:
c->write->error = 1;
ngx_connection_error(c, err, "sendfile() failed");
return NGX_ERROR;
}
} if (n == 0) {
/*
* if sendfile returns zero, then someone has truncated the file,
* so the offset became beyond the end of the file
*/ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"sendfile() reported that \"%s\" was truncated at %O",
file->file->name.data, file->file_pos); return NGX_ERROR;
} ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %z of %uz @%O",
n, size, file->file_pos); return n;
}

Nginx-HTTP之ngx_http_top_body_filter的更多相关文章

  1. nginx入门

    1.   前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Ngi ...

  2. 《深入理解Nginx》阅读与实践(四):简单的HTTP过滤模块

    一.Nginx的HTTP过滤模块特征 一个请求可以被任意个HTTP模块处理: 在普通HTTP模块处理请求完毕并调用ngx_http_send_header()发送HTTP头部或调用ngx_http_o ...

  3. Emiller's Advanced Topics In Nginx Module Development

    Emiller的Nginx模块开发指南 By Evan Miller DRAFT: August 13, 2009 (changes) 翻译:Kongch @2010年1月5日 0:04am -- 2 ...

  4. nginx自定义模块记录上游服务器特定响应头

    功能,服务器通过扩展自定义命令,记录上游的服务器返回的特定响应头内容,记录到本地文件中 代码如下: /* * Copyright (C) Ciaos */ #include <ngx_confi ...

  5. nginx服务器屏蔽上游错误码

    平时的开发工作中,有时会遇到脚本权限不对导致403,文件被删除导致404,甚至后端业务异常导致5xx等情况,其实我们可以在服务器加上判断,检测当后端服务出现异常的时候前端返回一个指定的静态文件(也可以 ...

  6. nginx源代码分析--模块分类

    ngx-modules Nginx 基本的模块大致能够分为四类: handler – 协同完毕client请求的处理.产生响应数据.比方模块, ngx_http_rewrite_module, ngx ...

  7. nginx学习笔记——http module分析

         源码:nginx 1.12.0           nginx由于其高性能.扩充性好等特点在迅速走红,越来越多的公司采用nginx作web服务器.负载均衡.waf等 工作,一些基于nginx ...

  8. nginx源码分析——http模块

         源码:nginx 1.12.0      一.nginx http模块简介           由于nginx的性能优势,现在已经有越来越多的单位.个人采用nginx或者openresty. ...

  9. Nginx 模块开发

    Nginx 模块概述 Nginx 模块有三种角色: 处理请求并产生输出的 Handler 模块 : 处理由  Handler  产生的输出的 Filter (滤波器)模块: 当出现多个后台 服务器时, ...

  10. nginx源代码分析--nginx模块解析

    nginx的模块很之多.能够觉得全部代码都是以模块的形式组织.这包含核心模块和功能模块,针对不同的应用场合.并不是全部的功能模块都要被用到,附录A给出的是默认configure(即简单的httpser ...

随机推荐

  1. wrbstrom使用

    使用webstrom时遇到Firefox浏览器打不开问题,是webstrom未找到你Firefox的安装路径下面为大家提供解决方法: 文件--->设置--->工具--->web浏览器 ...

  2. JS经典算法

     寻找500以内能被5和7整除的数字:for(var num=1;num<=500&&num++;) if(num%7==0&&num%5==0){ consol ...

  3. asp.net ListView控件的简单实用和配置

    1 web窗体界面代码 ItemType:控件要绑定的实体模型 SelectMethod:控件获取实体集合的后台方法 DataKeyNames:实体的主键 UpdateProduct:设置跟新的方法 ...

  4. Web Api 将DataTable装换成Excel,并通过文件流将其下载

    不废话,直接上代码 前端代码 <input type="button" class="layui-btn" value="Test-GetFil ...

  5. SQL优化的总结和一些避免全盘扫描的注意事项

    1.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描. 2.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一 ...

  6. 分布式全局ID的几种生成方案

    前言 在互联网的业务系统中,涉及到各种各样的ID,如在支付系统中就会有支付ID.退款ID等. 那一般生成ID都有哪些解决方案呢?特别是在复杂的分布式系统业务场景中,我们应该采用哪种适合自己的解决方案是 ...

  7. CRM WebClient UI的浏览器打印实现

    WebClient UI上自带了一个打印按钮,按Ctrl + P后可以生成一个新的页面供打印. 如下图所示.可以看到这个页面里所有的超链接都已经被移除了. 这个页面的生成逻辑如下. 1. 按住ctrl ...

  8. 9.Spring整合Hibernate_2_声明式的事务管理(Xml的方式)

    使用xml的方式进行声明式的事务管理 推荐使用xml的方式,因为可以同时为多个方法进行声明 <!-- 开启Spring中的事务管理(声明式的事务管理) xml--> <!-- 不管是 ...

  9. PHP 获取数组指定值的位置或下标

    <?php     //定义一个数组     $array = array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd');     // ...

  10. 后台程序员简单应用前端的bootstrap(小白)

    原因: 现在技术更新很快,我们需要掌握更多的语言和技术,公司现在也希望招全栈工程师. 名词: bootstrap(前端框架),less(css的扩充) 案例: 在bootstrap中常用row行级元素 ...