]> granicus.if.org Git - apache/commitdiff
Implement a length argument on input filters. There are three possible
authorRyan Bloom <rbb@apache.org>
Thu, 12 Oct 2000 16:35:39 +0000 (16:35 +0000)
committerRyan Bloom <rbb@apache.org>
Thu, 12 Oct 2000 16:35:39 +0000 (16:35 +0000)
values for the length, -1, 0, and a positive number.  -1 means that the
next filter should return all the data it has, the current filter will
take care to ensure that the protocol is followed.  Most filters will
never use this, because it implies they are implementing a conn_based
input filter.  0 means give me exactly one line of data.  A positive
number means give me a maximum of n bytes.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86567 13f79535-47bb-0310-9956-ffa450edef68

include/http_protocol.h
include/httpd.h
include/util_filter.h
modules/http/http_core.c
modules/http/http_protocol.c
server/util_filter.c

index 1900d36c6de4134b9e55101f03fbf89543a11e5a..789ba228ed2580a85bde7b9a79bb62f88ce43e5c 100644 (file)
@@ -529,7 +529,7 @@ API_EXPORT(int) ap_method_number_of(const char *method);
  */
 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 */
   /*
index fe63ab82be7d155aa14c94fb0bba6486c9d84eb1..9f6fe25e90a909a703e77e3160c96e79329f2e49 100644 (file)
@@ -906,8 +906,6 @@ struct conn_rec {
     /** 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... */
index f6b3791f198ece891f4b84e36f9018b47b532366..927880374aadd1b68f2fc00716425ebd220de1f2 100644 (file)
@@ -74,6 +74,12 @@ extern "C" {
 #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
  *
@@ -125,7 +131,12 @@ typedef struct ap_filter_t ap_filter_t;
  *
  * 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:
@@ -232,10 +243,19 @@ struct ap_filter_t {
  * 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
@@ -264,10 +284,10 @@ API_EXPORT(apr_status_t) ap_pass_brigade(ap_filter_t *filter, ap_bucket_brigade
  * @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():
@@ -285,10 +305,10 @@ API_EXPORT(void) ap_register_input_filter(const char *name,
  * @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);
 
 /*
index d71a5bc58963ac43cb7979bda3b3bd1615fbc24e..2c3329dda57d752929d4d4dbfc9b5ec65722330f 100644 (file)
@@ -3303,7 +3303,12 @@ static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
     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;
index 6228f2523940fe3c850712256750f864c477d50e..814c12e6d320292249e93cf977c97abdff47d0ac 100644 (file)
@@ -860,13 +860,13 @@ typedef struct http_filter_ctx {
     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;
@@ -874,7 +874,7 @@ apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b)
 
     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;
         }
     }
@@ -884,14 +884,14 @@ apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b)
             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;
@@ -903,24 +903,22 @@ apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b)
                 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));
@@ -960,7 +958,7 @@ static int getline(char *s, int n, conn_rec *c, int fold)
 
     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;
             }
         }
@@ -2286,7 +2284,6 @@ API_EXPORT(int) ap_setup_client_block(request_rec *r, int read_policy)
         }
 
         r->remaining = atol(lenp);
-        r->connection->remaining = r->remaining;
     }
 
     if ((r->read_body == REQUEST_NO_BODY) &&
@@ -2407,8 +2404,7 @@ API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
             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.
                      */
index 14ef6553d0e9a2abc25573b6a5aa90921a93d85f..9be310b5ccfe6ad80347f39c457fe424842570f5 100644 (file)
@@ -103,18 +103,22 @@ static void register_filter(const char *name,
 }
 
 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, 
                     &registered_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, 
                     &registered_output_filters);
 }
 
@@ -191,10 +195,11 @@ API_EXPORT(void) ap_add_output_filter(const char *name, void *ctx,
  * 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;
 }
@@ -210,7 +215,7 @@ API_EXPORT(apr_status_t) ap_pass_brigade(ap_filter_t *next, ap_bucket_brigade *b
         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;
 }