static apr_status_t upload_filter_init(ap_filter_t* f) { upload_conf* conf = ap_get_module_config(f->r->per_dir_config,&upload_module); upload_ctx* ctx = apr_palloc(f->r->pool, sizeof(upload_ctx)) ; // check content-type, get boundary or error const char* ctype = apr_table_get(f->r->headers_in, "Content-Type") ; if ( ! ctype || ! conf->file_field || strncmp ( ctype , "multipart/form-data", 19 ) ) { ap_remove_input_filter(f) ; return APR_SUCCESS ; } ctx->pool = f->r->pool ; ctx->form = apr_table_make(ctx->pool, conf->form_size) ; ctx->boundary = get_boundary(f->r->pool, ctype) ; ctx->parse_state = p_none ; ctx->key = ctx->val = 0 ; ctx->file_field = conf->file_field ; ctx->is_file = 0 ; ctx->leftover = 0 ; // ctx->bbin = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc) ; /* save the table in request_config */ ap_set_module_config(f->r->request_config, &upload_module, ctx->form) ; f->ctx = ctx ; return APR_SUCCESS ; }
static apr_status_t ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { ef_ctx_t *ctx = f->ctx; apr_status_t rv; if (!ctx) { if ((rv = init_filter_instance(f)) != APR_SUCCESS) { ctx = f->ctx; ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01470) "can't initialise input filter %s: %s", f->frec->name, (ctx->dc->onfail == 1) ? "removing" : "aborting"); ap_remove_input_filter(f); if (ctx->dc->onfail == 1) { return ap_get_brigade(f->next, bb, mode, block, readbytes); } else { f->r->status = HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR; } } ctx = f->ctx; } if (ctx->hit_eos) { /* Match behaviour of HTTP_IN if filter is re-invoked after * hitting EOS: give back another EOS. */ apr_bucket *e = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); return APR_SUCCESS; } if (ctx->noop) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } rv = ap_get_brigade(f->next, bb, mode, block, readbytes); if (rv != APR_SUCCESS) { return rv; } rv = ef_unified_filter(f, bb); return rv; }
static apr_status_t tmpfile_filter(ap_filter_t *f, apr_bucket_brigade *bbout, ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes) { apr_bucket_brigade* bbin = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc); apr_file_t* tmpfile ; char* tmpname = apr_pstrdup(f->r->pool, "/tmp/mod-upload.XXXXXX") ; if ( f->ctx ) { APR_BRIGADE_INSERT_TAIL(bbout, apr_bucket_eos_create(bbout->bucket_alloc)) ; return APR_SUCCESS ; } if ( apr_file_mktemp(&tmpfile, tmpname, KEEPONCLOSE, f->r->pool) != APR_SUCCESS ) { // error ap_remove_input_filter(f) ; } apr_pool_cleanup_register(f->r->pool, tmpfile, (void*)apr_file_close, apr_pool_cleanup_null) ; for ( ; ; ) { apr_bucket* b ; const char* ptr = 0 ; apr_size_t bytes ; #ifdef DEBUG ap_log_rerror(APLOG_MARK,APLOG_DEBUG,0, f->r, "get_brigade") ; #endif ap_get_brigade(f->next, bbin, AP_MODE_READBYTES, APR_BLOCK_READ, BUFLEN) ; for ( b = APR_BRIGADE_FIRST(bbin) ; b != APR_BRIGADE_SENTINEL(bbin) && ! f->ctx ; b = APR_BUCKET_NEXT(b) ) { if ( APR_BUCKET_IS_EOS(b) ) { f->ctx = f ; // just using it as a flag; any nonzero will do apr_file_flush(tmpfile) ; apr_brigade_puts(bbout, ap_filter_flush, f, tmpname) ; APR_BRIGADE_INSERT_TAIL(bbout, apr_bucket_eos_create(bbout->bucket_alloc) ) ; } else if ( apr_bucket_read(b, &ptr, &bytes, APR_BLOCK_READ) == APR_SUCCESS ) { #ifdef DEBUG ap_log_rerror(APLOG_MARK,APLOG_DEBUG,0, f->r, " %d bytes in bucket", bytes) ; #endif apr_file_write(tmpfile, ptr, &bytes) ; } } if ( f->ctx ) break ; else apr_brigade_cleanup(bbin) ; } apr_brigade_destroy(bbin) ; return APR_SUCCESS ; }
static apr_status_t amagent_post_filter(ap_filter_t *f, apr_bucket_brigade *bucket_out, ap_input_mode_t emode, apr_read_type_e eblock, apr_off_t nbytes) { request_rec *r = f->r; conn_rec *c = r->connection; apr_bucket *bucket; apr_size_t sz; char *clean; const char *data = apr_table_get(r->notes, amagent_post_filter_name); do { if (data == NULL) break; sz = strlen(data); clean = base64_decode(data, &sz); if (clean == NULL) break; apr_table_unset(r->notes, amagent_post_filter_name); LOG_R(APLOG_DEBUG, r, "amagent_post_filter(): reposting %ld bytes", sz); bucket = apr_bucket_heap_create((const char *) clean, sz, NULL, c->bucket_alloc); if (bucket == NULL) { free(clean); return APR_EGENERAL; } APR_BRIGADE_INSERT_TAIL(bucket_out, bucket); free(clean); bucket = apr_bucket_eos_create(c->bucket_alloc); if (bucket == NULL) { return APR_EGENERAL; } APR_BRIGADE_INSERT_TAIL(bucket_out, bucket); ap_remove_input_filter(f); return APR_SUCCESS; } while (0); apr_table_unset(r->notes, amagent_post_filter_name); ap_remove_input_filter(f); return ap_get_brigade(f->next, bucket_out, emode, eblock, nbytes); }
/** * Remove the kept_body and keep body filters from this specific request. */ static void ap_request_remove_filter(request_rec * r) { ap_filter_t * f = r->input_filters; while (f) { if (f->frec->filter_func.in_func == kept_body_filter || f->frec->filter_func.in_func == keep_body_filter) { ap_remove_input_filter(f); } f = f->next; } }
static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { ef_ctx_t *ctx = f->ctx; apr_status_t rv; if (!ctx) { if ((rv = init_filter_instance(f)) != APR_SUCCESS) { ctx = f->ctx; ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "can't initialise input filter %s: %s", f->frec->name, (ctx->dc->onfail == 1) ? "removing" : "aborting"); ap_remove_input_filter(f); if (ctx->dc->onfail == 1) { return ap_get_brigade(f->next, bb, mode, block, readbytes); } else { f->r->status = HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR; } } ctx = f->ctx; } if (ctx->noop || ctx->hit_eos) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } rv = ap_get_brigade(f->next, bb, mode, block, readbytes); if (rv != APR_SUCCESS) { return rv; } rv = ef_unified_filter(f, bb); return rv; }
static apr_status_t apreq_filter_init(ap_filter_t *f) { request_rec *r = f->r; struct filter_ctx *ctx = f->ctx; struct apache2_handle *handle = (struct apache2_handle *)apreq_handle_apache2(r); /* Don't parse GET (this protects against subrequest body parsing). */ if (f->r->method_number == M_GET) return APR_SUCCESS; if (ctx == NULL || ctx->body_status == APR_EINIT) { if (f == r->input_filters) { handle->f = f; } else if (r->input_filters->frec->filter_func.in_func == apreq_filter) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02047) "removing intermediate apreq filter"); if (handle->f == f) handle->f = r->input_filters; ap_remove_input_filter(f); } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02048) "relocating intermediate apreq filter"); apreq_filter_relocate(f); handle->f = f; } return APR_SUCCESS; } /* else this is a protocol filter which may still be active. * if it is, we must deregister it now. */ if (handle->f == f) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02049) "disabling stale protocol filter"); if (ctx->body_status == APR_INCOMPLETE) ctx->body_status = APREQ_ERROR_INTERRUPT; handle->f = NULL; } return APR_SUCCESS; }
/* Search thru the input filters and remove the reqtimeout one */ static void remove_reqtimeout(ap_filter_t *next) { ap_filter_t *reqto = NULL; ap_filter_rec_t *filter; filter = ap_get_input_filter_handle("reqtimeout"); if (!filter) { return; } while (next) { if (next->frec == filter) { reqto = next; break; } next = next->next; } if (reqto) { ap_remove_input_filter(reqto); } }
// This input filter handles the job of rewriting the request, it's injected at // runtime by the porter fixup filter. All it does is remove itself from the // filter chain and pass the newly modified content up the filter chain. static apr_status_t porter_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { porter_upload_request_t *ur = f->ctx; if (!ur) { // Because we add ourselves dynamically, this should never occur. // but handle it anyway. return ap_get_brigade(f->next, bb, mode, block, readbytes); } // Remove ourselves so we don't trigger again. ap_remove_input_filter(f); APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(bb->bucket_alloc)) ; APR_BRIGADE_PREPEND(bb, ur->bucket_brigade); apr_brigade_destroy(ur->bucket_brigade); return APR_SUCCESS; }
/** * @internal * * "Sniffs" the input (request) data from the connection stream and tries * to determine who closed a connection and why. */ static int ironbee_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { conn_rec *c = f->c; ironbee_conn_context *ctx = f->ctx; ib_conn_t *iconn = ctx->iconn; ib_core_cfg_t *corecfg; ib_stream_t *istream; apr_bucket *b; apr_status_t rc; int buffering = 0; /* Any mode not handled just gets passed through. */ if ((mode != AP_MODE_GETLINE) && (mode != AP_MODE_READBYTES)) { return ap_get_brigade(f->next, bb, mode, block, readbytes); } /* Configure. */ ib_context_module_config(iconn->ctx, ib_core_module(), (void *)&corecfg); if (corecfg != NULL) { buffering = (int)corecfg->buffer_req; } /* When buffering, data is removed from the brigade and handed * to IronBee. The filter must not return an empty brigade in this * case and keeps reading until there is processed data that comes * back from IronBee. */ do { ib_tx_t *itx = iconn->tx; /* If there is any processed data, then send it now. */ if (buffering && (itx != NULL)) { ib_sdata_t *sdata; /* Take any data from the drain (processed data) and * inject it back into the filter brigade. */ ib_fctl_drain(itx->fctl, &istream); if ((istream != NULL) && (istream->nelts > 0)) { int done = 0; while (!done) { apr_bucket *ibucket = NULL; /// @todo Handle multi-bucket lines if (mode == AP_MODE_GETLINE) { done = 1; } ib_stream_pull(istream, &sdata); if (sdata == NULL) { /* No more data left. */ break; } switch (sdata->type) { case IB_STREAM_DATA: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": DATA[%d]: %.*s", (int)sdata->dlen, (int)sdata->dlen, (char *)sdata->data); #endif /// @todo Is this creating a copy? Just need a reference. ibucket = apr_bucket_heap_create(sdata->data, sdata->dlen, NULL, bb->bucket_alloc); break; case IB_STREAM_FLUSH: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": FLUSH"); #endif ibucket = apr_bucket_flush_create(bb->bucket_alloc); break; case IB_STREAM_EOH: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": EOH"); #endif /// @todo Do something here??? break; case IB_STREAM_EOB: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": EOB"); #endif /// @todo Do something here??? break; case IB_STREAM_EOS: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": EOS"); #endif ibucket = apr_bucket_eos_create(bb->bucket_alloc); break; default: ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": UNKNOWN stream data type %d", sdata->type); } if (ibucket != NULL) { APR_BRIGADE_INSERT_TAIL(bb, ibucket); } } /* Need to send any processed data to avoid deadlock. */ if (!APR_BRIGADE_EMPTY(bb)) { return APR_SUCCESS; } } } /* Fetch data from the next filter. */ if (buffering) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "FETCH BRIGADE (buffering)"); /* Normally Apache will request the headers line-by-line, but * IronBee does not require this. So, here the request is * fetched with READBYTES and IronBee will then break * it back up into lines when it is injected back into * the brigade after the data is processed. */ rc = ap_get_brigade(f->next, bb, AP_MODE_READBYTES, block, HUGE_STRING_LEN); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "FETCH BRIGADE (non-buffering)"); rc = ap_get_brigade(f->next, bb, mode, block, readbytes); } /* Check for any timeouts/disconnects/errors. */ if (APR_STATUS_IS_TIMEUP(rc)) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": %s server closed connection (%d)", f->frec->name, rc); ap_remove_input_filter(f); return rc; } else if (APR_STATUS_IS_EOF(rc) || apr_get_os_error() == ECONNRESET) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": %s client closed connection (%d)", f->frec->name, rc); ap_remove_input_filter(f); return rc; } else if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": %s returned %d (0x%08x) - %s", f->frec->name, rc, rc, strerror(apr_get_os_error())); return rc; } /* Process data. */ for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) { if (buffering) { /// @todo setaside into our own pool to destroy later??? apr_bucket_setaside(b, c->pool); process_bucket(f, b); APR_BUCKET_REMOVE(b); } else { process_bucket(f, b); } } } while (buffering); return APR_SUCCESS; }
apr_status_t dav_svn__location_in_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; locate_ctx_t *ctx = f->ctx; apr_status_t rv; apr_bucket *bkt; const char *master_uri, *root_dir, *canonicalized_uri; apr_uri_t uri; /* Don't filter if we're in a subrequest or we aren't setup to proxy anything. */ master_uri = dav_svn__get_master_uri(r); if (r->main || !master_uri) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } /* And don't filter if our search-n-replace would be a noop anyway (that is, if our root path matches that of the master server). */ apr_uri_parse(r->pool, master_uri, &uri); root_dir = dav_svn__get_root_dir(r); canonicalized_uri = svn_urlpath__canonicalize(uri.path, r->pool); if (strcmp(canonicalized_uri, root_dir) == 0) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } /* ### FIXME: While we want to fix up any locations in proxied XML ### requests, we do *not* want to be futzing with versioned (or ### to-be-versioned) data, such as the file contents present in ### PUT requests and properties in PROPPATCH requests. ### See issue #3445 for details. */ /* We are url encoding the current url and the master url as incoming(from client) request body has it encoded already. */ canonicalized_uri = svn_path_uri_encode(canonicalized_uri, r->pool); root_dir = svn_path_uri_encode(root_dir, r->pool); if (!f->ctx) { ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx)); ctx->remotepath = canonicalized_uri; ctx->remotepath_len = strlen(ctx->remotepath); ctx->localpath = root_dir; ctx->localpath_len = strlen(ctx->localpath); ctx->pattern = apr_strmatch_precompile(r->pool, ctx->localpath, 1); ctx->pattern_len = ctx->localpath_len; } rv = ap_get_brigade(f->next, bb, mode, block, readbytes); if (rv) { return rv; } bkt = APR_BRIGADE_FIRST(bb); while (bkt != APR_BRIGADE_SENTINEL(bb)) { const char *data, *match; apr_size_t len; if (APR_BUCKET_IS_METADATA(bkt)) { bkt = APR_BUCKET_NEXT(bkt); continue; } /* read */ apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ); match = apr_strmatch(ctx->pattern, data, len); if (match) { apr_bucket *next_bucket; apr_bucket_split(bkt, match - data); next_bucket = APR_BUCKET_NEXT(bkt); apr_bucket_split(next_bucket, ctx->pattern_len); bkt = APR_BUCKET_NEXT(next_bucket); apr_bucket_delete(next_bucket); next_bucket = apr_bucket_pool_create(ctx->remotepath, ctx->remotepath_len, r->pool, bb->bucket_alloc); APR_BUCKET_INSERT_BEFORE(bkt, next_bucket); } else { bkt = APR_BUCKET_NEXT(bkt); } } return APR_SUCCESS; }
static apr_status_t merge_xml_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_status_t rv; request_rec *r = f->r; merge_ctx_t *ctx = f->ctx; apr_bucket *bucket; int seen_eos = 0; /* We shouldn't be added if we're not a MERGE/DELETE, but double check. */ if ((r->method_number != M_MERGE) && (r->method_number != M_DELETE)) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } if (!ctx) { f->ctx = ctx = apr_palloc(r->pool, sizeof(*ctx)); ctx->parser = apr_xml_parser_create(r->pool); ctx->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); apr_pool_create(&ctx->pool, r->pool); } rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes); if (rv != APR_SUCCESS) return rv; for (bucket = APR_BRIGADE_FIRST(ctx->bb); bucket != APR_BRIGADE_SENTINEL(ctx->bb); bucket = APR_BUCKET_NEXT(bucket)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(bucket)) { seen_eos = 1; break; } if (APR_BUCKET_IS_METADATA(bucket)) continue; rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) return rv; rv = apr_xml_parser_feed(ctx->parser, data, len); if (rv != APR_SUCCESS) { /* Clean up the parser. */ (void) apr_xml_parser_done(ctx->parser, NULL); break; } } /* This will clear-out the ctx->bb as well. */ APR_BRIGADE_CONCAT(bb, ctx->bb); if (seen_eos) { apr_xml_doc *pdoc; /* Remove ourselves now. */ ap_remove_input_filter(f); /* tell the parser that we're done */ rv = apr_xml_parser_done(ctx->parser, &pdoc); if (rv == APR_SUCCESS) { #if APR_CHARSET_EBCDIC apr_xml_parser_convert_doc(r->pool, pdoc, ap_hdrs_from_ascii); #endif /* stash the doc away for mod_dav_svn's later use. */ rv = apr_pool_userdata_set(pdoc, "svn-request-body", NULL, r->pool); if (rv != APR_SUCCESS) return rv; } } return APR_SUCCESS; }
void apreq_filter_make_context(ap_filter_t *f) { request_rec *r; struct filter_ctx *ctx; struct dir_config *d; r = f->r; d = ap_get_module_config(r->per_dir_config, &apreq_module); if (f == r->input_filters && r->proto_input_filters == f->next && f->next->frec->filter_func.in_func == apreq_filter && f->r->method_number != M_GET) { ctx = f->next->ctx; switch (ctx->body_status) { case APREQ_ERROR_INTERRUPT: ctx->body_status = APR_INCOMPLETE; /* fall thru */ case APR_SUCCESS: if (d != NULL) { ctx->temp_dir = d->temp_dir; ctx->read_limit = d->read_limit; ctx->brigade_limit = d->brigade_limit; if (ctx->parser != NULL) { ctx->parser->temp_dir = d->temp_dir; ctx->parser->brigade_limit = d->brigade_limit; } } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02057) "stealing filter context"); f->ctx = ctx; r->proto_input_filters = f; ap_remove_input_filter(f->next); return; default: ap_log_rerror(APLOG_MARK, APLOG_DEBUG, ctx->body_status, r, APLOGNO(02058) "cannot steal context: bad filter status"); } } ctx = apr_pcalloc(r->pool, sizeof *ctx); ctx->body_status = APR_EINIT; if (d == NULL) { ctx->read_limit = (apr_uint64_t)-1; ctx->brigade_limit = APREQ_DEFAULT_BRIGADE_LIMIT; } else { ctx->temp_dir = d->temp_dir; ctx->read_limit = (d->read_limit == (apr_uint64_t)-1) ? APREQ_DEFAULT_READ_LIMIT : d->read_limit; ctx->brigade_limit = (d->brigade_limit == (apr_size_t)-1) ? APREQ_DEFAULT_BRIGADE_LIMIT : d->brigade_limit; } f->ctx = ctx; }
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; }
/** * This is the KEEP_BODY_INPUT filter for HTTP requests, for times when the * body should be set aside for future use by other modules. */ static apr_status_t keep_body_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { apr_bucket *e; keep_body_ctx_t *ctx = f->ctx; apr_status_t rv; apr_bucket *bucket; apr_off_t len = 0; if (!ctx) { const char *lenp; char *endstr = NULL; request_dir_conf *dconf = ap_get_module_config(f->r->per_dir_config, &request_module); /* must we step out of the way? */ if (!dconf->keep_body || f->r->kept_body) { ap_remove_input_filter(f); return ap_get_brigade(f->next, b, mode, block, readbytes); } f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); /* fail fast if the content length exceeds keep body */ lenp = apr_table_get(f->r->headers_in, "Content-Length"); if (lenp) { /* Protects against over/underflow, non-digit chars in the * string (excluding leading space) (the endstr checks) * and a negative number. */ if (apr_strtoff(&ctx->remaining, lenp, &endstr, 10) || endstr == lenp || *endstr || ctx->remaining < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01411) "Invalid Content-Length"); ap_remove_input_filter(f); return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE); } /* If we have a limit in effect and we know the C-L ahead of * time, stop it here if it is invalid. */ if (dconf->keep_body < ctx->remaining) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01412) "Requested content-length of %" APR_OFF_T_FMT " is larger than the configured limit" " of %" APR_OFF_T_FMT, ctx->remaining, dconf->keep_body); ap_remove_input_filter(f); return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE); } } f->r->kept_body = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc); ctx->remaining = dconf->keep_body; } /* get the brigade from upstream, and read it in to get its length */ rv = ap_get_brigade(f->next, b, mode, block, readbytes); if (rv == APR_SUCCESS) { rv = apr_brigade_length(b, 1, &len); } /* does the length take us over the limit? */ if (APR_SUCCESS == rv && len > ctx->remaining) { if (f->r->kept_body) { apr_brigade_cleanup(f->r->kept_body); f->r->kept_body = NULL; } ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01413) "Requested content-length of %" APR_OFF_T_FMT " is larger than the configured limit" " of %" APR_OFF_T_FMT, len, ctx->keep_body); return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE); } ctx->remaining -= len; /* pass any errors downstream */ if (rv != APR_SUCCESS) { if (f->r->kept_body) { apr_brigade_cleanup(f->r->kept_body); f->r->kept_body = NULL; } return rv; } /* all is well, set aside the buckets */ for (bucket = APR_BRIGADE_FIRST(b); bucket != APR_BRIGADE_SENTINEL(b); bucket = APR_BUCKET_NEXT(bucket)) { apr_bucket_copy(bucket, &e); APR_BRIGADE_INSERT_TAIL(f->r->kept_body, e); } return APR_SUCCESS; }