static ngx_int_t ngx_event_pipe_drain_chains(ngx_event_pipe_t *p) { ngx_chain_t *cl, *tl; for ( ;; ) { if (p->busy) { cl = p->busy; p->busy = NULL; } else if (p->out) { cl = p->out; p->out = NULL; } else if (p->in) { cl = p->in; p->in = NULL; } else { return NGX_OK; } while (cl) { if (cl->buf->last_shadow) { if (ngx_event_pipe_add_free_buf(p, cl->buf->shadow) != NGX_OK) { return NGX_ABORT; } cl->buf->last_shadow = 0; } cl->buf->shadow = NULL; tl = cl->next; cl->next = p->free; p->free = cl; cl = tl; } } }
static ngx_int_t ngx_http_ajp_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) { ngx_int_t rc; ngx_buf_t *b, **prev; ngx_chain_t *cl; ngx_http_request_t *r; ngx_http_ajp_ctx_t *a; ngx_http_ajp_loc_conf_t *alcf; if (buf->pos == buf->last) { return NGX_OK; } r = p->input_ctx; a = ngx_http_get_module_ctx(r, ngx_http_ajp_module); alcf = ngx_http_get_module_loc_conf(r, ngx_http_ajp_module); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "ngx_http_ajp_input_filter: state(%d)", a->state); b = NULL; prev = &buf->shadow; while(buf->pos < buf->last) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0, "input filter packet, begin length: %z, buffer_size: %z", a->length, ngx_buf_size(buf)); /* This a new data packet */ if (a->length == 0) { if (a->extra_zero_byte) { if (*(buf->pos) == 0x00){ buf->pos++; } a->extra_zero_byte = 0; } rc = ngx_http_ajp_process_packet_header(r, a, buf); if (buf->pos == buf->last) { break; } if (rc == NGX_AGAIN) { break; } if (rc == NGX_DONE) { break; } if (rc == NGX_ERROR) { return NGX_ERROR; } } /* Get a zero length packet */ if (a->length == 0) { if (a->extra_zero_byte && (buf->pos < buf->last) && (*(buf->pos) == 0x00)) { buf->pos++; a->extra_zero_byte = 0; } continue; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0, "input filter packet, length:%z, buffer_size:%z", a->length, ngx_buf_size(buf)); if (p->free) { b = p->free->buf; p->free = p->free->next; } else { b = ngx_alloc_buf(p->pool); if (b == NULL) { return NGX_ERROR; } } ngx_memzero(b, sizeof(ngx_buf_t)); b->pos = buf->pos; b->start = buf->start; b->end = buf->end; b->tag = p->tag; b->temporary = 1; b->recycled = 1; *prev = b; prev = &b->shadow; cl = ngx_alloc_chain_link(p->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; if (p->in) { *p->last_in = cl; } else { p->in = cl; } p->last_in = &cl->next; /* STUB */ b->num = buf->num; if (buf->pos + a->length < buf->last) { buf->pos += a->length; b->last = buf->pos; a->length = 0; } else { a->length -= buf->last - buf->pos; buf->pos = buf->last; b->last = buf->last; } if (b->pos == b->last) { b->sync = 1; } if ((a->length == 0) && a->extra_zero_byte && (buf->pos < buf->last) && (*(buf->pos) == 0x00)) { /* The last byte of this message always seems to be * 0x00 and is not part of the chunk. */ buf->pos++; a->extra_zero_byte = 0; } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d %p size: %z", b->num, b->pos, b->last - b->pos); } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, "free buf %p %z", buf->pos, ngx_buf_size(buf)); if (alcf->keep_conn) { /* set p->length, minimal amount of data we want to see */ if (!a->length) { p->length = 1; } else { p->length = a->length; } if (p->upstream_done) { p->length = 0; } } if (b) { b->shadow = buf; b->last_shadow = 1; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf %p %z", b->pos, ngx_buf_size(buf)); return NGX_OK; } /* there is no data record in the buf, add it to free chain */ if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) { return NGX_ERROR; } return NGX_OK; }
static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) { u_char *prev; size_t bsize; ngx_int_t rc; ngx_uint_t flush, flushed, prev_last_shadow; ngx_chain_t *out, **ll, *cl, file; ngx_connection_t *downstream; downstream = p->downstream; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream: %d", downstream->write->ready); flushed = 0; for ( ;; ) { if (p->downstream_error) { return ngx_event_pipe_drain_chains(p); } if (p->upstream_eof || p->upstream_error || p->upstream_done) { /* pass the p->out and p->in chains to the output filter */ for (cl = p->busy; cl; cl = cl->next) { cl->buf->recycled = 0; } if (p->out) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream flush out"); for (cl = p->out; cl; cl = cl->next) { cl->buf->recycled = 0; } rc = p->output_filter(p->output_ctx, p->out); if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); } p->out = NULL; } if (p->in) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream flush in"); for (cl = p->in; cl; cl = cl->next) { cl->buf->recycled = 0; } rc = p->output_filter(p->output_ctx, p->in); if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); } p->in = NULL; } if (p->cacheable && p->buf_to_file) { file.buf = p->buf_to_file; file.next = NULL; if (ngx_write_chain_to_temp_file(p->temp_file, &file) == NGX_ERROR) { return NGX_ABORT; } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream done"); /* TODO: free unused bufs */ p->downstream_done = 1; break; } if (downstream->data != p->output_ctx || !downstream->write->ready || downstream->write->delayed) { break; } /* bsize is the size of the busy recycled bufs */ prev = NULL; bsize = 0; for (cl = p->busy; cl; cl = cl->next) { if (cl->buf->recycled) { if (prev == cl->buf->start) { continue; } bsize += cl->buf->end - cl->buf->start; prev = cl->buf->start; } } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write busy: %uz", bsize); out = NULL; if (bsize >= (size_t) p->busy_size) { flush = 1; goto flush; } flush = 0; ll = NULL; prev_last_shadow = 1; for ( ;; ) { if (p->out) { cl = p->out; if (cl->buf->recycled && bsize + cl->buf->last - cl->buf->pos > p->busy_size) { flush = 1; break; } p->out = p->out->next; ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs, cl->buf); } else if (!p->cacheable && p->in) { cl = p->in; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write buf ls:%d %p %z", cl->buf->last_shadow, cl->buf->pos, cl->buf->last - cl->buf->pos); if (cl->buf->recycled && cl->buf->last_shadow && bsize + cl->buf->last - cl->buf->pos > p->busy_size) { if (!prev_last_shadow) { p->in = p->in->next; cl->next = NULL; if (out) { *ll = cl; } else { out = cl; } } flush = 1; break; } prev_last_shadow = cl->buf->last_shadow; p->in = p->in->next; } else { break; } if (cl->buf->recycled) { bsize += cl->buf->last - cl->buf->pos; } cl->next = NULL; if (out) { *ll = cl; } else { out = cl; } ll = &cl->next; } flush: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write: out:%p, f:%d", out, flush); if (out == NULL) { if (!flush) { break; } /* a workaround for AIO */ if (flushed++ > 10) { return NGX_BUSY; } } rc = p->output_filter(p->output_ctx, out); if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); } ngx_chain_update_chains(&p->free, &p->busy, &out, p->tag); for (cl = p->free; cl; cl = cl->next) { if (cl->buf->temp_file) { if (p->cacheable || !p->cyclic_temp_file) { continue; } /* reset p->temp_offset if all bufs had been sent */ if (cl->buf->file_last == p->temp_file->offset) { p->temp_file->offset = 0; } } /* TODO: free buf if p->free_bufs && upstream done */ /* add the free shadow raw buf to p->free_raw_bufs */ if (cl->buf->last_shadow) { if (ngx_event_pipe_add_free_buf(p, cl->buf->shadow) != NGX_OK) { return NGX_ABORT; } cl->buf->last_shadow = 0; } cl->buf->shadow = NULL; } } return NGX_OK; }