*/
AP_DECLARE(const char *) ap_method_name_of(int methnum);
-int http_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length);
-apr_status_t dechunk_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length);
+apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode);
+apr_status_t dechunk_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode);
/* Hooks */
/*
#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.
- */
+/* ap_input_mode_t - input filtering modes
+ *
+ * AP_MODE_BLOCKING
+ *
+ * The filter shouldn't return until data is received or EOF is hit or an error
+ * occurs.
+ *
+ * AP_MODE_NONBLOCKING
+ *
+ * The filter should process any available data/status as normal, but will not
+ * wait for additional data.
+ *
+ * AP_MODE_PEEK
+ *
+ * The filter should return APR_SUCCESS if data is available or APR_EOF
+ * otherwise. The filter must not return any buckets of data. Data returned
+ * on a subsequent call, when mode is AP_MODE_BLOCKING or AP_MODE_NONBLOCKING.
+ */
+typedef enum {
+ AP_MODE_BLOCKING,
+ AP_MODE_NONBLOCKING,
+ AP_MODE_PEEK
+} ap_input_mode_t;
/*
* FILTER CHAIN
* The return value of a filter should be an APR status value.
*/
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 apr_status_t (*ap_in_filter_func)(ap_filter_t *f, ap_bucket_brigade *b,
+ ap_input_mode_t mode);
typedef union ap_filter_func {
ap_out_filter_func out_func;
ap_in_filter_func in_func;
* 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.
+ * @param mode AP_MODE_BLOCKING, AP_MODE_NONBLOCKING, or AP_MODE_PEEK
* @return apr_status_t value
- * @deffunc apr_status_t ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket, apr_ssize_t length)
+ * @deffunc apr_status_t ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket, ap_input_mode_t mode)
*/
-AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket, apr_ssize_t length);
+AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket,
+ ap_input_mode_t mode);
/**
* Pass the current bucket brigade down to the next filter on the filter
return APR_SUCCESS;
}
-/* 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)
+static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode)
{
ap_bucket *e;
ap_bucket_brigade *b;
} core_output_filter_ctx_t;
#define MAX_IOVEC_TO_WRITE 16
-static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
+static apr_status_t core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
{
apr_status_t rv;
ap_bucket_brigade *more = NULL;
static int getline(char *s, int n, request_rec *r, int fold);
apr_status_t dechunk_filter(ap_filter_t *f, ap_bucket_brigade *bb,
- apr_ssize_t length)
+ ap_input_mode_t mode)
{
apr_status_t rv;
struct dechunk_ctx *ctx = f->ctx;
if (ctx->state == WANT_BODY) {
/* Tell http_filter() how many bytes to deliver. */
f->c->remain = ctx->chunk_size - ctx->bytes_delivered;
- if ((rv = ap_get_brigade(f->next, bb, 999)) != APR_SUCCESS) {
+ if ((rv = ap_get_brigade(f->next, bb, mode)) != APR_SUCCESS) {
return rv;
}
/* Walk through the body, accounting for bytes, and removing an eos bucket if
ap_bucket_brigade *b;
} http_ctx_t;
-apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length)
+apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode)
{
#define ASCII_LF '\012'
ap_bucket *e;
if (!ctx) {
f->ctx = ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
ctx->b = ap_brigade_create(f->c->pool);
- if ((rv = ap_get_brigade(f->next, ctx->b, AP_GET_ANY_AMOUNT)) != APR_SUCCESS) {
- return rv;
- }
}
- else {
+
+ if (mode == AP_MODE_PEEK) {
+ /* XXX make me *try* to read from the network if AP_BRIGADE_EMPTY().
+ * For now, we can't do a non-blocking read so we bypass this.
+ *
+ * Also, note that in the cases where another request can be read now
+ * without blocking, it is likely already in our brigadet, so this hack
+ * isn't so bad after all.
+ */
if (AP_BRIGADE_EMPTY(ctx->b)) {
- if ((rv = ap_get_brigade(f->next, ctx->b, AP_GET_LINE)) != APR_SUCCESS) {
- return rv;
- }
+ return APR_EOF;
+ }
+ else {
+ return APR_SUCCESS;
+ }
+ }
+
+ if (AP_BRIGADE_EMPTY(ctx->b)) {
+ if ((rv = ap_get_brigade(f->next, ctx->b, mode)) != APR_SUCCESS) {
+ return rv;
}
}
while (1) {
if (AP_BRIGADE_EMPTY(b)) {
- if (ap_get_brigade(c->input_filters, b, AP_GET_LINE) != APR_SUCCESS ||
+ if (ap_get_brigade(c->input_filters, b, AP_MODE_BLOCKING) != APR_SUCCESS ||
AP_BRIGADE_EMPTY(b)) {
return -1;
}
* save data off to the side should probably create their own temporary
* brigade especially for that use.
*/
-AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
- ap_bucket_brigade *bb, apr_ssize_t length)
+AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next, ap_bucket_brigade *bb,
+ ap_input_mode_t mode)
{
if (next) {
- return next->frec->filter_func.in_func(next, bb, length);
+ return next->frec->filter_func.in_func(next, bb, mode);
}
return AP_NOBODY_READ;
}