* should be considered "const". The filter is allowed to modify the
* next/prev to insert/remove/replace elements in the bucket list, but
* the types and values of the individual buckets should not be altered.
+ *
+ * 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);
*/
/**
* Pass the current bucket brigade down to the next filter on the filter
- * stack. The filter should return the number of bytes written by the
- * next filter. If the bottom-most filter doesn't write to the next work,
- * then AP_NOBODY_WROTE is returned.
+ * stack. The filter should return an apr_status_t value. If the bottom-most
+ * filter doesn't write to the network, then AP_NOBODY_WROTE is returned.
* @param filter The next filter in the chain
* @param bucket The current bucket brigade
- * @return The number of bytes written
- * @deffunc int ap_pass_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket)
+ * @return apr_status_t value
+ * @deffunc apr_status_t ap_pass_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket)
*/
-API_EXPORT(int) ap_pass_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket);
+API_EXPORT(apr_status_t) ap_pass_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket);
/*
* ap_register_filter():
* !!!This is an extremely cheap ripoff of mod_charset.c from Russian Apache!!!
*/
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
* translation mechanics:
* we don't handle characters that straddle more than two buckets; an error
* will be generated
+ *
+ * we don't signal an error if we get EOS but we're in the middle of an input
+ * character
*/
/* send_downstream() is passed the translated data; it puts it in a single-
* bucket brigade and passes the brigade to the next filter
*/
-static int send_downstream(ap_filter_t *f, const char *tmp, apr_ssize_t len)
+static apr_status_t send_downstream(ap_filter_t *f, const char *tmp, apr_ssize_t len)
{
ap_bucket_brigade *bb;
return ap_pass_brigade(f->next, bb);
}
-static void send_eos(ap_filter_t *f)
+static apr_status_t send_eos(ap_filter_t *f)
{
ap_bucket_brigade *bb;
bb = ap_brigade_create(f->r->pool);
ap_brigade_append_buckets(bb, ap_bucket_create_eos());
- ap_pass_brigade(f->next, bb);
+ return ap_pass_brigade(f->next, bb);
}
static void remove_and_destroy(ap_bucket_brigade *bb, ap_bucket *b)
ctx->saved = 0;
}
- /* huh? we can catch errors here... */
- return APR_SUCCESS;
+ return rv;
}
/* xlate_filter() handles arbirary conversions from one charset to another...
* where the filter's context data is set up... the context data gives us
* the translation handle
*/
-static int xlate_filter(ap_filter_t *f, ap_bucket_brigade *bb)
+static apr_status_t xlate_filter(ap_filter_t *f, ap_bucket_brigade *bb)
{
charset_req_t *reqinfo = ap_get_module_config(f->r->request_config,
&charset_lite_module);
char tmp[XLATE_BUF_SIZE];
apr_ssize_t space_avail;
int done;
- int bytes_sent_downstream = 0;
- int written;
apr_status_t rv = APR_SUCCESS;
if (debug) {
* convert it until we look at the next bucket.
*/
set_aside_partial_char(f, cur_str, cur_len);
- rv = 0;
+ rv = APR_SUCCESS;
cur_len = 0;
}
}
if (rv != APR_SUCCESS) {
/* bad input byte; we can't continue */
done = 1;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, f->r->server,
+ "xlate_filter() - apr_xlate_conv_buffer() failed");
}
if (space_avail < XLATE_MIN_BUFF_LEFT) {
/* It is time to flush, as there is not enough space left in the
* current output buffer to bother with converting more data.
*/
- /* TODO: handle errors from this operation */
- written = send_downstream(f, tmp, sizeof(tmp) - space_avail);
+ rv = send_downstream(f, tmp, sizeof(tmp) - space_avail);
+ if (rv == APR_SUCCESS) {
+ done = 1;
+ }
- /* The filters (or ap_r* routines) upstream apparently want
- * to know how many bytes were written, not how many of their
- * bytes were accepted.
- */
- bytes_sent_downstream += written;
-
/* tmp is now empty */
space_avail = sizeof(tmp);
}
if (rv == APR_SUCCESS) {
if (space_avail < sizeof(tmp)) { /* gotta write out what we converted */
- written = send_downstream(f, tmp, sizeof(tmp) - space_avail);
- bytes_sent_downstream += written;
+ rv = send_downstream(f, tmp, sizeof(tmp) - space_avail);
}
-
+ }
+ if (rv == APR_SUCCESS) {
if (cur_len == AP_END_OF_BRIGADE) {
- send_eos(f);
+ rv = send_eos(f);
}
}
else {
"xlate_filter() - returning error");
}
- return bytes_sent_downstream;
+ return rv;
}
static const command_rec cmds[] =
NULL,
cmds,
NULL,
- charset_register_hooks,
+ charset_register_hooks,
};
* smart about when it actually sends the data, but this implements some sort
* of chunking for right now.
*/
-static int chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
+static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
{
ap_bucket *dptr = b->head, *lb, *next, *tail;
int len = 0, cur_len;
char lenstr[sizeof("ffffffff\r\n")];
const char *cur_str;
int hit_eos = 0;
- apr_status_t rv = 0; /* currently bytes written, will be APR_* */
+ apr_status_t rv = APR_SUCCESS;
while (dptr) {
if (dptr->type == AP_BUCKET_EOS) {
b->tail = ap_bucket_create_transient("\r\n", 2);
dptr->next = b->tail;
b->tail->prev = dptr;
- rv += ap_pass_brigade(f->next, b);
+ rv = ap_pass_brigade(f->next, b);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
/* start a new brigade */
len = 0;
b = ap_brigade_create(f->r->pool);
b->head = lb;
}
}
- rv += ap_pass_brigade(f->next, b);
- return rv;
+ return ap_pass_brigade(f->next, b);
}
/* Default filter. This filter should almost always be used. Its only job
#if 0
request_rec *r = f->r;
#endif
+ apr_status_t rv;
apr_ssize_t bytes_sent = 0;
ap_bucket *dptr = b->head;
int len = 0, written;
else {
#endif
while (dptr->read(dptr, &str, &len, 0) != AP_END_OF_BRIGADE) {
- ap_bwrite(f->r->connection->client, str, len, &written);
+ if ((rv = ap_bwrite(f->r->connection->client, str, len, &written))
+ != APR_SUCCESS) {
+ return rv;
+ }
dptr = dptr->next;
bytes_sent += written;
if (!dptr) {
if (len == AP_END_OF_BRIGADE) {
ap_bflush(f->r->connection->client);
}
- return bytes_sent;
+ return APR_SUCCESS;
#if 0
}
#endif
API_EXPORT(size_t) ap_send_mmap(apr_mmap_t *mm, request_rec *r, size_t offset,
size_t length)
{
- apr_ssize_t bytes_sent = 0;
ap_bucket_brigade *bb = NULL;
/* WE probably need to do something to make sure we are respecting the
*/
bb = ap_brigade_create(r->pool);
ap_brigade_append_buckets(bb, ap_bucket_create_mmap(mm, 0, mm->size));
- bytes_sent = ap_pass_brigade(r->filters, bb);
+ ap_pass_brigade(r->filters, bb);
- return bytes_sent;
+ return mm->size; /* XXX - change API to report apr_status_t? */
}
#endif /* USE_MMAP_FILES */
* the current filter. At that point, we can just call the first filter in
* the stack, or r->filters.
*/
-API_EXPORT(int) ap_pass_brigade(ap_filter_t *next, ap_bucket_brigade *bb)
+API_EXPORT(apr_status_t) ap_pass_brigade(ap_filter_t *next, ap_bucket_brigade *bb)
{
if (next) {
return next->filter_func(next, bb);