AP_DECLARE(apr_status_t) ap_filter_setaside_brigade(ap_filter_t *f,
apr_bucket_brigade *bb);
+/*
+ * Adopt a bucket brigade as is (no setaside nor copy).
+ * @param f The current filter
+ * @param bb The bucket brigade adopted. This brigade is always empty
+ * on return
+ * @remark httpd internal, not exported, needed by
+ * ap_core_input_filter
+ */
+void ap_filter_adopt_brigade(ap_filter_t *f, apr_bucket_brigade *bb);
+
/**
* Reinstate a brigade setaside earlier, and calculate the amount of data we
* should write based on the presence of flush buckets, size limits on in
*/
AP_DECLARE_NONSTD(int) ap_filter_input_pending(conn_rec *c);
-/**
+/*
* Recycle removed request filters so that they can be reused for filters
* added later on the same connection. This typically should happen after
* each request handling.
*
* @param c The connection.
+ * @remark httpd internal, not exported, needed by
+ * ap_process_request_after_handler
+ *
*/
-AP_DECLARE(void) ap_filter_recycle(conn_rec *c);
+void ap_filter_recycle(conn_rec *c);
/**
* Flush function for apr_brigade_* calls. This calls ap_pass_brigade
ap_input_mode_t mode, apr_read_type_e block,
apr_off_t readbytes)
{
- apr_status_t rv;
+ apr_status_t rv = APR_SUCCESS;
core_net_rec *net = f->ctx;
core_ctx_t *ctx = net->in_ctx;
const char *str;
if (rv != APR_SUCCESS)
return rv;
}
- else if (APR_BRIGADE_EMPTY(ctx->bb)) {
- return APR_EOF;
+ else {
+ ap_filter_reinstate_brigade(f, ctx->bb, NULL);
+ if (APR_BRIGADE_EMPTY(ctx->bb)) {
+ return APR_EOF;
+ }
}
/* ### This is bad. */
if (APR_STATUS_IS_EAGAIN(rv) && block == APR_NONBLOCK_READ) {
rv = APR_SUCCESS;
}
- return rv;
+ goto cleanup;
}
/* ### AP_MODE_PEEK is a horrific name for this mode because we also
* mean that there is another request, just a blank line.
*/
while (1) {
- if (APR_BRIGADE_EMPTY(ctx->bb))
- return APR_EOF;
+ if (APR_BRIGADE_EMPTY(ctx->bb)) {
+ rv = APR_EOF;
+ goto cleanup;
+ }
e = APR_BRIGADE_FIRST(ctx->bb);
-
rv = apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ);
-
- if (rv != APR_SUCCESS)
- return rv;
+ if (rv != APR_SUCCESS) {
+ goto cleanup;
+ }
c = str;
while (c < str + len) {
else if (*c == APR_ASCII_CR && *(c + 1) == APR_ASCII_LF)
c += 2;
else
- return APR_SUCCESS;
+ goto cleanup;
}
/* If we reach here, we were a bucket just full of CRLFs, so
/* FIXME: Is this the right thing to do in the core? */
apr_bucket_delete(e);
}
- return APR_SUCCESS;
+
+ /* UNREACHABLE */
+ ap_assert(0);
}
/* If mode is EXHAUSTIVE, we want to just read everything until the end
* must be EOS. */
e = apr_bucket_eos_create(f->c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(b, e);
- return APR_SUCCESS;
+
+ rv = APR_SUCCESS;
+ goto cleanup;
}
/* read up to the amount they specified. */
e = APR_BRIGADE_FIRST(ctx->bb);
rv = apr_bucket_read(e, &str, &len, block);
-
- if (APR_STATUS_IS_EAGAIN(rv) && block == APR_NONBLOCK_READ) {
- /* getting EAGAIN for a blocking read is an error; for a
- * non-blocking read, return an empty brigade. */
- return APR_SUCCESS;
- }
- else if (rv != APR_SUCCESS) {
- return rv;
+ if (rv != APR_SUCCESS) {
+ if (APR_STATUS_IS_EAGAIN(rv) && block == APR_NONBLOCK_READ) {
+ /* getting EAGAIN for a blocking read is an error; not for a
+ * non-blocking read, return an empty brigade. */
+ rv = APR_SUCCESS;
+ }
+ goto cleanup;
}
else if (block == APR_BLOCK_READ && len == 0) {
/* We wanted to read some bytes in blocking mode. We read
e = apr_bucket_eos_create(f->c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(b, e);
}
- return APR_SUCCESS;
+ goto cleanup;
}
/* Have we read as much data as we wanted (be greedy)? */
if (len < readbytes) {
apr_size_t bucket_len;
- rv = APR_SUCCESS;
/* We already registered the data in e in len */
e = APR_BUCKET_NEXT(e);
while ((len < readbytes) && (rv == APR_SUCCESS)
rv = apr_brigade_partition(ctx->bb, readbytes, &e);
if (rv != APR_SUCCESS) {
- return rv;
+ goto cleanup;
}
/* Must do move before CONCAT */
{
rv = apr_bucket_copy(e, ©_bucket);
if (rv != APR_SUCCESS) {
- return rv;
+ goto cleanup;
}
APR_BRIGADE_INSERT_TAIL(b, copy_bucket);
}
/* Take what was originally there and place it back on ctx->bb */
APR_BRIGADE_CONCAT(ctx->bb, ctx->tmpbb);
}
- return APR_SUCCESS;
+
+cleanup:
+ ap_filter_adopt_brigade(f, ctx->bb);
+ return rv;
}
static apr_status_t send_brigade_nonblocking(apr_socket_t *s,
return x;
}
-static void make_spare_ring(struct spare_ring **ring, apr_pool_t *p)
+static APR_INLINE
+void make_spare_ring(struct spare_ring **ring, apr_pool_t *p)
{
if (!*ring) {
*ring = apr_palloc(p, sizeof(**ring));
return APR_SUCCESS;
}
-AP_DECLARE(void) ap_filter_recycle(conn_rec *c)
+void ap_filter_recycle(conn_rec *c)
{
struct ap_filter_conn_ctx *x = c->filter_conn_ctx;
return APR_SUCCESS;
}
+void ap_filter_adopt_brigade(ap_filter_t *f, apr_bucket_brigade *bb)
+{
+ struct ap_filter_private *fp = f->priv;
+
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, f->c,
+ "adopt %s brigade to %s brigade in '%s' output filter",
+ APR_BRIGADE_EMPTY(bb) ? "empty" : "full",
+ (!fp->bb || APR_BRIGADE_EMPTY(fp->bb)) ? "empty" : "full",
+ f->frec->name);
+
+ if (!APR_BRIGADE_EMPTY(bb)) {
+ ap_filter_prepare_brigade(f);
+ APR_BRIGADE_CONCAT(fp->bb, bb);
+ }
+}
+
AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f,
apr_bucket_brigade *bb,
apr_bucket **flush_upto)
va_end(args);
return rv;
}
+
AP_DECLARE(void) ap_filter_protocol(ap_filter_t *f, unsigned int flags)
{
f->frec->proto_flags = flags ;