Changes with Apache 2.0.31-dev
+ *) Split out blocking from the mode in the input filters.
+ [Justin Erenkrantz]
+
*) Fix a segfault in mod_include. [Justin Erenkrantz, Jeff Trawick]
*) Cause Win32 to capture all child-worker process errors in
* 20020111 (2.0.31-dev) bump for ETag fields added at end of cor_dir_config
* 20020114 (2.0.31-dev) mod_dav changed how it asks its provider to fulfill
* a GET request
+ * 20020118 (2.0.31-dev) Input filtering split of blocking and mode
*/
#define MODULE_MAGIC_COOKIE 0x41503230UL /* "AP20" */
/**
* input filtering modes
- * @see apr_read_type_e in apr_buckets.h -- this is a superset of it
*/
typedef enum {
- /** The filter shouldn't return until data is received or EOF is hit
- * or an error occurs. */
- AP_MODE_BLOCKING = APR_BLOCK_READ,
- /** The filter should process any available data/status as normal,
- * but will not wait for additional data. */
- AP_MODE_NONBLOCKING = APR_NONBLOCK_READ,
- /** 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. */
- AP_MODE_PEEK,
- /*
- * the filter should initialize the connection if needed,
- * NNTP or FTP over SSL for example.
+ /** The filter should return at most *readbytes data. */
+ AP_MODE_READBYTES,
+ /** The filter should return at most one line of CRLF data.
+ * (If a potential line is too long or no CRLF is found, the
+ * filter may return partial data).
+ */
+ AP_MODE_GETLINE,
+ /** The filter should implicitly eat any CRLF pairs that it sees. */
+ AP_MODE_EATCRLF,
+ /** The filter read should be treated as speculative and any returned
+ * data should be stored for later retrieval in another mode. */
+ AP_MODE_SPECULATIVE,
+ /** The filter read should be exhaustive and read until it can not
+ * read any more.
+ * Use this mode with extreme caution.
+ */
+ AP_MODE_EXHAUSTIVE,
+ /** The filter should initialize the connection if needed,
+ * NNTP or FTP over SSL for example.
*/
AP_MODE_INIT
} ap_input_mode_t;
*/
typedef apr_status_t (*ap_out_filter_func)(ap_filter_t *f, apr_bucket_brigade *b);
typedef apr_status_t (*ap_in_filter_func)(ap_filter_t *f, apr_bucket_brigade *b,
- ap_input_mode_t mode, apr_off_t *readbytes);
+ ap_input_mode_t mode, apr_read_type_e block, apr_off_t *readbytes);
typedef union ap_filter_func {
ap_out_filter_func out_func;
* filter doesn't read from the network, then ::AP_NOBODY_READ is returned.
* @param filter The next filter in the chain
* @param bucket The current bucket brigade
- * @param mode ::AP_MODE_BLOCKING, ::AP_MODE_NONBLOCKING, or ::AP_MODE_PEEK
- * @param readbytes How many bytes to read from the next filter. 0 means that
- * a single line should be read.
+ * @param mode The way in which the data should be read
+ * @param block How the operations should be performed
+ * ::APR_BLOCK_READ, ::APR_NONBLOCK_READ
+ * @param readbytes How many bytes to read from the next filter.
*/
-AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket,
- ap_input_mode_t mode, apr_off_t *readbytes);
+AP_DECLARE(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);
/**
* Pass the current bucket brigade down to the next filter on the filter
for ( ; ; ) {
/* Get a single line of input from the client */
- if ((rv = ap_get_brigade(c->input_filters, bb,
- AP_MODE_BLOCKING, &zero) != APR_SUCCESS ||
+ if ((rv = ap_get_brigade(c->input_filters, bb, AP_MODE_GETLINE,
+ APR_BLOCK_READ, &zero) != APR_SUCCESS ||
APR_BRIGADE_EMPTY(bb))) {
apr_brigade_destroy(bb);
break;
static apr_status_t CaseFilterInFilter(ap_filter_t *f,
apr_bucket_brigade *pbbOut,
ap_input_mode_t eMode,
+ apr_read_type_e eBlock,
apr_off_t *nBytes)
{
request_rec *r = f->r;
}
if (APR_BRIGADE_EMPTY(pCtx->pbbTmp)) {
- ret = ap_get_brigade(f->next, pCtx->pbbTmp, eMode, nBytes);
+ ret = ap_get_brigade(f->next, pCtx->pbbTmp, eMode, eBlock, nBytes);
- if (eMode == AP_MODE_PEEK || ret != APR_SUCCESS)
+ if (eMode == AP_MODE_EATCRLF || ret != APR_SUCCESS)
return ret;
}
break;
}
- ret=apr_bucket_read(pbktIn, &data, &len, eMode);
+ ret=apr_bucket_read(pbktIn, &data, &len, eBlock);
if(ret != APR_SUCCESS)
return ret;
}
static int xlate_in_filter(ap_filter_t *f, apr_bucket_brigade *bb,
- ap_input_mode_t mode, apr_off_t *readbytes)
+ ap_input_mode_t mode, apr_read_type_e block,
+ apr_off_t *readbytes)
{
apr_status_t rv;
charset_req_t *reqinfo = ap_get_module_config(f->r->request_config,
}
if (ctx->noop) {
- return ap_get_brigade(f->next, bb, mode, readbytes);
+ return ap_get_brigade(f->next, bb, mode, block, readbytes);
}
if (APR_BRIGADE_EMPTY(ctx->bb)) {
- if ((rv = ap_get_brigade(f->next, bb, mode, readbytes)) != APR_SUCCESS) {
+ if ((rv = ap_get_brigade(f->next, bb, mode, block,
+ readbytes)) != APR_SUCCESS) {
return rv;
}
}
#if 0
static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb,
- ap_input_mode_t mode, apr_off_t *readbytes)
+ ap_input_mode_t mode, apr_read_type_e block,
+ apr_off_t *readbytes)
{
apr_status_t rv;
apr_bucket *b;
apr_ssize_t len;
char *zero;
- rv = ap_get_brigade(f->next, bb, mode, readbytes);
+ rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
if (rv != APR_SUCCESS) {
return rv;
}
* are successfully parsed.
*/
apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
- ap_input_mode_t mode, apr_off_t *readbytes)
+ ap_input_mode_t mode, apr_read_type_e block,
+ apr_off_t *readbytes)
{
apr_bucket *e;
http_ctx_t *ctx = f->ctx;
apr_status_t rv;
/* just get out of the way of this thing. */
- if (mode == AP_MODE_PEEK) {
- return ap_get_brigade(f->next, b, mode, readbytes);
+ if (mode == AP_MODE_EATCRLF) {
+ return ap_get_brigade(f->next, b, mode, block, readbytes);
}
if (!ctx) {
AP_DEBUG_ASSERT(*readbytes > 0); /* shouldn't be in getline mode */
}
- rv = ap_get_brigade(f->next, b, mode, readbytes);
+ rv = ap_get_brigade(f->next, b, mode, block, readbytes);
if (rv != APR_SUCCESS) {
return rv;
/* read until we get a non-empty brigade */
while (APR_BRIGADE_EMPTY(bb)) {
apr_off_t len_read = bufsiz;
- if (ap_get_brigade(r->input_filters, bb, AP_MODE_BLOCKING,
- &len_read) != APR_SUCCESS) {
+ if (ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
+ APR_BLOCK_READ, &len_read) != APR_SUCCESS) {
/* if we actually fail here, we want to just return and
* stop trying to read data from the client.
*/
/* ### shouldn't this read from the connection input filters? */
/* ### is zero correct? that means "read one line" */
if (!r->connection->keepalive ||
- ap_get_brigade(r->input_filters, bb, AP_MODE_PEEK, &zero) != APR_SUCCESS) {
+ ap_get_brigade(r->input_filters, bb, AP_MODE_EATCRLF,
+ APR_NONBLOCK_READ, &zero) != APR_SUCCESS) {
apr_bucket *e = apr_bucket_flush_create();
/* We just send directly to the connection based filters. At
* These (input) filters are internal to the mod_core operation.
*/
apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
- ap_input_mode_t mode, apr_off_t *readbytes);
+ ap_input_mode_t mode, apr_read_type_e block,
+ apr_off_t *readbytes);
char *ap_response_code_string(request_rec *r, int error_index);
"proxy: FTP: start body send");
/* read the body, pass it to the output filters */
- while (ap_get_brigade(remote->input_filters, bb, AP_MODE_BLOCKING, &readbytes) == APR_SUCCESS) {
+ while (ap_get_brigade(remote->input_filters, bb, AP_MODE_READBYTES,
+ APR_BLOCK_READ, &readbytes) == APR_SUCCESS) {
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
ap_pass_brigade(r->output_filters, bb);
break;
apr_bucket *e;
readbytes = AP_IOBUFSIZE;
while (ap_get_brigade(rp->input_filters,
- bb,
- AP_MODE_BLOCKING,
+ bb,
+ AP_MODE_READBYTES,
+ APR_BLOCK_READ,
&readbytes) == APR_SUCCESS) {
#if DEBUGGING
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
apr_off_t zero = 0;
/* get brigade from network one line at a time */
if (APR_SUCCESS != (rv = ap_get_brigade(c->input_filters, bb,
- AP_MODE_BLOCKING,
+ AP_MODE_GETLINE,
+ APR_BLOCK_READ,
&zero /* readline */))) {
return rv;
}
ap_filter_t *f;
apr_status_t rc;
ap_input_mode_t mode;
- int getline;
+ apr_read_type_e block;
apr_bucket_brigade *bb;
apr_bucket *bucket;
char_buffer_t cbuf;
/* first use data already read from socket if any */
if ((len = char_buffer_read(&inbio->cbuf, in, inl))) {
- if ((len <= inl) || inbio->getline) {
+ if ((len <= inl) || inbio->mode == AP_MODE_GETLINE) {
return len;
}
}
}
if (APR_BRIGADE_EMPTY(inbio->bb)) {
+ /* We will always call with READBYTES even if the user wants
+ * GETLINE.
+ */
inbio->rc = ap_get_brigade(inbio->f->next, inbio->bb,
- inbio->mode, &readbytes);
+ AP_MODE_READBYTES, inbio->block, &readbytes);
if ((inbio->rc != APR_SUCCESS) || APR_BRIGADE_EMPTY(inbio->bb))
{
inbio->bucket = APR_BRIGADE_FIRST(inbio->bb);
inbio->rc = apr_bucket_read(inbio->bucket,
- &buf, &buf_len, inbio->mode);
+ &buf, &buf_len, inbio->block);
if (inbio->rc != APR_SUCCESS) {
apr_bucket_delete(inbio->bucket);
}
}
- if (inbio->getline) {
+ if (inbio->mode == AP_MODE_GETLINE) {
/* only read from the socket once in getline mode.
* since callers buffer size is likely much larger than
* the request headers. caller can always come back for more
if ((bytes = char_buffer_read(&ctx->cbuf, buf, wanted))) {
*len = bytes;
- if ((*len >= wanted) || ctx->inbio.getline) {
+ if ((*len >= wanted) || ctx->inbio.mode == AP_MODE_GETLINE) {
return APR_SUCCESS;
}
}
const char *pos;
apr_status_t status;
- ctx->inbio.getline = 1;
status = ssl_io_input_read(ctx, buf, len);
- ctx->inbio.getline = 0;
if (status != APR_SUCCESS) {
return status;
static apr_status_t ssl_io_filter_Input(ap_filter_t *f,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
+ apr_read_type_e block,
apr_off_t *readbytes)
{
apr_status_t status;
int is_init = (mode == AP_MODE_INIT);
/* XXX: we don't currently support peek or readbytes == -1 */
- if (mode == AP_MODE_PEEK || *readbytes == -1) {
+ if (mode == AP_MODE_EATCRLF || *readbytes == -1) {
return APR_ENOTIMPL;
}
- ctx->inbio.mode = is_init ? AP_MODE_BLOCKING : mode;
+ ctx->inbio.mode = mode;
+ ctx->inbio.block = block;
/* XXX: we could actually move ssl_hook_process_connection to an
* ap_hook_process_connection but would still need to call it for
return APR_SUCCESS;
}
- if (bytes > 0) {
+ if (ctx->inbio.mode == AP_MODE_READBYTES) {
/* Protected from truncation, bytes < MAX_SIZE_T */
if (bytes < len) {
len = (apr_size_t)bytes;
}
- ctx->inbio.getline = 0;
status = ssl_io_input_read(ctx, ctx->buffer, &len);
}
- else {
+ else if (ctx->inbio.mode == AP_MODE_GETLINE) {
status = ssl_io_input_getline(ctx, ctx->buffer, &len);
}
+ else {
+ /* We have no idea what you are talking about, so return an error. */
+ return APR_ENOTIMPL;
+ }
if (status != APR_SUCCESS) {
return ssl_io_filter_error(f, bb, status);
ctx->inbio.f = frec->pInputFilter;
ctx->inbio.bb = apr_brigade_create(c->pool);
ctx->inbio.bucket = NULL;
- ctx->inbio.getline = 0;
ctx->inbio.cbuf.length = 0;
ctx->cbuf.length = 0;
return ap_pass_brigade(r->output_filters, bb);
}
-static int net_time_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_off_t *readbytes)
+static int net_time_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ ap_input_mode_t mode, apr_read_type_e block,
+ apr_off_t *readbytes)
{
int keptalive = f->c->keepalive == 1;
apr_socket_t *csd = ap_get_module_config(f->c->conn_config, &core_module);
*first_line = 1;
}
- if (mode != AP_MODE_INIT && mode != AP_MODE_PEEK) {
+ if (mode != AP_MODE_INIT && mode != AP_MODE_EATCRLF) {
if (*first_line) {
apr_setsocketopt(csd, APR_SO_TIMEOUT,
(int)(keptalive
}
}
}
- return ap_get_brigade(f->next, b, mode, readbytes);
+ return ap_get_brigade(f->next, b, mode, block, readbytes);
}
-static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_off_t *readbytes)
+static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ ap_input_mode_t mode, apr_read_type_e block,
+ apr_off_t *readbytes)
{
apr_bucket *e;
apr_status_t rv;
/* ### AP_MODE_PEEK is a horrific name for this mode because we also
* eat any CRLFs that we see. That's not the obvious intention of
* this mode. Determine whether anyone actually uses this or not. */
- if (mode == AP_MODE_PEEK) {
+ if (mode == AP_MODE_EATCRLF) {
apr_bucket *e;
const char *c;
* This is just an all-around bad idea. We may be better off by
* just closing the socket. Determine whether anyone uses this.
*/
- if (*readbytes == -1) {
+ if (mode == AP_MODE_EXHAUSTIVE) {
apr_bucket *e;
apr_off_t total;
APR_BRIGADE_INSERT_TAIL(b, e);
return APR_SUCCESS;
}
- /* readbytes == 0 is "read a single line". otherwise, read a block. */
- if (*readbytes) {
+ /* read up to the amount they specified. */
+ if (mode == AP_MODE_READBYTES) {
apr_off_t total;
apr_bucket *e;
apr_bucket_brigade *newbb;
AP_DEBUG_ASSERT(*readbytes > 0);
e = APR_BRIGADE_FIRST(ctx->b);
- rv = apr_bucket_read(e, &str, &len, mode);
+ rv = apr_bucket_read(e, &str, &len, block);
if (APR_STATUS_IS_EAGAIN(rv)) {
*readbytes = 0;
const char *pos;
e = APR_BRIGADE_FIRST(ctx->b);
- rv = apr_bucket_read(e, &str, &len, mode);
+ rv = apr_bucket_read(e, &str, &len, block);
/* We should treat EAGAIN here the same as we do for EOF (brigade is
* empty). We do this by returning whatever we have read. This may
/* ### this "read one line" doesn't seem right... shouldn't we be
### reading large chunks of data or something?
*/
- while (ap_get_brigade(r->input_filters, bb, AP_MODE_NONBLOCKING,
- &zero /* read one line */) == APR_SUCCESS) {
+ while (ap_get_brigade(r->input_filters, bb, AP_MODE_GETLINE,
+ APR_NONBLOCK_READ, &zero) == APR_SUCCESS) {
apr_bucket *e;
APR_BRIGADE_FOREACH(e, bb) {
const char *str;
}
static apr_status_t perchild_buffer(ap_filter_t *f, apr_bucket_brigade *b,
- ap_input_mode_t mode, apr_off_t *readbytes)
+ ap_input_mode_t mode,
+ apr_read_type_e block,
+ apr_off_t *readbytes)
{
apr_bucket *e;
apr_status_t rv;
const char *str;
apr_size_t len;
- if ((rv = ap_get_brigade(f->next, b, mode, readbytes)) != APR_SUCCESS) {
+ if ((rv = ap_get_brigade(f->next, b, mode, block,
+ readbytes)) != APR_SUCCESS) {
return rv;
}
/* ### this "read one line" doesn't seem right... shouldn't we be
### reading large chunks of data or something?
*/
- while (ap_get_brigade(r->input_filters, bb, AP_MODE_NONBLOCKING,
- &zero /* read one line */) == APR_SUCCESS) {
+ while (ap_get_brigade(r->input_filters, bb, AP_MODE_GETLINE,
+ APR_NONBLOCK_READ, &zero) == APR_SUCCESS) {
apr_bucket *e;
APR_BRIGADE_FOREACH(e, bb) {
const char *str;
}
static apr_status_t perchild_buffer(ap_filter_t *f, apr_bucket_brigade *b,
- ap_input_mode_t mode, apr_off_t *readbytes)
+ ap_input_mode_t mode,
+ apr_read_type_e block,
+ apr_off_t *readbytes)
{
apr_bucket *e;
apr_status_t rv;
const char *str;
apr_size_t len;
- if ((rv = ap_get_brigade(f->next, b, mode, readbytes)) != APR_SUCCESS) {
+ if ((rv = ap_get_brigade(f->next, b, mode, block,
+ readbytes)) != APR_SUCCESS) {
return rv;
}
if (APR_BRIGADE_EMPTY(b)) {
apr_off_t zero = 0;
if ((retval = ap_get_brigade(r->input_filters, b,
- AP_MODE_BLOCKING,
- &zero /* readline */)) != APR_SUCCESS ||
+ AP_MODE_GETLINE,
+ APR_BLOCK_READ,
+ &zero)) != APR_SUCCESS ||
APR_BRIGADE_EMPTY(b)) {
apr_brigade_destroy(b);
return -1;
AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
+ apr_read_type_e block,
apr_off_t *readbytes)
{
if (next) {
- return next->frec->filter_func.in_func(next, bb, mode, readbytes);
+ return next->frec->filter_func.in_func(next, bb, mode, block,
+ readbytes);
}
return AP_NOBODY_READ;
}