*/
API_EXPORT(const char *) ap_method_name_of(int methnum);
-int http_filter(ap_filter_t *f, ap_bucket_brigade *b);
+int http_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length);
/* Hooks */
/*
/** A list of output filters to be used for this connection
* @defvar ap_filter_t *filters */
struct ap_filter_t *output_filters;
- /** bytes left to read in the current request body */
- long remaining;
};
/* Per-vhost config... */
#define AP_NOBODY_WROTE -1
#define AP_NOBODY_READ -2
+/* Input filtering macros */
+#define AP_GET_LINE 0 /* Get one line from the next filter */
+#define AP_GET_ANY_AMOUNT -1 /* Get as much data as the next filter
+ * is willing to give up.
+ */
+
/*
* FILTER CHAIN
*
*
* The return value of a filter should be an APR status value.
*/
-typedef apr_status_t (*ap_filter_func)(ap_filter_t *f, ap_bucket_brigade *b);
+typedef apr_status_t (*ap_out_filter_func)(ap_filter_t *f, ap_bucket_brigade *b);
+typedef apr_status_t (*ap_in_filter_func)(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length);
+typedef union ap_filter_func {
+ ap_out_filter_func out_func;
+ ap_in_filter_func in_func;
+} ap_filter_func;
/*
* ap_filter_type:
* filter doesn't write to the network, then AP_NOBODY_READ is returned.
* @param filter The next filter in the chain
* @param bucket The current bucket brigade
+ * @param length The maximum amount of data to be returned from the next
+ * lowest filter. If filter a requests 15 bytes
+ * from the filter b, that doesn't stop the b
+ * from requesting 30 bytes from filter c. It just
+ * stops b from returning more that 15 bytes to a. The other
+ * 15 must be stored by b. A value of AP_GET_LINE (0) tells
+ * the filter to only ever return a single line. A value of
+ * AP_GET_ANY_AMOUNT (-1) tells a filter to return everything
+ * it has.
* @return apr_status_t value
- * @deffunc apr_status_t ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket)
+ * @deffunc apr_status_t ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket, int length)
*/
-API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket);
+API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket, int length);
/**
* Pass the current bucket brigade down to the next filter on the filter
* @param name The name to attach to the filter function
* @param filter_func The filter function to name
* @param The type of filter function, either AP_FTYPE_CONTENT or AP_FTYPE_CONNECTION
- * @deffunc void ap_register_input_filter(const char *name, ap_filter_func filter_func, ap_filter_type ftype)
+ * @deffunc void ap_register_input_filter(const char *name, ap_in_filter_func filter_func, ap_filter_type ftype)
*/
API_EXPORT(void) ap_register_input_filter(const char *name,
- ap_filter_func filter_func,
+ ap_in_filter_func filter_func,
ap_filter_type ftype);
/*
* ap_register_output_filter():
* @param name The name to attach to the filter function
* @param filter_func The filter function to name
* @param The type of filter function, either AP_FTYPE_CONTENT or AP_FTYPE_CONNECTION
- * @deffunc void ap_register_output_filter(const char *name, ap_filter_func filter_func, ap_filter_type ftype)
+ * @deffunc void ap_register_output_filter(const char *name, ap_out_filter_func filter_func, ap_filter_type ftype)
*/
API_EXPORT(void) ap_register_output_filter(const char *name,
- ap_filter_func filter_func,
+ ap_out_filter_func filter_func,
ap_filter_type ftype);
/*
return APR_SUCCESS;
}
-static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b)
+/* This function only understands a length of AP_GET_ANY_AMOUNT. It will
+ * ignore length values and always return the entire brigade. This is
+ * pretty safe to do, because we know there always needs to be an intervening
+ * filter just above this that will only make requests for AP_GET_ANY_AMOUNT
+ */
+static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length)
{
apr_socket_t *csock = NULL;
ap_bucket *e;
ap_bucket_brigade *b;
} http_ctx_t;
-apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b)
+apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length)
{
#define ASCII_CR '\015'
#define ASCII_LF '\012'
ap_bucket *e;
char *buff;
- apr_ssize_t length;
+ apr_ssize_t len;
char *pos;
http_ctx_t *ctx = f->ctx;
ap_bucket_brigade *bb;
if (!ctx) {
f->ctx = ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
- if ((rv = ap_get_brigade(f->next, b)) != APR_SUCCESS) {
+ if ((rv = ap_get_brigade(f->next, b, AP_GET_ANY_AMOUNT)) != APR_SUCCESS) {
return rv;
}
}
ctx->b = NULL; /* XXX we just leaked a brigade structure */
}
else {
- if ((rv = ap_get_brigade(f->next, b)) != APR_SUCCESS) {
+ if ((rv = ap_get_brigade(f->next, b, AP_GET_LINE)) != APR_SUCCESS) {
return rv;
}
}
}
- if (f->c->remaining > 0) {
- int remain = f->c->remaining;
+ if (length > 0) {
+ int remain = length;
e = AP_BRIGADE_FIRST(b);
while (remain > e->length && e != AP_BRIGADE_SENTINEL(b)) {
remain -= e->length;
remain = 0;
}
bb = ap_brigade_split(b, AP_BUCKET_NEXT(e));
- f->c->remaining = remain;
ctx->b = bb;
return APR_SUCCESS;
}
else {
- f->c->remaining = remain;
ctx->b = NULL;
return APR_SUCCESS;
}
}
AP_BRIGADE_FOREACH(e, b) {
- if ((rv = e->read(e, (const char **)&buff, &length, 0)) != APR_SUCCESS) {
+ if ((rv = e->read(e, (const char **)&buff, &len, 0)) != APR_SUCCESS) {
return rv;
}
pos = buff;
- while (pos < buff + length) {
+ while (pos < buff + len) {
if (*pos == ASCII_LF) {
e->split(e, pos - buff + 1);
bb = ap_brigade_split(b, AP_BUCKET_NEXT(e));
while (1) {
if (AP_BRIGADE_EMPTY(b)) {
- if (ap_get_brigade(c->input_filters, b) != APR_SUCCESS) {
+ if (ap_get_brigade(c->input_filters, b, AP_GET_LINE) != APR_SUCCESS) {
return -1;
}
}
}
r->remaining = atol(lenp);
- r->connection->remaining = r->remaining;
}
if ((r->read_body == REQUEST_NO_BODY) &&
if (AP_BRIGADE_EMPTY(bb)) {
apr_getsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, &timeout);
apr_setsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, 0);
- r->connection->remaining = len_to_read;
- if (ap_get_brigade(r->input_filters, bb) != APR_SUCCESS) {
+ if (ap_get_brigade(r->input_filters, bb, len_to_read) != APR_SUCCESS) {
/* if we actually fail here, we want to just return and
* stop trying to read data from the client.
*/
}
API_EXPORT(void) ap_register_input_filter(const char *name,
- ap_filter_func filter_func,
+ ap_in_filter_func filter_func,
ap_filter_type ftype)
{
- register_filter(name, filter_func, ftype,
+ ap_filter_func f;
+ f.in_func = filter_func;
+ register_filter(name, f, ftype,
®istered_input_filters);
}
API_EXPORT(void) ap_register_output_filter(const char *name,
- ap_filter_func filter_func,
+ ap_out_filter_func filter_func,
ap_filter_type ftype)
{
- register_filter(name, filter_func, ftype,
+ ap_filter_func f;
+ f.out_func = filter_func;
+ register_filter(name, f, ftype,
®istered_output_filters);
}
* save data off to the side should probably create their own temporary
* brigade especially for that use.
*/
-API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *next, ap_bucket_brigade *bb)
+API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *next,
+ ap_bucket_brigade *bb, int length)
{
if (next) {
- return next->frec->filter_func(next, bb);
+ return next->frec->filter_func.in_func(next, bb, length);
}
return AP_NOBODY_READ;
}
if (AP_BRIGADE_LAST(bb)->type == AP_BUCKET_EOS && next->r) {
next->r->eos_sent = 1;
}
- return next->frec->filter_func(next, bb);
+ return next->frec->filter_func.out_func(next, bb);
}
return AP_NOBODY_WROTE;
}