static apr_status_t send_out(h2_task *task, apr_bucket_brigade* bb, int block) { apr_off_t written, left; apr_status_t status; apr_brigade_length(bb, 0, &written); H2_TASK_OUT_LOG(APLOG_TRACE2, task, bb, "h2_task send_out"); h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "send_out(before)"); /* engines send unblocking */ status = h2_beam_send(task->output.beam, bb, block? APR_BLOCK_READ : APR_NONBLOCK_READ); h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "send_out(after)"); if (APR_STATUS_IS_EAGAIN(status)) { apr_brigade_length(bb, 0, &left); written -= left; status = APR_SUCCESS; } if (status == APR_SUCCESS) { if (h2_task_logio_add_bytes_out) { h2_task_logio_add_bytes_out(task->c, written); } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, task->c, "h2_task(%s): send_out done", task->id); } else { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c, "h2_task(%s): send_out (%ld bytes)", task->id, (long)written); } return status; }
apr_status_t h2_io_in_read(h2_io *io, apr_bucket_brigade *bb, apr_size_t maxlen) { apr_off_t start_len = 0; apr_bucket *last; apr_status_t status; if (io->rst_error) { return APR_ECONNABORTED; } if (!io->bbin || APR_BRIGADE_EMPTY(io->bbin)) { return io->eos_in? APR_EOF : APR_EAGAIN; } apr_brigade_length(bb, 1, &start_len); last = APR_BRIGADE_LAST(bb); status = h2_util_move(bb, io->bbin, maxlen, NULL, "h2_io_in_read"); if (status == APR_SUCCESS) { apr_bucket *nlast = APR_BRIGADE_LAST(bb); apr_off_t end_len = 0; apr_brigade_length(bb, 1, &end_len); if (last == nlast) { return APR_EAGAIN; } io->input_consumed += (end_len - start_len); } return status; }
apr_status_t h2_conn_io_consider_flush(h2_conn_io *io) { apr_status_t status = APR_SUCCESS; int flush_now = 0; /* The HTTP/1.1 network output buffer/flush behaviour does not * give optimal performance in the HTTP/2 case, as the pattern of * buckets (data/eor/eos) is different. * As long as we do not have found out the "best" way to deal with * this, force a flush at least every WRITE_BUFFER_SIZE amount * of data which seems to work nicely. */ if (io->unflushed) { apr_off_t len = 0; if (!APR_BRIGADE_EMPTY(io->output)) { apr_brigade_length(io->output, 0, &len); } len += io->buflen; flush_now = (len >= WRITE_BUFFER_SIZE); } if (flush_now) { return h2_conn_io_flush(io); } return status; }
static apr_status_t pass_out(apr_bucket_brigade *bb, void *ctx) { h2_conn_io *io = (h2_conn_io*)ctx; apr_status_t status; apr_off_t bblen; if (APR_BRIGADE_EMPTY(bb)) { return APR_SUCCESS; } ap_update_child_status(io->connection->sbh, SERVER_BUSY_WRITE, NULL); status = apr_brigade_length(bb, 0, &bblen); if (status == APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, io->connection, "h2_conn_io(%ld): pass_out brigade %ld bytes", io->connection->id, (long)bblen); status = ap_pass_brigade(io->connection->output_filters, bb); if (status == APR_SUCCESS) { io->bytes_written += (apr_size_t)bblen; io->last_write = apr_time_now(); } apr_brigade_cleanup(bb); } return status; }
APU_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb, char **c, apr_size_t *len, apr_pool_t *pool) { apr_off_t actual; apr_size_t total; apr_status_t rv; apr_brigade_length(bb, 1, &actual); /* XXX: This is dangerous beyond belief. At least in the * apr_brigade_flatten case, the user explicitly stated their * buffer length - so we don't up and palloc 4GB for a single * file bucket. This API must grow a useful max boundry, * either compiled-in or preset via the *len value. * * Shouldn't both fn's grow an additional return value for * the case that the brigade couldn't be flattened into the * provided or allocated buffer (such as APR_EMOREDATA?) * Not a failure, simply an advisory result. */ total = (apr_size_t)actual; *c = apr_palloc(pool, total); rv = apr_brigade_flatten(bb, *c, &total); if (rv != APR_SUCCESS) { return rv; } *len = total; return APR_SUCCESS; }
static int brigade_flatten(lua_State*L) { apr_bucket_brigade *bb = (apr_bucket_brigade*)CHECK_BUCKETBRIGADE_OBJECT(1); apr_off_t off = 0; apr_status_t rc = apr_brigade_length(bb, 1, &off); apr_size_t len = (apr_size_t)off; if(rc==APR_SUCCESS) { char* buf = apr_bucket_alloc(len, bb->bucket_alloc); rc = apr_brigade_flatten(bb, buf, &len); if(rc==APR_SUCCESS) { lua_pushlstring(L,buf, len); }else { lua_pushnil(L); } apr_bucket_free(buf); }else { lua_pushnil(L); } lua_pushinteger(L,rc); return 2; }
static llzr_conn* get_post_data(request_rec* r) { GTable *request_post_data = g_hash_table_new(g_str_hash, g_str_equal); apr_array_header_t *pairs = NULL; apr_off_t len; apr_size_t size; int res; char *buffer; res = ap_parse_form_data(r, NULL, &pairs, -1, HUGE_STRING_LEN); if (res != OK || !pairs) return NULL; /* Return NULL if we failed or if there are is no POST data */ while (pairs && !apr_is_empty_array(pairs)) { ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs); apr_brigade_length(pair->value, 1, &len); size = (apr_size_t) len; buffer = apr_palloc(r->pool, size + 1); apr_brigade_flatten(pair->value, buffer, &size); buffer[len] = 0; g_hash_table_insert( request_post_data, apr_pstrdup(r->pool, pair->name), buffer); } return request_post_data; }
Params *getPostParms(request_rec *r, apr_off_t * postSize) { apr_array_header_t *pairs = NULL; apr_off_t len; apr_size_t size; int res; int i = 0; char *buffer; Params *params = NULL; res = ap_parse_form_data(r, NULL, &pairs, -1, HUGE_STRING_LEN); if (res != OK || !pairs) return NULL; params = apr_pcalloc(r->pool, sizeof(Params) * (pairs->nelts + 1)); while (pairs && !apr_is_empty_array(pairs)) { ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs); apr_brigade_length(pair->value, 1, &len); size = (apr_size_t) len; buffer = apr_palloc(r->pool, size + 1); apr_brigade_flatten(pair->value, buffer, &size); buffer[len] = 0; params[i].key = apr_pstrdup(r->pool, pair->name); params[i].val = buffer; params[i].length = strlen(buffer); //ap_rprintf(r,"key : val : len: is %s : %s : %d ===", params[i].key, params[i].val, params[i].length); i++; } *postSize = i; return params; }
apr_size_t h2_io_out_length(h2_io *io) { if (io->bbout) { apr_off_t len = 0; apr_brigade_length(io->bbout, 0, &len); return (len > 0)? len : 0; } return 0; }
// This is the method which does all the work handling the uploads. It's only // triggered by the fixup filter if +porter_should_rewrite_body+ returns true. apr_status_t porter_process_upload(request_rec *r) { porter_server_conf *config = (porter_server_conf *) ap_get_module_config(r->server->module_config, &porter_module); // Prepare the apreq objects. apreq_handle_t *req = apreq_handle_apache2(r); const apr_table_t *request_body = apreq_params(req, r->pool); // Create our upload request object, this is fleshed out by the rest of this method porter_upload_request_t *upload_request = porter_create_request(req, r, config); // This happens with malformed requests. apreq_params should never return null // when the content-length is > 0 and it's a multipart request. So just assume // it's broken and return bad request. Otherwise subsequent method calls will // cause a segfault if (request_body == NULL) { PORTER_LOG_REQUEST_ERROR("Invalid request body"); return HTTP_BAD_REQUEST; } // loop over each parameter provided by the user (see porter_each_parameter) apr_table_do(porter_each_parameter, upload_request, request_body, NULL); // If any of the parameter handlers return an error, they save the error code // in the upload_request. So return that same error code. if (upload_request->status != APR_SUCCESS) { return upload_request->status; } // Just because the content type is multipart and the content-length was > 0 doesn't // mean that the user actually uploaded any files. If they didn't, just return success // and let the original body be passed upstream. if (!apr_is_empty_array(upload_request->param_names)) { // Write the parameter names to the X-Uploads header (comma seperated) const char *upload_parameters = apr_array_pstrcat(r->pool, upload_request->param_names, ','); apr_off_t len; apr_table_setn(r->headers_in, HTTP_X_UPLOADS, upload_parameters); // figure out the length of the newly rewritten body and set it in the request // along with the right content type. apr_brigade_length(upload_request->bucket_brigade, 0, &len); apr_table_setn(r->headers_in, "Content-Length", apr_itoa(r->pool, len)); apr_table_setn(r->headers_in, "Content-Type", "application/x-www-form-urlencoded"); // Add our input filter to the filter chain, this allows // us to replace the request body with our own one, and ensure that // gets passed down to the handler. ap_add_input_filter_handle(porter_input_filter_handle, upload_request, r, r->connection); } return APR_SUCCESS; }
static void bind_post(int *count, lily_parse_state *parser, request_rec *r) { if (*count == -1) return; lily_var *post_var = bind_hash_str_str_var(parser->symtab, "post"); lily_hash_val *hash_val = post_var->value.hash; apr_array_header_t *pairs; apr_off_t len; apr_size_t size; char *buffer; char *sipkey = parser->vm->sipkey; lily_class *string_cls = lily_class_by_id(parser->symtab, SYM_CLASS_STRING); lily_sig *string_sig = string_cls->sig; /* Credit: I found out how to use this by reading httpd 2.4's mod_lua (specifically req_parsebody of lua_request.c). */ int res = ap_parse_form_data(r, NULL, &pairs, -1, 1024 * 8); if (res == OK) { while (pairs && !apr_is_empty_array(pairs)) { ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs); apr_brigade_length(pair->value, 1, &len); size = (apr_size_t) len; buffer = lily_malloc(size + 1); if (buffer == NULL) { *count = -1; return; } apr_brigade_flatten(pair->value, buffer, &size); buffer[len] = 0; lily_value *elem_key = bind_string(string_sig, pair->name); /* Give the buffer to the value to save memory. */ lily_value *elem_value = bind_string_and_buffer(string_sig, buffer); lily_hash_elem *new_elem = bind_hash_elem_with_values(sipkey, elem_key, elem_value); if (elem_key == NULL || elem_value == NULL || new_elem == NULL) { lily_free(new_elem); deref_destroy_value(elem_key); deref_destroy_value(elem_value); *count = -1; return; } new_elem->next = hash_val->elem_chain; hash_val->elem_chain = new_elem; } } (*count)++; }
static int brigade_length(lua_State*L) { apr_bucket_brigade *bb = (apr_bucket_brigade*)CHECK_BUCKETBRIGADE_OBJECT(1); int read_all = lua_isnoneornil(L,2) ? 1 : lua_toboolean(L, 2); apr_off_t length = 0; apr_status_t rc = apr_brigade_length(bb, read_all, &length); lua_pushinteger(L, (lua_Integer)length); lua_pushinteger(L, rc); return 2; }
/** * Initialisation of filter to handle a kept body on subrequests. * * If a body is to be reinserted into a subrequest, any chunking will have * been removed from the body during storage. We need to change the request * from Transfer-Encoding: chunked to an explicit Content-Length. */ static int kept_body_filter_init(ap_filter_t *f) { apr_off_t length = 0; request_rec *r = f->r; apr_bucket_brigade *kept_body = r->kept_body; if (kept_body) { apr_table_unset(r->headers_in, "Transfer-Encoding"); apr_brigade_length(kept_body, 1, &length); apr_table_setn(r->headers_in, "Content-Length", apr_off_t_toa(r->pool, length)); } return OK; }
apr_status_t h2_util_bb_avail(apr_bucket_brigade *bb, apr_size_t *plen, int *peos) { apr_status_t status; /* test read to determine available length */ apr_off_t blen = 0; status = apr_brigade_length(bb, 0, &blen); if (blen < (apr_off_t)*plen) { *plen = blen; } *peos = h2_util_has_eos(bb, *plen); return status; }
static int proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o, apr_bucket_brigade *bb, char *name) { int rv; #ifdef DEBUGGING apr_off_t len; #endif do { apr_brigade_cleanup(bb); rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES, APR_NONBLOCK_READ, AP_IOBUFSIZE); if (rv == APR_SUCCESS) { if (c_o->aborted) { return APR_EPIPE; } if (APR_BRIGADE_EMPTY(bb)) { break; } #ifdef DEBUGGING len = -1; apr_brigade_length(bb, 0, &len); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02440) "read %" APR_OFF_T_FMT " bytes from %s", len, name); #endif rv = ap_pass_brigade(c_o->output_filters, bb); if (rv == APR_SUCCESS) { ap_fflush(c_o->output_filters, bb); } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02441) "error on %s - ap_pass_brigade", name); } } else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(02442) "error on %s - ap_get_brigade", name); } } while (rv == APR_SUCCESS); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r, "wstunnel_transfer complete"); if (APR_STATUS_IS_EAGAIN(rv)) { rv = APR_SUCCESS; } return rv; }
int output_finalize_bb (output_t* output, apr_table_t* out_headers){ apr_status_t rv; apr_bucket* eos_bucket; eos_bucket = apr_bucket_eos_create(output->bucket_allocator); APR_BRIGADE_INSERT_TAIL(output->bucket_brigade, eos_bucket); apr_table_overlap(out_headers, output->headers, APR_OVERLAP_TABLES_SET); rv = apr_brigade_length(output->bucket_brigade,1,&(output->length)); return rv; }
apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, apr_size_t maxlen, int *pfile_handles_allowed) { apr_status_t status; int start_allowed; if (io->rst_error) { return APR_ECONNABORTED; } if (io->eos_out) { apr_off_t len; /* We have already delivered an EOS bucket to a reader, no * sense in storing anything more here. */ status = apr_brigade_length(bb, 1, &len); if (status == APR_SUCCESS) { if (len > 0) { /* someone tries to write real data after EOS, that * does not look right. */ status = APR_EOF; } /* cleanup, as if we had moved the data */ apr_brigade_cleanup(bb); } return status; } /* Let's move the buckets from the request processing in here, so * that the main thread can read them when it has time/capacity. * * Move at most "maxlen" memory bytes. If buckets remain, it is * the caller's responsibility to take care of this. * * We allow passing of file buckets as long as we do not have too * many open files already buffered. Otherwise we will run out of * file handles. */ start_allowed = *pfile_handles_allowed; status = h2_util_move(io->bbout, bb, maxlen, pfile_handles_allowed, "h2_io_out_write"); /* track # file buckets moved into our pool */ if (start_allowed != *pfile_handles_allowed) { io->files_handles_owned += (start_allowed - *pfile_handles_allowed); } return status; }
/** var post: Hash[String, Tainted[String]] This contains key+value pairs that were sent to the server as POST variables. Any pair that has a key or a value that is not valid utf-8 will not be present. */ static lily_value *load_var_post(lily_options *options, uint16_t *unused) { lily_value *v = lily_new_empty_value(); lily_move_hash_f(MOVE_DEREF_NO_GC, v, lily_new_hash_val()); lily_hash_val *hash_val = v->value.hash; request_rec *r = (request_rec *)options->data; apr_array_header_t *pairs; apr_off_t len; apr_size_t size; char *buffer; /* Credit: I found out how to use this by reading httpd 2.4's mod_lua (specifically req_parsebody of lua_request.c). */ int res = ap_parse_form_data(r, NULL, &pairs, -1, 1024 * 8); if (res == OK) { while (pairs && !apr_is_empty_array(pairs)) { ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs); if (lily_is_valid_utf8(pair->name) == 0) continue; apr_brigade_length(pair->value, 1, &len); size = (apr_size_t) len; buffer = lily_malloc(size + 1); if (lily_is_valid_utf8(buffer) == 0) { lily_free(buffer); continue; } apr_brigade_flatten(pair->value, buffer, &size); buffer[len] = 0; lily_value *elem_key = lily_new_string(pair->name); /* Give the buffer to the value to save memory. */ lily_value *elem_raw_value = lily_new_string_take(buffer); lily_value *elem_value = bind_tainted_of(elem_raw_value); apache_add_unique_hash_entry(options->sipkey, hash_val, elem_key, elem_value); } } return v; }
static apr_status_t logio_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { apr_off_t length; apr_status_t status; logio_config_t *cf = ap_get_module_config(f->c->conn_config, &logio_module); status = ap_get_brigade(f->next, bb, mode, block, readbytes); apr_brigade_length (bb, 0, &length); if (length > 0) cf->bytes_in += length; return status; }
static void test_bwrite(abts_case *tc, void *data) { apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); apr_bucket_brigade *bb = apr_brigade_create(p, ba); apr_off_t length; int n; for (n = 0; n < COUNT; n++) { apr_assert_success(tc, "brigade_write", apr_brigade_write(bb, NULL, NULL, THESTR, sizeof THESTR)); } apr_assert_success(tc, "determine brigade length", apr_brigade_length(bb, 1, &length)); ABTS_ASSERT(tc, "brigade has correct length", length == (COUNT * sizeof THESTR)); apr_brigade_destroy(bb); apr_bucket_alloc_destroy(ba); }
PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc, request_rec *r, proxy_conn_rec *p_conn, conn_rec *origin, apr_bucket_brigade *bb, int flush) { apr_status_t status; apr_off_t transferred; if (flush) { apr_bucket *e = apr_bucket_flush_create(bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); } apr_brigade_length(bb, 0, &transferred); if (transferred != -1) p_conn->worker->s->transferred += transferred; status = ap_pass_brigade(origin->output_filters, bb); if (status != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, "AH01084: " "pass request body failed to %pI (%s)", p_conn->addr, p_conn->hostname); if (origin->aborted) { const char *ssl_note; if (((ssl_note = apr_table_get(origin->notes, "SSL_connect_rv")) != NULL) && (strcmp(ssl_note, "err") == 0)) { return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, "Error during SSL Handshake with" " remote server"); } return APR_STATUS_IS_TIMEUP(status) ? HTTP_GATEWAY_TIME_OUT : HTTP_BAD_GATEWAY; } else { return HTTP_BAD_REQUEST; } } apr_brigade_cleanup(bb); return OK; }
static int track_upload_progress(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { apr_status_t rv; upload_progress_node_t *node; ServerConfig* config = get_server_config(f->r); if ((rv = ap_get_brigade(f->next, bb, mode, block, readbytes)) != APR_SUCCESS) { return rv; } apr_off_t length; apr_brigade_length(bb, 1, &length); const char* id = get_progress_id(f->r); if(id == NULL) return APR_SUCCESS; CACHE_LOCK(); node = find_node(f->r, id); CACHE_UNLOCK(); if(node == NULL) { return APR_SUCCESS; } else { CACHE_LOCK(); node->received += (int)length; int upload_time = time(NULL) - node->started_at; if(upload_time > 0) { node->speed = (int)(node->received / upload_time); } CACHE_UNLOCK(); } return APR_SUCCESS; }
static ngx_int_t ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_modsecurity_loc_conf_t *cf; ngx_http_modsecurity_ctx_t *ctx; ngx_int_t rc; apr_off_t content_length; ngx_chain_t *cl, *out; ngx_int_t last_buf = 0; cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity); ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); if (r != r->main || !cf->enable || ctx == NULL || ctx->complete) { return ngx_http_next_body_filter(r, in); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: body filter"); for (cl = in; cl; cl = cl->next) { apr_bucket *e; ngx_buf_t *buf = cl->buf; apr_bucket_brigade *bb = ctx->brigade; off_t size = ngx_buf_size(buf); if (size) { char *data = apr_pmemdup(bb->p, buf->pos, size); if (data == NULL) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } e = apr_bucket_pool_create(data , size, bb->p, bb->bucket_alloc); if (e == NULL) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } APR_BRIGADE_INSERT_TAIL(bb, e); } if (buf->last_buf) { last_buf = 1; buf->last_buf = 0; e = apr_bucket_eos_create(bb->bucket_alloc); if (e == NULL) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } APR_BRIGADE_INSERT_TAIL(bb, e); break; } buf->pos = buf->last; } if (!last_buf) { return NGX_AGAIN; } /* last buf has been saved */ ctx->complete = 1; modsecSetResponseBrigade(ctx->req, ctx->brigade); if (ngx_http_modsecurity_load_headers_in(r) != NGX_OK || ngx_http_modsecurity_load_headers_out(r) != NGX_OK) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } rc = ngx_http_modsecurity_status(r, modsecProcessResponse(ctx->req)); if (rc != NGX_DECLINED) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, rc); } apr_brigade_length(ctx->brigade, 0, &content_length); rc = move_brigade_to_chain(ctx->brigade, &out, r->pool); if (rc == NGX_ERROR) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } if (ngx_http_modsecurity_save_headers_in(r) != NGX_OK ||ngx_http_modsecurity_save_headers_out(r) != NGX_OK) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } if (r->headers_out.content_length_n != -1) { r->headers_out.content_length_n = content_length; r->headers_out.content_length = NULL; /* header filter will set this */ } r->header_sent = 0; rc = ngx_http_next_header_filter(r); if (rc == NGX_ERROR || rc > NGX_OK) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, rc); } return ngx_http_next_body_filter(r, out); }
static int pgasp_handler (request_rec * r) { char cursor_string[256]; pgasp_config* config = (pgasp_config*) ap_get_module_config(r->server->module_config, &pgasp_module ) ; pgasp_dir_config* dir_config = (pgasp_dir_config*) ap_get_module_config(r->per_dir_config, &pgasp_module ) ; apr_table_t * GET = NULL, *GETargs = NULL; apr_array_header_t * POST; PGconn * pgc; PGresult * pgr; int i, j, allowed_to_serve, filename_length = 0; int field_count, tuple_count; char * requested_file; char *basename; params_t params; /* PQexecParams doesn't seem to like zero-length strings, so we feed it a dummy */ const char * dummy_get = "nothing"; const char * dummy_user = "******"; const char * cursor_values[2] = { r -> args ? apr_pstrdup(r->pool, r -> args) : dummy_get, r->user ? r->user : dummy_user }; int cursor_value_lengths[2] = { strlen(cursor_values[0]), strlen(cursor_values[1]) }; int cursor_value_formats[2] = { 0, 0 }; if (!r -> handler || strcmp (r -> handler, "pgasp-handler") ) return DECLINED; if (!r -> method || (strcmp (r -> method, "GET") && strcmp (r -> method, "POST")) ) return DECLINED; if (config->is_enabled != true) return OK; /* pretending we have responded, may return DECLINED in the future */ requested_file = apr_pstrdup (r -> pool, r -> path_info /*filename*/); i = strlen(requested_file) - 1; while (i > 0) { if (requested_file[i] == '.') filename_length = i; if (requested_file[i] == '/') break; i--; } if (i >= 0) { requested_file += i+1; /* now pointing to foo.pgasp instead of /var/www/.../foo.pgasp */ if (filename_length > i) filename_length -= i+1; } allowed_to_serve = false; for (i = 0; i < config->allowed_count; i++) { if (!strcmp(config->allowed[i], requested_file)) { allowed_to_serve = true; break; } } if (config->allowed_count == 0) allowed_to_serve = true; if (!allowed_to_serve) { ap_set_content_type(r, "text/plain"); ap_rprintf(r, "Hello there\nThis is PGASP\nEnabled: %s\n", config->is_enabled ? "On" : "Off"); ap_rprintf(r, "Requested: %s\n", requested_file); ap_rprintf(r, "Allowed: %s\n", allowed_to_serve ? "Yes" : "No"); return OK; /* pretending we have served the file, may return HTTP_FORDIDDEN in the future */ } if (filename_length == 0) { basename = requested_file; } else { basename = apr_pstrndup(r->pool, requested_file, filename_length); } ap_args_to_table(r, &GETargs); if (OK != ap_parse_form_data(r, NULL, &POST, -1, (~((apr_size_t)0)))) { __(r->server, " ** ap_parse_form_data is NOT OK"); } GET = (NULL == GET) ? GETargs : apr_table_overlay(r->pool, GETargs, GET); // move all POST parameters into GET table { ap_form_pair_t *pair; char *buffer; apr_off_t len; apr_size_t size; while (NULL != (pair = apr_array_pop(POST))) { apr_brigade_length(pair->value, 1, &len); size = (apr_size_t) len; buffer = apr_palloc(r->pool, size + 1); apr_brigade_flatten(pair->value, buffer, &size); buffer[len] = 0; apr_table_setn(GET, apr_pstrdup(r->pool, pair->name), buffer); //should name and value be ap_unescape_url() -ed? // __(r->server, "POST[%s]: %s", pair->name, buffer); } } params.r = r; params.args = NULL; apr_table_do(tab_args, ¶ms, GET, NULL); params.args = apr_pstrcat(r->pool, "&", params.args, "&", NULL); cursor_values[0] = params.args; cursor_value_lengths[0] = strlen(cursor_values[0]); /* set response content type according to configuration or to default value */ ap_set_content_type(r, dir_config->content_type_set ? dir_config->content_type : "text/html"); /* now connecting to Postgres, getting function output, and printing it */ pgc = pgasp_pool_open (r->server); if (PQstatus(pgc) != CONNECTION_OK) { spit_pg_error ("connect"); pgasp_pool_close(r->server, pgc); return OK; } /* removing extention (.pgasp or other) from file name, and adding "f_" for function name, i.e. foo.pgasp becomes psp_foo() */ snprintf(cursor_string, sizeof(cursor_string), "select * from f_%s($1::varchar)", basename); /* passing GET as first (and only) parameter */ if (0 == PQsendQueryParams (pgc, cursor_string, 1, NULL, cursor_values, cursor_value_lengths, cursor_value_formats, 0)) { spit_pg_error ("sending async query with params"); return clean_up_connection(r->server); } if (0 == PQsetSingleRowMode(pgc)) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "can not fall into single raw mode to fetch data"); } while (NULL != (pgr = PQgetResult(pgc))) { if (PQresultStatus(pgr) != PGRES_TUPLES_OK && PQresultStatus(pgr) != PGRES_SINGLE_TUPLE) { spit_pg_error ("fetch data"); return clean_up_connection(r->server); } /* the following counts and for-loop may seem excessive as it's just 1 row/1 field, but might need it in the future */ field_count = PQnfields(pgr); tuple_count = PQntuples(pgr); for (i = 0; i < tuple_count; i++) { for (j = 0; j < field_count; j++) ap_rprintf(r, "%s", PQgetvalue(pgr, i, j)); ap_rprintf(r, "\n"); } PQclear (pgr); } pgasp_pool_close(r->server, pgc); return OK; }
static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, apr_bucket_brigade *bbout, apr_off_t start, apr_off_t end) { apr_bucket *first = NULL, *last = NULL, *out_first = NULL, *e; apr_uint64_t pos = 0, off_first = 0, off_last = 0; apr_status_t rv; apr_uint64_t start64, end64; apr_off_t pofft = 0; /* * Once we know that start and end are >= 0 convert everything to apr_uint64_t. * See the comments in apr_brigade_partition why. * In short apr_off_t (for values >= 0)and apr_size_t fit into apr_uint64_t. */ start64 = (apr_uint64_t)start; end64 = (apr_uint64_t)end; if (start < 0 || end < 0 || start64 > end64) return APR_EINVAL; for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { apr_uint64_t elen64; /* we know that no bucket has undefined length (-1) */ AP_DEBUG_ASSERT(e->length != (apr_size_t)(-1)); elen64 = (apr_uint64_t)e->length; if (!first && (elen64 + pos > start64)) { first = e; off_first = pos; } if (elen64 + pos > end64) { last = e; off_last = pos; break; } pos += elen64; } if (!first || !last) return APR_EINVAL; e = first; while (1) { apr_bucket *copy; AP_DEBUG_ASSERT(e != APR_BRIGADE_SENTINEL(bb)); rv = apr_bucket_copy(e, ©); if (rv != APR_SUCCESS) { apr_brigade_cleanup(bbout); return rv; } APR_BRIGADE_INSERT_TAIL(bbout, copy); if (e == first) { if (off_first != start64) { rv = apr_bucket_split(copy, (apr_size_t)(start64 - off_first)); if (rv != APR_SUCCESS) { apr_brigade_cleanup(bbout); return rv; } out_first = APR_BUCKET_NEXT(copy); APR_BUCKET_REMOVE(copy); apr_bucket_destroy(copy); } else { out_first = copy; } } if (e == last) { if (e == first) { off_last += start64 - off_first; copy = out_first; } if (end64 - off_last != (apr_uint64_t)e->length) { rv = apr_bucket_split(copy, (apr_size_t)(end64 + 1 - off_last)); if (rv != APR_SUCCESS) { apr_brigade_cleanup(bbout); return rv; } copy = APR_BUCKET_NEXT(copy); if (copy != APR_BRIGADE_SENTINEL(bbout)) { APR_BUCKET_REMOVE(copy); apr_bucket_destroy(copy); } } break; } e = APR_BUCKET_NEXT(e); } AP_DEBUG_ASSERT(APR_SUCCESS == apr_brigade_length(bbout, 1, &pofft)); pos = (apr_uint64_t)pofft; AP_DEBUG_ASSERT(pos == end64 - start64 + 1); return APR_SUCCESS; }
static apr_status_t rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *bb) { apr_status_t rv = APR_SUCCESS; rl_ctx_t *ctx = f->ctx; apr_bucket_alloc_t *ba = f->r->connection->bucket_alloc; /* Set up our rl_ctx_t on first use */ if (ctx == NULL) { const char *rl = NULL; int ratelimit; int burst = 0; /* no subrequests. */ if (f->r->main != NULL) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* Configuration: rate limit */ rl = apr_table_get(f->r->subprocess_env, "rate-limit"); if (rl == NULL) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* rl is in kilo bytes / second */ ratelimit = atoi(rl) * 1024; if (ratelimit <= 0) { /* remove ourselves */ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(03488) "rl: disabling: rate-limit = %s (too high?)", rl); ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* Configuration: optional initial burst */ rl = apr_table_get(f->r->subprocess_env, "rate-initial-burst"); if (rl != NULL) { burst = atoi(rl) * 1024; if (burst <= 0) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(03489) "rl: disabling burst: rate-initial-burst = %s (too high?)", rl); burst = 0; } } /* Set up our context */ ctx = apr_palloc(f->r->pool, sizeof(rl_ctx_t)); f->ctx = ctx; ctx->state = RATE_LIMIT; ctx->speed = ratelimit; ctx->burst = burst; ctx->do_sleep = 0; /* calculate how many bytes / interval we want to send */ /* speed is bytes / second, so, how many (speed / 1000 % interval) */ ctx->chunk_size = (ctx->speed / (1000 / RATE_INTERVAL_MS)); ctx->tmpbb = apr_brigade_create(f->r->pool, ba); ctx->holdingbb = apr_brigade_create(f->r->pool, ba); } else { APR_BRIGADE_PREPEND(bb, ctx->holdingbb); } while (!APR_BRIGADE_EMPTY(bb)) { apr_bucket *e; if (ctx->state == RATE_FULLSPEED) { /* Find where we 'stop' going full speed. */ for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { if (AP_RL_BUCKET_IS_END(e)) { apr_brigade_split_ex(bb, e, ctx->holdingbb); ctx->state = RATE_LIMIT; break; } } e = apr_bucket_flush_create(ba); APR_BRIGADE_INSERT_TAIL(bb, e); rv = ap_pass_brigade(f->next, bb); apr_brigade_cleanup(bb); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01455) "rl: full speed brigade pass failed."); return rv; } } else { for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { if (AP_RL_BUCKET_IS_START(e)) { apr_brigade_split_ex(bb, e, ctx->holdingbb); ctx->state = RATE_FULLSPEED; break; } } while (!APR_BRIGADE_EMPTY(bb)) { apr_off_t len = ctx->chunk_size + ctx->burst; APR_BRIGADE_CONCAT(ctx->tmpbb, bb); /* * Pull next chunk of data; the initial amount is our * burst allotment (if any) plus a chunk. All subsequent * iterations are just chunks with whatever remaining * burst amounts we have left (in case not done in the * first bucket). */ rv = apr_brigade_partition(ctx->tmpbb, len, &e); if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01456) "rl: partition failed."); return rv; } /* Send next metadata now if any */ while (e != APR_BRIGADE_SENTINEL(ctx->tmpbb) && APR_BUCKET_IS_METADATA(e)) { e = APR_BUCKET_NEXT(e); } if (e != APR_BRIGADE_SENTINEL(ctx->tmpbb)) { apr_brigade_split_ex(ctx->tmpbb, e, bb); } else { apr_brigade_length(ctx->tmpbb, 1, &len); } /* * Adjust the burst amount depending on how much * we've done up to now. */ if (ctx->burst) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, APLOGNO(03485) "rl: burst %d; len %"APR_OFF_T_FMT, ctx->burst, len); if (len < ctx->burst) { ctx->burst -= len; } else { ctx->burst = 0; } } e = APR_BRIGADE_LAST(ctx->tmpbb); if (APR_BUCKET_IS_EOS(e)) { ap_remove_output_filter(f); } else if (!APR_BUCKET_IS_FLUSH(e)) { if (APR_BRIGADE_EMPTY(bb)) { /* Wait for more (or next call) */ break; } e = apr_bucket_flush_create(ba); APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, e); } #if defined(RLFDEBUG) brigade_dump(f->r, ctx->tmpbb); brigade_dump(f->r, bb); #endif /* RLFDEBUG */ if (ctx->do_sleep) { apr_sleep(RATE_INTERVAL_MS * 1000); } else { ctx->do_sleep = 1; } rv = ap_pass_brigade(f->next, ctx->tmpbb); apr_brigade_cleanup(ctx->tmpbb); if (rv != APR_SUCCESS) { /* Most often, user disconnects from stream */ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01457) "rl: brigade pass failed."); return rv; } } } if (!APR_BRIGADE_EMPTY(ctx->holdingbb)) { /* Any rate-limited data in tmpbb is sent unlimited along * with the rest. */ APR_BRIGADE_CONCAT(bb, ctx->tmpbb); APR_BRIGADE_CONCAT(bb, ctx->holdingbb); } } #if defined(RLFDEBUG) brigade_dump(f->r, ctx->tmpbb); #endif /* RLFDEBUG */ /* Save remaining tmpbb with the correct lifetime for the next call */ return ap_save_brigade(f, &ctx->holdingbb, &ctx->tmpbb, f->r->pool); }
static ngx_inline ngx_int_t ngx_http_modsecurity_save_request_body(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; apr_off_t content_length; ngx_buf_t *buf; ngx_http_core_srv_conf_t *cscf; size_t size; ngx_http_connection_t *hc; ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); apr_brigade_length(ctx->brigade, 0, &content_length); if (r->header_in->end - r->header_in->last >= content_length) { /* use r->header_in */ if (ngx_buf_size(r->header_in)) { /* move to the end */ ngx_memmove(r->header_in->pos + content_length, r->header_in->pos, ngx_buf_size(r->header_in)); } if (apr_brigade_flatten(ctx->brigade, (char *)r->header_in->pos, (apr_size_t *)&content_length) != APR_SUCCESS) { return NGX_ERROR; } apr_brigade_cleanup(ctx->brigade); r->header_in->last += content_length; return NGX_OK; } if (ngx_buf_size(r->header_in)) { /* * ngx_http_set_keepalive will reuse r->header_in if * (r->header_in != c->buffer && r->header_in.last != r->header_in.end), * so we need this code block. * see ngx_http_set_keepalive, ngx_http_alloc_large_header_buffer */ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); size = ngx_max(cscf->large_client_header_buffers.size, (size_t)content_length + ngx_buf_size(r->header_in)); hc = r->http_connection; if (hc->nfree && size == cscf->large_client_header_buffers.size) { buf = hc->free[--hc->nfree]; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: use http free large header buffer: %p %uz", buf->pos, buf->end - buf->last); } else if (hc->nbusy < cscf->large_client_header_buffers.num) { if (hc->busy == NULL) { hc->busy = ngx_palloc(r->connection->pool, cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *)); } if (hc->busy == NULL) { return NGX_ERROR; } else { buf = ngx_create_temp_buf(r->connection->pool, size); } } else { /* TODO: how to deal this case ? */ return NGX_ERROR; } } else { buf = ngx_create_temp_buf(r->pool, (size_t) content_length); } if (buf == NULL) { return NGX_ERROR; } if (apr_brigade_flatten(ctx->brigade, (char *)buf->pos, (apr_size_t *)&content_length) != APR_SUCCESS) { return NGX_ERROR; } apr_brigade_cleanup(ctx->brigade); buf->last += content_length; ngx_memcpy(buf->last, r->header_in->pos, ngx_buf_size(r->header_in)); buf->last += ngx_buf_size(r->header_in); r->header_in = buf; return NGX_OK; }
apr_status_t apreq_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { request_rec *r = f->r; struct filter_ctx *ctx; apr_status_t rv; apr_off_t len; switch (mode) { case AP_MODE_READBYTES: /* only the modes above are supported */ break; case AP_MODE_EXHAUSTIVE: /* not worth supporting at this level */ case AP_MODE_GETLINE: /* chunked trailers are b0rked in ap_http_filter */ return ap_get_brigade(f->next, bb, mode, block, readbytes); default: return APR_ENOTIMPL; } if (f->ctx == NULL) apreq_filter_make_context(f); ctx = f->ctx; if (ctx->body_status == APR_EINIT) apreq_filter_init_context(f); if (ctx->spool && !APR_BRIGADE_EMPTY(ctx->spool)) { apr_bucket *e; rv = apr_brigade_partition(ctx->spool, readbytes, &e); if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) return rv; if (APR_BUCKET_IS_EOS(e)) e = APR_BUCKET_NEXT(e); apreq_brigade_move(bb, ctx->spool, e); return APR_SUCCESS; } else if (ctx->body_status != APR_INCOMPLETE) { if (ctx->filter_error) return ctx->filter_error; rv = ap_get_brigade(f->next, bb, mode, block, readbytes); ap_remove_input_filter(f); return rv; } rv = ap_get_brigade(f->next, bb, mode, block, readbytes); if (rv != APR_SUCCESS) return rv; apreq_brigade_copy(ctx->bb, bb); apr_brigade_length(bb, 1, &len); ctx->bytes_read += len; if (ctx->bytes_read > ctx->read_limit) { ctx->body_status = APREQ_ERROR_OVERLIMIT; ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->body_status, r, APLOGNO(02054) "Bytes read (%" APR_UINT64_T_FMT ") exceeds configured max_body limit (%" APR_UINT64_T_FMT ")", ctx->bytes_read, ctx->read_limit); } else { ctx->body_status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb); apr_brigade_cleanup(ctx->bb); } return APR_SUCCESS; }
static apr_status_t rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) { apr_status_t rv = APR_SUCCESS; rl_ctx_t *ctx = f->ctx; apr_bucket *fb; int do_sleep = 0; apr_bucket_alloc_t *ba = f->r->connection->bucket_alloc; apr_bucket_brigade *bb = input_bb; if (f->c->aborted) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01454) "rl: conn aborted"); apr_brigade_cleanup(bb); return APR_ECONNABORTED; } if (ctx == NULL) { const char *rl = NULL; int ratelimit; /* no subrequests. */ if (f->r->main != NULL) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } rl = apr_table_get(f->r->subprocess_env, "rate-limit"); if (rl == NULL) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* rl is in kilo bytes / second */ ratelimit = atoi(rl) * 1024; if (ratelimit <= 0) { /* remove ourselves */ ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* first run, init stuff */ ctx = apr_palloc(f->r->pool, sizeof(rl_ctx_t)); f->ctx = ctx; ctx->state = RATE_LIMIT; ctx->speed = ratelimit; /* calculate how many bytes / interval we want to send */ /* speed is bytes / second, so, how many (speed / 1000 % interval) */ ctx->chunk_size = (ctx->speed / (1000 / RATE_INTERVAL_MS)); ctx->tmpbb = apr_brigade_create(f->r->pool, ba); ctx->holdingbb = apr_brigade_create(f->r->pool, ba); } while (ctx->state != RATE_ERROR && (!APR_BRIGADE_EMPTY(bb) || !APR_BRIGADE_EMPTY(ctx->holdingbb))) { apr_bucket *e; if (!APR_BRIGADE_EMPTY(ctx->holdingbb)) { APR_BRIGADE_CONCAT(bb, ctx->holdingbb); } while (ctx->state == RATE_FULLSPEED && !APR_BRIGADE_EMPTY(bb)) { /* Find where we 'stop' going full speed. */ for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { if (AP_RL_BUCKET_IS_END(e)) { apr_bucket *f; f = APR_RING_LAST(&bb->list); APR_RING_UNSPLICE(e, f, link); APR_RING_SPLICE_TAIL(&ctx->holdingbb->list, e, f, apr_bucket, link); ctx->state = RATE_LIMIT; break; } } if (f->c->aborted) { apr_brigade_cleanup(bb); ctx->state = RATE_ERROR; break; } fb = apr_bucket_flush_create(ba); APR_BRIGADE_INSERT_TAIL(bb, fb); rv = ap_pass_brigade(f->next, bb); if (rv != APR_SUCCESS) { ctx->state = RATE_ERROR; ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01455) "rl: full speed brigade pass failed."); } } while (ctx->state == RATE_LIMIT && !APR_BRIGADE_EMPTY(bb)) { for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { if (AP_RL_BUCKET_IS_START(e)) { apr_bucket *f; f = APR_RING_LAST(&bb->list); APR_RING_UNSPLICE(e, f, link); APR_RING_SPLICE_TAIL(&ctx->holdingbb->list, e, f, apr_bucket, link); ctx->state = RATE_FULLSPEED; break; } } while (!APR_BRIGADE_EMPTY(bb)) { apr_bucket *stop_point; apr_off_t len = 0; if (f->c->aborted) { apr_brigade_cleanup(bb); ctx->state = RATE_ERROR; break; } if (do_sleep) { apr_sleep(RATE_INTERVAL_MS * 1000); } else { do_sleep = 1; } apr_brigade_length(bb, 1, &len); rv = apr_brigade_partition(bb, ctx->chunk_size, &stop_point); if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) { ctx->state = RATE_ERROR; ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01456) "rl: partition failed."); break; } if (stop_point != APR_BRIGADE_SENTINEL(bb)) { apr_bucket *f; apr_bucket *e = APR_BUCKET_PREV(stop_point); f = APR_RING_FIRST(&bb->list); APR_RING_UNSPLICE(f, e, link); APR_RING_SPLICE_HEAD(&ctx->tmpbb->list, f, e, apr_bucket, link); } else { APR_BRIGADE_CONCAT(ctx->tmpbb, bb); } fb = apr_bucket_flush_create(ba); APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb); #if 0 brigade_dump(f->r, ctx->tmpbb); brigade_dump(f->r, bb); #endif rv = ap_pass_brigade(f->next, ctx->tmpbb); apr_brigade_cleanup(ctx->tmpbb); if (rv != APR_SUCCESS) { ctx->state = RATE_ERROR; ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01457) "rl: brigade pass failed."); break; } } } } return rv; }
apr_status_t apreq_filter_prefetch(ap_filter_t *f, apr_off_t readbytes) { struct filter_ctx *ctx = f->ctx; request_rec *r = f->r; apr_status_t rv; apr_off_t len; if (ctx->body_status == APR_EINIT) apreq_filter_init_context(f); if (ctx->body_status != APR_INCOMPLETE || readbytes == 0) return ctx->body_status; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02050) "prefetching %" APR_OFF_T_FMT " bytes", readbytes); rv = ap_get_brigade(f->next, ctx->bb, AP_MODE_READBYTES, APR_BLOCK_READ, readbytes); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02051) "ap_get_brigade failed during prefetch"); ctx->filter_error = rv; return ctx->body_status = APREQ_ERROR_GENERAL; } apreq_brigade_setaside(ctx->bb, r->pool); apreq_brigade_copy(ctx->bbtmp, ctx->bb); rv = apreq_brigade_concat(r->pool, ctx->temp_dir, ctx->brigade_limit, ctx->spool, ctx->bbtmp); if (rv != APR_SUCCESS && rv != APR_EOF) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02052) "apreq_brigade_concat failed; TempDir problem?"); ctx->filter_error = APR_EGENERAL; return ctx->body_status = rv; } /* Adding "f" to the protocol filter chain ensures the * spooled data is preserved across internal redirects. */ if (f != r->proto_input_filters) { ap_filter_t *in; for (in = r->input_filters; in != r->proto_input_filters; in = in->next) { if (f == in) { r->proto_input_filters = f; break; } } } apr_brigade_length(ctx->bb, 1, &len); ctx->bytes_read += len; if (ctx->bytes_read > ctx->read_limit) { ctx->body_status = APREQ_ERROR_OVERLIMIT; ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->body_status, r, APLOGNO(02053) "Bytes read (%" APR_UINT64_T_FMT ") exceeds configured read limit (%" APR_UINT64_T_FMT ")", ctx->bytes_read, ctx->read_limit); return ctx->body_status; } ctx->body_status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb); apr_brigade_cleanup(ctx->bb); return ctx->body_status; }