static void ngx_http_groonga_context_receive_handler_raw(grn_ctx *context, int flags, ngx_http_groonga_handler_data_t *data) { char *chunk = NULL; unsigned int chunk_size = 0; int recv_flags; ngx_http_request_t *r; ngx_log_t *log; grn_bool is_last_chunk; grn_ctx_recv(context, &chunk, &chunk_size, &recv_flags); data->raw.processed = GRN_TRUE; if (data->raw.rc != NGX_OK) { return; } r = data->raw.r; log = r->connection->log; is_last_chunk = (flags & GRN_CTX_TAIL); if (!data->raw.header_sent) { ngx_http_groonga_handler_set_content_type(r, grn_ctx_get_mime_type(context)); r->headers_out.status = NGX_HTTP_OK; if (is_last_chunk) { r->headers_out.content_length_n = chunk_size; if (chunk_size == 0) { r->header_only = 1; } } else { r->headers_out.content_length_n = -1; } data->raw.rc = ngx_http_send_header(r); data->raw.header_sent = GRN_TRUE; if (data->raw.rc != NGX_OK) { return; } } if (chunk_size > 0 || is_last_chunk) { ngx_chain_t *chain; chain = ngx_chain_get_free_buf(r->pool, &(data->raw.free_chain)); if (!chain) { ngx_log_error(NGX_LOG_ERR, log, 0, "http_groonga: failed to allocate memory for chunked body"); data->raw.rc = NGX_ERROR; return; } if (chunk_size == 0) { chain->buf->pos = NULL; chain->buf->last = NULL; chain->buf->memory = 0; } else { chain->buf->pos = (u_char *)chunk; chain->buf->last = (u_char *)chunk + chunk_size; chain->buf->memory = 1; } chain->buf->tag = (ngx_buf_tag_t)&ngx_http_groonga_module; chain->buf->flush = 1; chain->buf->temporary = 0; chain->buf->in_file = 0; if (is_last_chunk) { chain->buf->last_buf = 1; } else { chain->buf->last_buf = 0; } chain->next = NULL; data->raw.rc = ngx_http_output_filter(r, chain); ngx_chain_update_chains(r->pool, &(data->raw.free_chain), &(data->raw.busy_chain), &chain, (ngx_buf_tag_t)&ngx_http_groonga_module); } }
ngx_int_t ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) { ngx_http_request_t *pr; ngx_http_lua_ctx_t *pr_ctx; ngx_http_lua_ctx_t *ctx; /* subrequest ctx */ ngx_http_lua_co_ctx_t *pr_coctx; size_t len; ngx_str_t *body_str; u_char *p; ngx_chain_t *cl; ngx_http_lua_post_subrequest_data_t *psr_data = data; ctx = psr_data->ctx; if (ctx->run_post_subrequest) { if (r != r->connection->data) { r->connection->data = r; } return NGX_OK; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run post subrequest handler, rc:%i c:%ud", rc, r->main->count); ctx->run_post_subrequest = 1; pr = r->parent; pr_ctx = ngx_http_get_module_ctx(pr, ngx_http_lua_module); if (pr_ctx == NULL) { return NGX_ERROR; } pr_coctx = psr_data->pr_co_ctx; pr_coctx->pending_subreqs--; if (pr_coctx->pending_subreqs == 0) { dd("all subrequests are done"); pr_ctx->no_abort = 0; pr_ctx->resume_handler = ngx_http_lua_subrequest_resume; pr_ctx->cur_co_ctx = pr_coctx; } if (pr_ctx->entered_content_phase) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua restoring write event handler"); pr->write_event_handler = ngx_http_lua_content_wev_handler; } else { pr->write_event_handler = ngx_http_core_run_phases; } dd("status rc = %d", (int) rc); dd("status headers_out.status = %d", (int) r->headers_out.status); dd("uri: %.*s", (int) r->uri.len, r->uri.data); /* capture subrequest response status */ pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; if (pr_coctx->sr_statuses[ctx->index] == 0) { if (rc == NGX_OK) { rc = NGX_HTTP_OK; } if (rc == NGX_ERROR) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } if (rc >= 100) { pr_coctx->sr_statuses[ctx->index] = rc; } } if (!ctx->seen_last_for_subreq) { pr_coctx->sr_flags[ctx->index] |= NGX_HTTP_LUA_SUBREQ_TRUNCATED; } dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ pr_coctx->sr_headers[ctx->index] = &r->headers_out; /* copy subrequest response body */ body_str = &pr_coctx->sr_bodies[ctx->index]; len = 0; for (cl = ctx->body; cl; cl = cl->next) { /* ignore all non-memory buffers */ len += cl->buf->last - cl->buf->pos; } body_str->len = len; if (len == 0) { body_str->data = NULL; } else { p = ngx_palloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } body_str->data = p; /* copy from and then free the data buffers */ for (cl = ctx->body; cl; cl = cl->next) { p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); cl->buf->last = cl->buf->pos; #if 0 dd("free body chain link buf ASAP"); ngx_pfree(r->pool, cl->buf->start); #endif } } if (ctx->body) { #if defined(nginx_version) && nginx_version >= 1001004 ngx_chain_update_chains(r->pool, #else ngx_chain_update_chains( #endif &pr_ctx->free_bufs, &pr_ctx->busy_bufs, &ctx->body, (ngx_buf_tag_t) &ngx_http_lua_module); dd("free bufs: %p", pr_ctx->free_bufs); }
static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) { size_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl, *out, *tl, **ll; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; rb = r->request_body; if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http request body chunked filter"); rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); if (rb->chunked == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_in.content_length_n = 0; rb->rest = 3; } out = NULL; ll = &out; for (cl = in; cl; cl = cl->next) { for ( ;; ) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body chunked buf " "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z", 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); rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked); if (rc == NGX_OK) { /* a chunk has been parsed successfully */ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->client_max_body_size && clcf->client_max_body_size < r->headers_in.content_length_n + rb->chunked->size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client intended to send too large chunked " "body: %O bytes", r->headers_in.content_length_n + rb->chunked->size); r->lingering_close = 1; return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; } tl = ngx_chain_get_free_buf(r->pool, &rb->free); if (tl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = tl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->temporary = 1; b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body; b->start = cl->buf->pos; b->pos = cl->buf->pos; b->last = cl->buf->last; b->end = cl->buf->end; *ll = tl; ll = &tl->next; size = cl->buf->last - cl->buf->pos; if ((off_t) size > rb->chunked->size) { cl->buf->pos += rb->chunked->size; r->headers_in.content_length_n += rb->chunked->size; rb->chunked->size = 0; } else { rb->chunked->size -= size; r->headers_in.content_length_n += size; cl->buf->pos = cl->buf->last; } b->last = cl->buf->pos; continue; } if (rc == NGX_DONE) { /* a whole response has been parsed successfully */ rb->rest = 0; tl = ngx_chain_get_free_buf(r->pool, &rb->free); if (tl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = tl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->last_buf = 1; *ll = tl; ll = &tl->next; break; } if (rc == NGX_AGAIN) { /* set rb->rest, amount of data we want to see next time */ rb->rest = rb->chunked->length; break; } /* invalid */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid chunked body"); return NGX_HTTP_BAD_REQUEST; } } rc = ngx_http_request_body_save_filter(r, out); ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, (ngx_buf_tag_t) &ngx_http_read_client_request_body); return rc; }
static ngx_int_t ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc; ngx_chain_t *cl; ngx_http_gunzip_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_gunzip_filter_module); if (ctx == NULL || ctx->done) { return ngx_http_next_body_filter(r, in); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http gunzip filter"); if (!ctx->started) { if (ngx_http_gunzip_filter_inflate_start(r, ctx) != NGX_OK) { goto failed; } } if (in) { if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { goto failed; } } if (ctx->nomem) { /* flush busy buffers */ if (ngx_http_next_body_filter(r, NULL) == NGX_ERROR) { goto failed; } cl = NULL; ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl, (ngx_buf_tag_t) &ngx_http_gunzip_filter_module); ctx->nomem = 0; } for ( ;; ) { /* cycle while we can write to a client */ for ( ;; ) { /* cycle while there is data to feed zlib and ... */ rc = ngx_http_gunzip_filter_add_data(r, ctx); if (rc == NGX_DECLINED) { break; } if (rc == NGX_AGAIN) { continue; } /* ... there are buffers to write zlib output */ rc = ngx_http_gunzip_filter_get_buf(r, ctx); if (rc == NGX_DECLINED) { break; } if (rc == NGX_ERROR) { goto failed; } rc = ngx_http_gunzip_filter_inflate(r, ctx); if (rc == NGX_OK) { break; } if (rc == NGX_ERROR) { goto failed; } /* rc == NGX_AGAIN */ } if (ctx->out == NULL) { return ctx->busy ? NGX_AGAIN : NGX_OK; } rc = ngx_http_next_body_filter(r, ctx->out); if (rc == NGX_ERROR) { goto failed; } ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &ctx->out, (ngx_buf_tag_t) &ngx_http_gunzip_filter_module); ctx->last_out = &ctx->out; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "gunzip out: %p", ctx->out); ctx->nomem = 0; if (ctx->done) { return rc; } } /* unreachable */ failed: ctx->done = 1; return NGX_ERROR; }
static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) { size_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl, *tl, *out, **ll; ngx_http_request_body_t *rb; rb = r->request_body; if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http request body content length filter"); rb->rest = r->headers_in.content_length_n; } out = NULL; ll = &out; for (cl = in; cl; cl = cl->next) { tl = ngx_chain_get_free_buf(r->pool, &rb->free); if (tl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = tl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->temporary = 1; b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body; b->start = cl->buf->pos; b->pos = cl->buf->pos; b->last = cl->buf->last; b->end = cl->buf->end; size = cl->buf->last - cl->buf->pos; if ((off_t) size < rb->rest) { cl->buf->pos = cl->buf->last; rb->rest -= size; } else { cl->buf->pos += rb->rest; rb->rest = 0; b->last = cl->buf->pos; b->last_buf = 1; } *ll = tl; ll = &tl->next; } rc = ngx_http_request_body_save_filter(r, out); ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, (ngx_buf_tag_t) &ngx_http_read_client_request_body); return rc; }