src/event/ngx_event_pipe.c - nginx-1.31.9 nginx/ @ 2a3a19c6f

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_event_pipe.h>


  9. static ngx_int_t ngx_event_pipe_read_upstream(ngx_event_pipe_t *p);
  10. static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p);

  11. static ngx_int_t ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p);
  12. static ngx_inline void ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf);
  13. static ngx_int_t ngx_event_pipe_drain_chains(ngx_event_pipe_t *p);


  14. ngx_int_t
  15. ‌ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
  16. {
  17.     ngx_int_t     rc;
  18.     ngx_uint_t    flags;
  19.     ngx_event_t  *rev, *wev;

  20.     for ( ;; ) {
  21.         if (do_write) {
  22.             p->log->action = "sending to client";

  23.             rc = ngx_event_pipe_write_to_downstream(p);

  24.             if (rc == NGX_ABORT) {
  25.                 return NGX_ABORT;
  26.             }

  27.             if (rc == NGX_BUSY) {
  28.                 return NGX_OK;
  29.             }
  30.         }

  31.         p->read = 0;
  32.         p->upstream_blocked = 0;

  33.         p->log->action = "reading upstream";

  34.         if (ngx_event_pipe_read_upstream(p) == NGX_ABORT) {
  35.             return NGX_ABORT;
  36.         }

  37.         if (!p->read && !p->upstream_blocked) {
  38.             break;
  39.         }

  40.         do_write = 1;
  41.     }

  42.     if (p->upstream
  43.         && p->upstream->fd != (ngx_socket_t) -1)
  44.     {
  45.         rev = p->upstream->read;

  46.         flags = (rev->eof || rev->error) ? NGX_CLOSE_EVENT : 0;

  47.         if (ngx_handle_read_event(rev, flags) != NGX_OK) {
  48.             return NGX_ABORT;
  49.         }

  50.         if (!rev->delayed) {
  51.             if (rev->active && !rev->ready) {
  52.                 ngx_add_timer(rev, p->read_timeout);

  53.             } else if (rev->timer_set) {
  54.                 ngx_del_timer(rev);
  55.             }
  56.         }
  57.     }

  58.     if (p->downstream->fd != (ngx_socket_t) -1
  59.         && p->downstream->data == p->output_ctx)
  60.     {
  61.         wev = p->downstream->write;
  62.         if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
  63.             return NGX_ABORT;
  64.         }

  65.         if (!wev->delayed) {
  66.             if (wev->active && !wev->ready) {
  67.                 ngx_add_timer(wev, p->send_timeout);

  68.             } else if (wev->timer_set) {
  69.                 ngx_del_timer(wev);
  70.             }
  71.         }
  72.     }

  73.     return NGX_OK;
  74. }


  75. static ngx_int_t
  76. ‌ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
  77. {
  78.     off_t         limit;
  79.     ssize_t       n, size;
  80.     ngx_int_t     rc;
  81.     ngx_buf_t    *b;
  82.     ngx_msec_t    delay;
  83.     ngx_chain_t  *chain, *cl, *ln;

  84.     if (p->upstream_eof || p->upstream_error || p->upstream_done
  85.         || p->upstream == NULL)
  86.     {
  87.         return NGX_OK;
  88.     }

  89. #if (NGX_THREADS)

  90.     if (p->aio) {
  91.         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  92.                        "pipe read upstream: aio");
  93.         return NGX_AGAIN;
  94.     }

  95.     if (p->writing) {
  96.         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  97.                        "pipe read upstream: writing");

  98.         rc = ngx_event_pipe_write_chain_to_temp_file(p);

  99.         if (rc != NGX_OK) {
  100.             return rc;
  101.         }
  102.     }

  103. #endif

  104.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
  105.                    "pipe read upstream: %d", p->upstream->read->ready);

  106.     for ( ;; ) {

  107.         if (p->upstream_eof || p->upstream_error || p->upstream_done) {
  108.             break;
  109.         }

  110.         if (p->preread_bufs == NULL && !p->upstream->read->ready) {
  111.             break;
  112.         }

  113.         if (p->preread_bufs) {

  114.             /* use the pre-read bufs if they exist */

  115.             chain = p->preread_bufs;
  116.             p->preread_bufs = NULL;
  117.             n = p->preread_size;

  118.             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
  119.                            "pipe preread: %z", n);

  120.             if (n) {
  121.                 p->read = 1;
  122.             }

  123.         } else {

  124. #if (NGX_HAVE_KQUEUE)

  125.             /*
  126.              * kqueue notifies about the end of file or a pending error.
  127.              * This test allows not to allocate a buf on these conditions
  128.              * and not to call c->recv_chain().
  129.              */

  130.             if (p->upstream->read->available == 0
  131.                 && p->upstream->read->pending_eof
  132. #if (NGX_SSL)
  133.                 && !p->upstream->ssl
  134. #endif
  135.                 )
  136.             {
  137.                 p->upstream->read->ready = 0;
  138.                 p->upstream->read->eof = 1;
  139.                 p->upstream_eof = 1;
  140.                 p->read = 1;

  141.                 if (p->upstream->read->kq_errno) {
  142.                     p->upstream->read->error = 1;
  143.                     p->upstream_error = 1;
  144.                     p->upstream_eof = 0;

  145.                     ngx_log_error(NGX_LOG_ERR, p->log,
  146.                                   p->upstream->read->kq_errno,
  147.                                   "kevent() reported that upstream "
  148.                                   "closed connection");
  149.                 }

  150.                 break;
  151.             }
  152. #endif

  153.             if (p->limit_rate) {
  154.                 if (p->upstream->read->delayed) {
  155.                     break;
  156.                 }

  157.                 limit = (off_t) p->limit_rate * (ngx_time() - p->start_sec + 1)
  158.                         - p->read_length;

  159.                 if (limit <= 0) {
  160.                     p->upstream->read->delayed = 1;
  161.                     delay = (ngx_msec_t) (- limit * 1000 / p->limit_rate + 1);
  162.                     ngx_add_timer(p->upstream->read, delay);
  163.                     break;
  164.                 }

  165.             } else {
  166.                 limit = 0;
  167.             }

  168.             if (p->free_raw_bufs) {

  169.                 /* use the free bufs if they exist */

  170.                 chain = p->free_raw_bufs;
  171.                 p->free_raw_bufs = NULL;

  172.             } else if (p->allocated < p->bufs.num) {

  173.                 /* allocate a new buf if it's still allowed */

  174.                 b = ngx_create_temp_buf(p->pool, p->bufs.size);
  175.                 if (b == NULL) {
  176.                     return NGX_ABORT;
  177.                 }

  178.                 p->allocated++;

  179.                 chain = ngx_alloc_chain_link(p->pool);
  180.                 if (chain == NULL) {
  181.                     return NGX_ABORT;
  182.                 }

  183.                 chain->buf = b;
  184.                 chain->next = NULL;

  185.             } else if (!p->cacheable
  186.                        && !p->downstream_error
  187.                        && p->downstream->data == p->output_ctx
  188.                        && p->downstream->write->ready
  189.                        && !p->downstream->write->delayed)
  190.             {
  191.                 /*
  192.                  * if the bufs are not needed to be saved in a cache and
  193.                  * a downstream is ready then write the bufs to a downstream
  194.                  */

  195.                 p->upstream_blocked = 1;

  196.                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  197.                                "pipe downstream ready");

  198.                 break;

  199.             } else if (p->cacheable
  200.                        || p->temp_file->offset < p->max_temp_file_size)
  201.             {

  202.                 /*
  203.                  * if it is allowed, then save some bufs from p->in
  204.                  * to a temporary file, and add them to a p->out chain
  205.                  */

  206.                 rc = ngx_event_pipe_write_chain_to_temp_file(p);

  207.                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
  208.                                "pipe temp offset: %O", p->temp_file->offset);

  209.                 if (rc == NGX_BUSY) {
  210.                     break;
  211.                 }

  212.                 if (rc != NGX_OK) {
  213.                     return rc;
  214.                 }

  215.                 chain = p->free_raw_bufs;
  216.                 p->free_raw_bufs = NULL;

  217.             } else {

  218.                 /* there are no bufs to read in */

  219.                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  220.                                "no pipe bufs to read in");

  221.                 break;
  222.             }

  223.             n = p->upstream->recv_chain(p->upstream, chain, limit);

  224.             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
  225.                            "pipe recv chain: %z", n);

  226.             if (p->free_raw_bufs) {
  227.                 chain->next = p->free_raw_bufs;
  228.             }
  229.             p->free_raw_bufs = chain;

  230.             if (n == NGX_ERROR) {
  231.                 p->upstream_error = 1;
  232.                 break;
  233.             }

  234.             if (n == NGX_AGAIN) {
  235.                 break;
  236.             }

  237.             p->read = 1;

  238.             if (n == 0) {
  239.                 p->upstream_eof = 1;
  240.                 break;
  241.             }
  242.         }

  243.         delay = p->limit_rate ? (ngx_msec_t) n * 1000 / p->limit_rate : 0;

  244.         p->read_length += n;
  245.         cl = chain;
  246.         p->free_raw_bufs = NULL;

  247.         while (cl && n > 0) {

  248.             ngx_event_pipe_remove_shadow_links(cl->buf);

  249.             size = cl->buf->end - cl->buf->last;

  250.             if (n >= size) {
  251.                 cl->buf->last = cl->buf->end;

  252.                 /* STUB */ cl->buf->num = p->num++;

  253.                 if (p->input_filter(p, cl->buf) == NGX_ERROR) {
  254.                     return NGX_ABORT;
  255.                 }

  256.                 n -= size;
  257.                 ln = cl;
  258.                 cl = cl->next;
  259.                 ngx_free_chain(p->pool, ln);

  260.             } else {
  261.                 cl->buf->last += n;
  262.                 n = 0;
  263.             }
  264.         }

  265.         if (cl) {
  266.             for (ln = cl; ln->next; ln = ln->next) { /* void */ }

  267.             ln->next = p->free_raw_bufs;
  268.             p->free_raw_bufs = cl;
  269.         }

  270.         if (delay > 0) {
  271.             p->upstream->read->delayed = 1;
  272.             ngx_add_timer(p->upstream->read, delay);
  273.             break;
  274.         }
  275.     }

  276. #if (NGX_DEBUG)

  277.     for (cl = p->busy; cl; cl = cl->next) {
  278.         ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0,
  279.                        "pipe buf busy s:%d t:%d f:%d "
  280.                        "%p, pos %p, size: %z "
  281.                        "file: %O, size: %O",
  282.                        (cl->buf->shadow ? 1 : 0),
  283.                        cl->buf->temporary, cl->buf->in_file,
  284.                        cl->buf->start, cl->buf->pos,
  285.                        cl->buf->last - cl->buf->pos,
  286.                        cl->buf->file_pos,
  287.                        cl->buf->file_last - cl->buf->file_pos);
  288.     }

  289.     for (cl = p->out; cl; cl = cl->next) {
  290.         ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0,
  291.                        "pipe buf out  s:%d t:%d f:%d "
  292.                        "%p, pos %p, size: %z "
  293.                        "file: %O, size: %O",
  294.                        (cl->buf->shadow ? 1 : 0),
  295.                        cl->buf->temporary, cl->buf->in_file,
  296.                        cl->buf->start, cl->buf->pos,
  297.                        cl->buf->last - cl->buf->pos,
  298.                        cl->buf->file_pos,
  299.                        cl->buf->file_last - cl->buf->file_pos);
  300.     }

  301.     for (cl = p->in; cl; cl = cl->next) {
  302.         ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0,
  303.                        "pipe buf in   s:%d t:%d f:%d "
  304.                        "%p, pos %p, size: %z "
  305.                        "file: %O, size: %O",
  306.                        (cl->buf->shadow ? 1 : 0),
  307.                        cl->buf->temporary, cl->buf->in_file,
  308.                        cl->buf->start, cl->buf->pos,
  309.                        cl->buf->last - cl->buf->pos,
  310.                        cl->buf->file_pos,
  311.                        cl->buf->file_last - cl->buf->file_pos);
  312.     }

  313.     for (cl = p->free_raw_bufs; cl; cl = cl->next) {
  314.         ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0,
  315.                        "pipe buf free s:%d t:%d f:%d "
  316.                        "%p, pos %p, size: %z "
  317.                        "file: %O, size: %O",
  318.                        (cl->buf->shadow ? 1 : 0),
  319.                        cl->buf->temporary, cl->buf->in_file,
  320.                        cl->buf->start, cl->buf->pos,
  321.                        cl->buf->last - cl->buf->pos,
  322.                        cl->buf->file_pos,
  323.                        cl->buf->file_last - cl->buf->file_pos);
  324.     }

  325.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
  326.                    "pipe length: %O", p->length);

  327. #endif

  328.     if (p->free_raw_bufs && p->length != -1) {
  329.         cl = p->free_raw_bufs;

  330.         if (cl->buf->last - cl->buf->pos >= p->length) {

  331.             p->free_raw_bufs = cl->next;

  332.             /* STUB */ cl->buf->num = p->num++;

  333.             if (p->input_filter(p, cl->buf) == NGX_ERROR) {
  334.                 return NGX_ABORT;
  335.             }

  336.             ngx_free_chain(p->pool, cl);
  337.         }
  338.     }

  339.     if (p->length == 0) {
  340.         p->upstream_done = 1;
  341.         p->read = 1;
  342.     }

  343.     if ((p->upstream_eof || p->upstream_error) && p->free_raw_bufs) {

  344.         /* STUB */ p->free_raw_bufs->buf->num = p->num++;

  345.         if (p->input_filter(p, p->free_raw_bufs->buf) == NGX_ERROR) {
  346.             return NGX_ABORT;
  347.         }

  348.         p->free_raw_bufs = p->free_raw_bufs->next;

  349.         if (p->free_bufs && p->buf_to_file == NULL) {
  350.             for (cl = p->free_raw_bufs; cl; cl = cl->next) {
  351.                 if (cl->buf->shadow == NULL) {
  352.                     ngx_pfree(p->pool, cl->buf->start);
  353.                 }
  354.             }
  355.         }
  356.     }

  357.     if (p->cacheable && (p->in || p->buf_to_file)) {

  358.         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  359.                        "pipe write chain");

  360.         rc = ngx_event_pipe_write_chain_to_temp_file(p);

  361.         if (rc != NGX_OK) {
  362.             return rc;
  363.         }
  364.     }

  365.     return NGX_OK;
  366. }


  367. static ngx_int_t
  368. ‌ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
  369. {
  370.     u_char            *prev;
  371.     size_t             bsize;
  372.     ngx_int_t          rc;
  373.     ngx_uint_t         flush, flushed, prev_last_shadow;
  374.     ngx_chain_t       *out, **ll, *cl;
  375.     ngx_connection_t  *downstream;

  376.     downstream = p->downstream;

  377.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
  378.                    "pipe write downstream: %d", downstream->write->ready);

  379. #if (NGX_THREADS)

  380.     if (p->writing) {
  381.         rc = ngx_event_pipe_write_chain_to_temp_file(p);

  382.         if (rc == NGX_ABORT) {
  383.             return NGX_ABORT;
  384.         }
  385.     }

  386. #endif

  387.     flushed = 0;

  388.     for ( ;; ) {
  389.         if (p->downstream_error) {
  390.             return ngx_event_pipe_drain_chains(p);
  391.         }

  392.         if (p->upstream_eof || p->upstream_error || p->upstream_done) {

  393.             /* pass the p->out and p->in chains to the output filter */

  394.             for (cl = p->busy; cl; cl = cl->next) {
  395.                 cl->buf->recycled = 0;
  396.             }

  397.             if (p->out) {
  398.                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  399.                                "pipe write downstream flush out");

  400.                 for (cl = p->out; cl; cl = cl->next) {
  401.                     cl->buf->recycled = 0;
  402.                 }

  403.                 rc = p->output_filter(p->output_ctx, p->out);

  404.                 if (rc == NGX_ERROR) {
  405.                     p->downstream_error = 1;
  406.                     return ngx_event_pipe_drain_chains(p);
  407.                 }

  408.                 p->out = NULL;
  409.             }

  410.             if (p->writing) {
  411.                 break;
  412.             }

  413.             if (p->in) {
  414.                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  415.                                "pipe write downstream flush in");

  416.                 for (cl = p->in; cl; cl = cl->next) {
  417.                     cl->buf->recycled = 0;
  418.                 }

  419.                 rc = p->output_filter(p->output_ctx, p->in);

  420.                 if (rc == NGX_ERROR) {
  421.                     p->downstream_error = 1;
  422.                     return ngx_event_pipe_drain_chains(p);
  423.                 }

  424.                 p->in = NULL;
  425.             }

  426.             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  427.                            "pipe write downstream done");

  428.             /* TODO: free unused bufs */

  429.             p->downstream_done = 1;
  430.             break;
  431.         }

  432.         if (downstream->data != p->output_ctx
  433.             || !downstream->write->ready
  434.             || downstream->write->delayed)
  435.         {
  436.             break;
  437.         }

  438.         /* bsize is the size of the busy recycled bufs */

  439.         prev = NULL;
  440.         bsize = 0;

  441.         for (cl = p->busy; cl; cl = cl->next) {

  442.             if (cl->buf->recycled) {
  443.                 if (prev == cl->buf->start) {
  444.                     continue;
  445.                 }

  446.                 bsize += cl->buf->end - cl->buf->start;
  447.                 prev = cl->buf->start;
  448.             }
  449.         }

  450.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
  451.                        "pipe write busy: %uz", bsize);

  452.         out = NULL;

  453.         if (bsize >= (size_t) p->busy_size) {
  454.             flush = 1;
  455.             goto flush;
  456.         }

  457.         flush = 0;
  458.         ll = NULL;
  459.         prev_last_shadow = 1;

  460.         for ( ;; ) {
  461.             if (p->out) {
  462.                 cl = p->out;

  463.                 if (cl->buf->recycled) {
  464.                     ngx_log_error(NGX_LOG_ALERT, p->log, 0,
  465.                                   "recycled buffer in pipe out chain");
  466.                 }

  467.                 p->out = p->out->next;

  468.             } else if (!p->cacheable && !p->writing && p->in) {
  469.                 cl = p->in;

  470.                 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0,
  471.                                "pipe write buf ls:%d %p %z",
  472.                                cl->buf->last_shadow,
  473.                                cl->buf->pos,
  474.                                cl->buf->last - cl->buf->pos);

  475.                 if (cl->buf->recycled && prev_last_shadow) {
  476.                     if (bsize + cl->buf->end - cl->buf->start > p->busy_size) {
  477.                         flush = 1;
  478.                         break;
  479.                     }

  480.                     bsize += cl->buf->end - cl->buf->start;
  481.                 }

  482.                 prev_last_shadow = cl->buf->last_shadow;

  483.                 p->in = p->in->next;

  484.             } else {
  485.                 break;
  486.             }

  487.             cl->next = NULL;

  488.             if (out) {
  489.                 *ll = cl;
  490.             } else {
  491.                 out = cl;
  492.             }
  493.             ll = &cl->next;
  494.         }

  495.     flush:

  496.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
  497.                        "pipe write: out:%p, f:%ui", out, flush);

  498.         if (out == NULL) {

  499.             if (!flush) {
  500.                 break;
  501.             }

  502.             /* a workaround for AIO */
  503.             if (flushed++ > 10) {
  504.                 return NGX_BUSY;
  505.             }
  506.         }

  507.         rc = p->output_filter(p->output_ctx, out);

  508.         ngx_chain_update_chains(p->pool, &p->free, &p->busy, &out, p->tag);

  509.         if (rc == NGX_ERROR) {
  510.             p->downstream_error = 1;
  511.             return ngx_event_pipe_drain_chains(p);
  512.         }

  513.         for (cl = p->free; cl; cl = cl->next) {

  514.             if (cl->buf->temp_file) {
  515.                 if (p->cacheable || !p->cyclic_temp_file) {
  516.                     continue;
  517.                 }

  518.                 /* reset p->temp_offset if all bufs had been sent */

  519.                 if (cl->buf->file_last == p->temp_file->offset) {
  520.                     p->temp_file->offset = 0;
  521.                 }
  522.             }

  523.             /* TODO: free buf if p->free_bufs && upstream done */

  524.             /* add the free shadow raw buf to p->free_raw_bufs */

  525.             if (cl->buf->last_shadow) {
  526.                 if (ngx_event_pipe_add_free_buf(p, cl->buf->shadow) != NGX_OK) {
  527.                     return NGX_ABORT;
  528.                 }

  529.                 cl->buf->last_shadow = 0;
  530.             }

  531.             cl->buf->shadow = NULL;
  532.         }
  533.     }

  534.     return NGX_OK;
  535. }


  536. static ngx_int_t
  537. ‌ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
  538. {
  539.     ssize_t       size, bsize, n;
  540.     ngx_buf_t    *b;
  541.     ngx_uint_t    prev_last_shadow;
  542.     ngx_chain_t  *cl, *tl, *next, *out, **ll, **last_out, **last_free;

  543. #if (NGX_THREADS)

  544.     if (p->writing) {

  545.         if (p->aio) {
  546.             return NGX_AGAIN;
  547.         }

  548.         out = p->writing;
  549.         p->writing = NULL;

  550.         n = ngx_write_chain_to_temp_file(p->temp_file, NULL);

  551.         if (n == NGX_ERROR) {
  552.             return NGX_ABORT;
  553.         }

  554.         goto done;
  555.     }

  556. #endif

  557.     if (p->buf_to_file) {
  558.         out = ngx_alloc_chain_link(p->pool);
  559.         if (out == NULL) {
  560.             return NGX_ABORT;
  561.         }

  562.         out->buf = p->buf_to_file;
  563.         out->next = p->in;

  564.     } else {
  565.         out = p->in;
  566.     }

  567.     if (!p->cacheable) {

  568.         size = 0;
  569.         cl = out;
  570.         ll = NULL;
  571.         prev_last_shadow = 1;

  572.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
  573.                        "pipe offset: %O", p->temp_file->offset);

  574.         do {
  575.             bsize = cl->buf->last - cl->buf->pos;

  576.             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, p->log, 0,
  577.                            "pipe buf ls:%d %p, pos %p, size: %z",
  578.                            cl->buf->last_shadow, cl->buf->start,
  579.                            cl->buf->pos, bsize);

  580.             if (prev_last_shadow
  581.                 && ((size + bsize > p->temp_file_write_size)
  582.                     || (p->temp_file->offset + size + bsize
  583.                         > p->max_temp_file_size)))
  584.             {
  585.                 break;
  586.             }

  587.             prev_last_shadow = cl->buf->last_shadow;

  588.             size += bsize;
  589.             ll = &cl->next;
  590.             cl = cl->next;

  591.         } while (cl);

  592.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "size: %z", size);

  593.         if (ll == NULL) {
  594.             return NGX_BUSY;
  595.         }

  596.         if (cl) {
  597.             p->in = cl;
  598.             *ll = NULL;

  599.         } else {
  600.             p->in = NULL;
  601.             p->last_in = &p->in;
  602.         }

  603.     } else {
  604.         p->in = NULL;
  605.         p->last_in = &p->in;
  606.     }

  607. #if (NGX_THREADS)
  608.     if (p->thread_handler) {
  609.         p->temp_file->thread_write = 1;
  610.         p->temp_file->file.thread_task = p->thread_task;
  611.         p->temp_file->file.thread_handler = p->thread_handler;
  612.         p->temp_file->file.thread_ctx = p->thread_ctx;
  613.     }
  614. #endif

  615.     n = ngx_write_chain_to_temp_file(p->temp_file, out);

  616.     if (n == NGX_ERROR) {
  617.         return NGX_ABORT;
  618.     }

  619. #if (NGX_THREADS)

  620.     if (n == NGX_AGAIN) {
  621.         p->writing = out;
  622.         p->thread_task = p->temp_file->file.thread_task;
  623.         return NGX_AGAIN;
  624.     }

  625. done:

  626. #endif

  627.     if (p->buf_to_file) {
  628.         p->temp_file->offset = p->buf_to_file->last - p->buf_to_file->pos;
  629.         n -= p->buf_to_file->last - p->buf_to_file->pos;
  630.         p->buf_to_file = NULL;
  631.         out = out->next;
  632.     }

  633.     if (n > 0) {
  634.         /* update previous buffer or add new buffer */

  635.         if (p->out) {
  636.             for (cl = p->out; cl->next; cl = cl->next) { /* void */ }

  637.             b = cl->buf;

  638.             if (b->file_last == p->temp_file->offset) {
  639.                 p->temp_file->offset += n;
  640.                 b->file_last = p->temp_file->offset;
  641.                 goto free;
  642.             }

  643.             last_out = &cl->next;

  644.         } else {
  645.             last_out = &p->out;
  646.         }

  647.         cl = ngx_chain_get_free_buf(p->pool, &p->free);
  648.         if (cl == NULL) {
  649.             return NGX_ABORT;
  650.         }

  651.         b = cl->buf;

  652.         ngx_memzero(b, sizeof(ngx_buf_t));

  653.         b->tag = p->tag;

  654.         b->file = &p->temp_file->file;
  655.         b->file_pos = p->temp_file->offset;
  656.         p->temp_file->offset += n;
  657.         b->file_last = p->temp_file->offset;

  658.         b->in_file = 1;
  659.         b->temp_file = 1;

  660.         *last_out = cl;
  661.     }

  662. free:

  663.     for (last_free = &p->free_raw_bufs;
  664.          *last_free != NULL;
  665.          last_free = &(*last_free)->next)
  666.     {
  667.         /* void */
  668.     }

  669.     for (cl = out; cl; cl = next) {
  670.         next = cl->next;

  671.         cl->next = p->free;
  672.         p->free = cl;

  673.         b = cl->buf;

  674.         if (b->last_shadow) {

  675.             tl = ngx_alloc_chain_link(p->pool);
  676.             if (tl == NULL) {
  677.                 return NGX_ABORT;
  678.             }

  679.             tl->buf = b->shadow;
  680.             tl->next = NULL;

  681.             *last_free = tl;
  682.             last_free = &tl->next;

  683.             b->shadow->pos = b->shadow->start;
  684.             b->shadow->last = b->shadow->start;

  685.             ngx_event_pipe_remove_shadow_links(b->shadow);
  686.         }
  687.     }

  688.     return NGX_OK;
  689. }


  690. /* the copy input filter */

  691. ngx_int_t
  692. ‌ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  693. {
  694.     ngx_buf_t    *b;
  695.     ngx_chain_t  *cl;

  696.     if (buf->pos == buf->last) {
  697.         return NGX_OK;
  698.     }

  699.     if (p->upstream_done) {
  700.         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
  701.                        "input data after close");
  702.         return NGX_OK;
  703.     }

  704.     if (p->length == 0) {
  705.         p->upstream_done = 1;

  706.         ngx_log_error(NGX_LOG_WARN, p->log, 0,
  707.                       "upstream sent more data than specified in "
  708.                       "\"Content-Length\" header");

  709.         return NGX_OK;
  710.     }

  711.     cl = ngx_chain_get_free_buf(p->pool, &p->free);
  712.     if (cl == NULL) {
  713.         return NGX_ERROR;
  714.     }

  715.     b = cl->buf;

  716.     ngx_memcpy(b, buf, sizeof(ngx_buf_t));
  717.     b->shadow = buf;
  718.     b->tag = p->tag;
  719.     b->last_shadow = 1;
  720.     b->recycled = 1;
  721.     buf->shadow = b;

  722.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);

  723.     if (p->in) {
  724.         *p->last_in = cl;
  725.     } else {
  726.         p->in = cl;
  727.     }
  728.     p->last_in = &cl->next;

  729.     if (p->length == -1) {
  730.         return NGX_OK;
  731.     }

  732.     if (b->last - b->pos > p->length) {

  733.         ngx_log_error(NGX_LOG_WARN, p->log, 0,
  734.                       "upstream sent more data than specified in "
  735.                       "\"Content-Length\" header");

  736.         b->last = b->pos + p->length;
  737.         p->upstream_done = 1;

  738.         return NGX_OK;
  739.     }

  740.     p->length -= b->last - b->pos;

  741.     return NGX_OK;
  742. }


  743. static ngx_inline void
  744. ‌ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf)
  745. {
  746.     ngx_buf_t  *b, *next;

  747.     b = buf->shadow;

  748.     if (b == NULL) {
  749.         return;
  750.     }

  751.     while (!b->last_shadow) {
  752.         next = b->shadow;

  753.         b->temporary = 0;
  754.         b->recycled = 0;

  755.         b->shadow = NULL;
  756.         b = next;
  757.     }

  758.     b->temporary = 0;
  759.     b->recycled = 0;
  760.     b->last_shadow = 0;

  761.     b->shadow = NULL;

  762.     buf->shadow = NULL;
  763. }


  764. ngx_int_t
  765. ‌ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b)
  766. {
  767.     ngx_chain_t  *cl;

  768.     cl = ngx_alloc_chain_link(p->pool);
  769.     if (cl == NULL) {
  770.         return NGX_ERROR;
  771.     }

  772.     if (p->buf_to_file && b->start == p->buf_to_file->start) {
  773.         b->pos = p->buf_to_file->last;
  774.         b->last = p->buf_to_file->last;

  775.     } else {
  776.         b->pos = b->start;
  777.         b->last = b->start;
  778.     }

  779.     b->shadow = NULL;

  780.     cl->buf = b;

  781.     if (p->free_raw_bufs == NULL) {
  782.         p->free_raw_bufs = cl;
  783.         cl->next = NULL;

  784.         return NGX_OK;
  785.     }

  786.     if (p->free_raw_bufs->buf->pos == p->free_raw_bufs->buf->last) {

  787.         /* add the free buf to the list start */

  788.         cl->next = p->free_raw_bufs;
  789.         p->free_raw_bufs = cl;

  790.         return NGX_OK;
  791.     }

  792.     /* the first free buf is partially filled, thus add the free buf after it */

  793.     cl->next = p->free_raw_bufs->next;
  794.     p->free_raw_bufs->next = cl;

  795.     return NGX_OK;
  796. }


  797. static ngx_int_t
  798. ‌ngx_event_pipe_drain_chains(ngx_event_pipe_t *p)
  799. {
  800.     ngx_chain_t  *cl, *tl;

  801.     for ( ;; ) {
  802.         if (p->out) {
  803.             cl = p->out;
  804.             p->out = NULL;

  805.         } else if (p->in) {
  806.             cl = p->in;
  807.             p->in = NULL;

  808.         } else {
  809.             return NGX_OK;
  810.         }

  811.         while (cl) {
  812.             if (cl->buf->last_shadow) {
  813.                 if (ngx_event_pipe_add_free_buf(p, cl->buf->shadow) != NGX_OK) {
  814.                     return NGX_ABORT;
  815.                 }

  816.                 cl->buf->last_shadow = 0;
  817.             }

  818.             cl->buf->shadow = NULL;
  819.             tl = cl->next;
  820.             cl->next = p->free;
  821.             p->free = cl;
  822.             cl = tl;
  823.         }
  824.     }
  825. }