Apache HTTPD
mod_request.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * mod_request.c --- HTTP routines to set aside or process request bodies.
19 */
20
21#include "apr.h"
22#include "apr_strings.h"
23#include "apr_buckets.h"
24#include "apr_lib.h"
25
26#include "ap_config.h"
27#include "httpd.h"
28#include "http_config.h"
29#include "http_protocol.h"
30#include "http_log.h" /* For errors detected in basic auth common
31 * support code... */
32#include "http_request.h"
33
34#include "mod_request.h"
35
36/* Handles for core filters */
39
42 int http_error)
43{
45
48 NULL, f->r->pool,
49 f->c->bucket_alloc);
51 e = apr_bucket_eos_create(f->c->bucket_alloc);
53 return ap_pass_brigade(f->r->output_filters, bb);
54}
55
60
69{
71 keep_body_ctx_t *ctx = f->ctx;
72 apr_status_t rv;
73 apr_bucket *bucket;
74 apr_off_t len = 0;
75
76 if (!ctx) {
77 const char *lenp;
78 request_dir_conf *dconf = ap_get_module_config(f->r->per_dir_config,
79 &request_module);
80
81 /* must we step out of the way? */
82 if (!dconf->keep_body || f->r->kept_body) {
84 return ap_get_brigade(f->next, b, mode, block, readbytes);
85 }
86
87 f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
88
89 /* fail fast if the content length exceeds keep body */
90 lenp = apr_table_get(f->r->headers_in, "Content-Length");
91 if (lenp) {
92
93 /* Protects against over/underflow, non-digit chars in the
94 * string, leading plus/minus signs, trailing characters and
95 * a negative number.
96 */
97 if (!ap_parse_strict_length(&ctx->remaining, lenp)) {
99 "Invalid Content-Length '%s'", lenp);
100
103 }
104
105 /* If we have a limit in effect and we know the C-L ahead of
106 * time, stop it here if it is invalid.
107 */
108 if (dconf->keep_body < ctx->remaining) {
110 "Requested content-length of %" APR_OFF_T_FMT
111 " is larger than the configured limit"
112 " of %" APR_OFF_T_FMT, ctx->remaining, dconf->keep_body);
115 }
116
117 }
118
119 f->r->kept_body = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc);
120 ctx->remaining = dconf->keep_body;
121 }
122
123 /* get the brigade from upstream, and read it in to get its length */
124 rv = ap_get_brigade(f->next, b, mode, block, readbytes);
125 if (rv == APR_SUCCESS) {
126 rv = apr_brigade_length(b, 1, &len);
127 }
128
129 /* does the length take us over the limit? */
130 if (APR_SUCCESS == rv && len > ctx->remaining) {
131 if (f->r->kept_body) {
132 apr_brigade_cleanup(f->r->kept_body);
133 f->r->kept_body = NULL;
134 }
136 "Requested content-length of %" APR_OFF_T_FMT
137 " is larger than the configured limit"
138 " of %" APR_OFF_T_FMT, len, ctx->keep_body);
140 }
141 ctx->remaining -= len;
142
143 /* pass any errors downstream */
144 if (rv != APR_SUCCESS) {
145 if (f->r->kept_body) {
146 apr_brigade_cleanup(f->r->kept_body);
147 f->r->kept_body = NULL;
148 }
149 return rv;
150 }
151
152 /* all is well, set aside the buckets */
153 for (bucket = APR_BRIGADE_FIRST(b);
154 bucket != APR_BRIGADE_SENTINEL(b);
155 bucket = APR_BUCKET_NEXT(bucket))
156 {
157 apr_bucket_copy(bucket, &e);
158 APR_BRIGADE_INSERT_TAIL(f->r->kept_body, e);
159 }
160
161 return APR_SUCCESS;
162}
163
164
169
178{
179 apr_off_t length = 0;
180 request_rec *r = f->r;
181 apr_bucket_brigade *kept_body = r->kept_body;
182
183 if (kept_body) {
184 apr_table_unset(r->headers_in, "Transfer-Encoding");
185 apr_brigade_length(kept_body, 1, &length);
186 apr_table_setn(r->headers_in, "Content-Length", apr_off_t_toa(r->pool, length));
187 }
188
189 return OK;
190}
191
202{
203 request_rec *r = f->r;
204 apr_bucket_brigade *kept_body = r->kept_body;
205 kept_body_ctx_t *ctx = f->ctx;
206 apr_bucket *ec, *e2;
207 apr_status_t rv;
208
209 /* just get out of the way of things we don't want. */
210 if (!kept_body || (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE)) {
211 return ap_get_brigade(f->next, b, mode, block, readbytes);
212 }
213
214 /* set up the context if it does not already exist */
215 if (!ctx) {
216 f->ctx = ctx = apr_palloc(f->r->pool, sizeof(*ctx));
217 ctx->offset = 0;
218 apr_brigade_length(kept_body, 1, &ctx->remaining);
219 }
220
221 /* kept_body is finished, send next filter */
222 if (ctx->remaining <= 0) {
223 return ap_get_brigade(f->next, b, mode, block, readbytes);
224 }
225
226 /* send all of the kept_body, but no more */
227 if (readbytes > ctx->remaining) {
228 readbytes = ctx->remaining;
229 }
230
231 /* send part of the kept_body */
232 if ((rv = apr_brigade_partition(kept_body, ctx->offset, &ec)) != APR_SUCCESS) {
234 "apr_brigade_partition() failed on kept_body at %" APR_OFF_T_FMT, ctx->offset);
235 return rv;
236 }
237 if ((rv = apr_brigade_partition(kept_body, ctx->offset + readbytes, &e2)) != APR_SUCCESS) {
239 "apr_brigade_partition() failed on kept_body at %" APR_OFF_T_FMT, ctx->offset + readbytes);
240 return rv;
241 }
242
243 do {
245 const char *str;
247
248 if (apr_bucket_copy(ec, &foo) != APR_SUCCESS) {
249 /* As above; this should not fail since the bucket has
250 * a known length, but just to be sure, this takes
251 * care of uncopyable buckets that do somehow manage
252 * to slip through. */
253 /* XXX: check for failure? */
255 apr_bucket_copy(ec, &foo);
256 }
258 ec = APR_BUCKET_NEXT(ec);
259 } while (ec != e2);
260
261 ctx->remaining -= readbytes;
262 ctx->offset += readbytes;
263
264 return APR_SUCCESS;
265}
266
271{
273 while (f) {
274 if (f->frec == fn) {
275 return 1;
276 }
277 f = f->next;
278 }
279 return 0;
280}
281
311
312/*
313 * Remove the kept_body and keep_body filters from this specific request.
314 */
316{
318
319 while (f) {
320 if (f->frec->filter_func.in_func == kept_body_filter ||
321 f->frec->filter_func.in_func == keep_body_filter) {
323 }
324 f = f->next;
325 }
326}
327
329{
330 request_dir_conf *new =
332
333 new->keep_body_set = 0; /* unset */
334 new->keep_body = 0; /* don't by default */
335
336 return (void *) new;
337}
338
339static void *merge_request_dir_config(apr_pool_t *p, void *basev, void *addv)
340{
344
345 new->keep_body = (add->keep_body_set == 0) ? base->keep_body : add->keep_body;
346 new->keep_body_set = add->keep_body_set || base->keep_body_set;
347
348 return new;
349}
350
351static const char *set_kept_body_size(cmd_parms *cmd, void *dconf,
352 const char *arg)
353{
354 request_dir_conf *conf = dconf;
355 char *end = NULL;
356
357 if (APR_SUCCESS != apr_strtoff(&(conf->keep_body), arg, &end, 10)
358 || conf->keep_body < 0 || *end) {
359 return "KeptBodySize must be a valid size in bytes, or zero.";
360 }
361 conf->keep_body_set = 1;
362
363 return NULL;
364}
365
366static const command_rec request_cmds[] = {
368 "Maximum size of request bodies kept aside for use by filters"),
369 { NULL }
370};
371
384
387 create_request_dir_config, /* create per-directory config structure */
388 merge_request_dir_config, /* merge per-directory config structures */
389 NULL, /* create per-server config structure */
390 NULL, /* merge per-server config structures */
391 request_cmds, /* command apr_table_t */
392 register_hooks /* register hooks */
393};
Symbol export macros and hook functions.
const char apr_size_t len
Definition ap_regex.h:187
APR-UTIL Buckets/Bucket Brigades.
APR general purpose library routines.
APR Strings library.
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
request_rec * r
#define OK
Definition httpd.h:456
void ap_remove_input_filter(ap_filter_t *f)
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
ap_filter_t * ap_add_input_filter_handle(ap_filter_rec_t *f, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_filter_rec_t * ap_register_input_filter(const char *name, ap_in_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
apr_status_t ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
@ AP_FTYPE_RESOURCE
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_MARK
Definition http_log.h:283
apr_bucket * ap_bucket_error_create(int error, const char *buf, apr_pool_t *p, apr_bucket_alloc_t *list)
void ap_hook_insert_filter(ap_HOOK_insert_filter_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition request.c:96
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
apr_file_t * f
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define APR_BUCKET_NEXT(e)
apr_read_type_e
Definition apr_buckets.h:57
apr_bucket * e
#define APR_BRIGADE_SENTINEL(b)
apr_brigade_flush void * ctx
#define apr_bucket_copy(e, c)
#define APR_BRIGADE_FIRST(b)
#define apr_bucket_read(e, str, len, block)
int apr_off_t * length
@ APR_BLOCK_READ
Definition apr_buckets.h:58
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
#define APR_HOOK_LAST
Definition apr_hooks.h:305
#define APR_REGISTER_OPTIONAL_FN(name)
#define ACCESS_CONF
#define HTTP_REQUEST_ENTITY_TOO_LARGE
Definition httpd.h:521
#define KEEP_BODY_FILTER
Definition mod_request.h:44
#define KEPT_BODY_FILTER
Definition mod_request.h:45
#define STANDARD20_MODULE_STUFF
int ap_parse_strict_length(apr_off_t *len, const char *str)
Definition util.c:2683
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char char ** end
apr_cmdtype_e cmd
Apache Configuration.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static ap_filter_rec_t * keep_body_input_filter_handle
Definition mod_request.c:37
static apr_status_t bail_out_on_error(apr_bucket_brigade *bb, ap_filter_t *f, int http_error)
Definition mod_request.c:40
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)
Definition mod_request.c:65
struct kept_body_filter_ctx kept_body_ctx_t
static int request_is_filter_present(request_rec *r, ap_filter_rec_t *fn)
static apr_status_t kept_body_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
static void * create_request_dir_config(apr_pool_t *p, char *dummy)
static const char * set_kept_body_size(cmd_parms *cmd, void *dconf, const char *arg)
static void register_hooks(apr_pool_t *p)
static void ap_request_insert_filter(request_rec *r)
struct keep_body_filter_ctx keep_body_ctx_t
static void * merge_request_dir_config(apr_pool_t *p, void *basev, void *addv)
static ap_filter_rec_t * kept_body_input_filter_handle
Definition mod_request.c:38
static void ap_request_remove_filter(request_rec *r)
static const command_rec request_cmds[]
static int kept_body_filter_init(ap_filter_t *f)
mod_request private header file
return NULL
Definition mod_so.c:359
This structure is used for recording information about the registered filters. It associates a name w...
The representation of a filter chain.
apr_pool_t * pool
apr_off_t keep_body
Definition mod_request.h:51
A structure that represents the current request.
Definition httpd.h:845
apr_pool_t * pool
Definition httpd.h:847
conn_rec * connection
Definition httpd.h:849
apr_bucket_brigade * kept_body
Definition httpd.h:953
struct ap_filter_t * input_filters
Definition httpd.h:1072
apr_table_t * headers_in
Definition httpd.h:976
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
#define str
ap_input_mode_t
input filtering modes
Definition util_filter.h:41
@ AP_MODE_READBYTES
Definition util_filter.h:43
@ AP_MODE_GETLINE
Definition util_filter.h:48