From b0470cc5acd2563f73d535687b0ea06ee77d7583 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20Malo?= Date: Tue, 24 Apr 2007 22:22:49 +0000 Subject: [PATCH] `build all` git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@532108 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/developer/output-filters.html.en | 213 +++++++++++-------- docs/manual/mod/mod_proxy.html.en | 4 +- docs/manual/mod/mod_proxy.xml.ja | 2 +- 3 files changed, 126 insertions(+), 93 deletions(-) diff --git a/docs/manual/developer/output-filters.html.en b/docs/manual/developer/output-filters.html.en index 2081c2d56d..e887de4fda 100644 --- a/docs/manual/developer/output-filters.html.en +++ b/docs/manual/developer/output-filters.html.en @@ -87,7 +87,8 @@ covers a case where filters are encouraged to generate FLUSH buckets.

-

Example bucket brigade

HEAP FLUSH FILE EOS
+

Example bucket brigade

+ HEAP FLUSH FILE EOS

This shows a bucket brigade which may be passed to a filter; it contains two metadata buckets (FLUSH and @@ -122,12 +123,18 @@ filter chain. But, for good defensive programming, filters should be prepared to accept an empty brigade, and do nothing.

-

How to handle an empty brigade

apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
-    if (APR_BRIGADE_EMPTY(bb)) {
-        return APR_SUCCESS;
-    }
-    ....
+

How to handle an empty brigade

+ apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb)
+ {
+ + if (APR_BRIGADE_EMPTY(bb)) {
+ + return APR_SUCCESS;
+
+ }
+ ....
+
+

top
@@ -145,7 +152,7 @@

There are a variety of functions and macros for traversing and manipulating bucket brigades; see the apr_bucket.h - header for complete coverage. Commonly used macros include: + header for complete coverage. Commonly used macros include:

APR_BRIGADE_FIRST(bb)
@@ -160,7 +167,7 @@
APR_BUCKET_PREV(e)
gives the bucket before bucket e
-

+

The apr_bucket_brigade structure itself is allocated out of a pool, so if a filter creates a new brigade, it @@ -194,7 +201,7 @@

When dealing with non-metadata buckets, it is important to understand that the "apr_bucket *" object is an - abstract representation of data: + abstract representation of data:

  1. The amount of data represented by the bucket may or may not @@ -209,7 +216,7 @@ represents data stored in a file on disk.
- Filters read the data from a bucket using the +

Filters read the data from a bucket using the apr_bucket_read function. When this function is invoked, the bucket may morph into a different bucket type, and may also insert a new bucket into the bucket brigade. @@ -220,7 +227,7 @@ single FILE bucket representing an entire file, 24 kilobytes in size:

-
FILE(0K-24K)
+

FILE(0K-24K)

When this bucket is read, it will read a block of data from the file, morph into a HEAP bucket to represent that @@ -229,7 +236,7 @@ after the apr_bucket_read call, the brigade looks like:

-
HEAP(8K) FILE(8K-24K)
+

HEAP(8K) FILE(8K-24K)

top
@@ -242,20 +249,24 @@ loop is critical to producing a well-behaved output filter.

Taking an example which loops through the entire brigade as - follows: - -

Bad output filter -- do not imitate!

apr_bucket *e = APR_BRIGADE_FIRST(bb);
-const char *data;
-apr_size_t len;
-
-while (e != APR_BRIGADE_SENTINEL(bb)) {
-   apr_bucket_read(e, &data, &length, APR_BLOCK_READ);
-   e = APR_BUCKET_NEXT(e);
-}
-
-return ap_pass_brigade(bb);
- - The above implementation would consume memory proportional to + follows:

+ +

Bad output filter -- do not imitate!

+ apr_bucket *e = APR_BRIGADE_FIRST(bb);
+const char *data;
+apr_size_t len;
+
+while (e != APR_BRIGADE_SENTINEL(bb)) {
+ + apr_bucket_read(e, &data, &length, APR_BLOCK_READ);
+ e = APR_BUCKET_NEXT(e);
+
+}
+
+return ap_pass_brigade(bb); +

+ +

The above implementation would consume memory proportional to content size. If passed a FILE bucket, for example, the entire file contents would be read into memory as each apr_bucket_read call morphed a FILE @@ -265,22 +276,26 @@ return ap_pass_brigade(bb);

amount of memory to filter any brigade; a temporary brigade is needed and must be allocated only once per response, see the Maintaining state section.

-

Better output filter

apr_bucket *e;
-const char *data;
-apr_size_t len;
-
-while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) {
-   rv = apr_bucket_read(e, &data, &length, APR_BLOCK_READ);
-   if (rv) ...;
-   /* Remove bucket e from bb. */
-   APR_BUCKET_REMOVE(e);
-   /* Insert it into  temporary brigade. */
-   APR_BRIGADE_INSERT_HEAD(tmpbb, e);
-   /* Pass brigade downstream. */
-   rv = ap_pass_brigade(f->next, tmpbb);
-   if (rv) ...;
-   apr_brigade_cleanup(tmpbb);
-}
+

Better output filter

+apr_bucket *e;
+const char *data;
+apr_size_t len;
+
+while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) {
+ + rv = apr_bucket_read(e, &data, &length, APR_BLOCK_READ);
+ if (rv) ...;
+ /* Remove bucket e from bb. */
+ APR_BUCKET_REMOVE(e);
+ /* Insert it into temporary brigade. */
+ APR_BRIGADE_INSERT_HEAD(tmpbb, e);
+ /* Pass brigade downstream. */
+ rv = ap_pass_brigade(f->next, tmpbb);
+ if (rv) ...;
+ apr_brigade_cleanup(tmpbb);
+
+} +

top
@@ -294,26 +309,35 @@ while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) { temporary brigade in such a structure, to avoid having to allocate a new brigade per invocation as described in the Brigade structure section.

-

Example code to maintain filter state

struct dummy_state {
-   apr_bucket_brigade *tmpbb;
-   int filter_state;
-   ....
-};
-
-apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
-    struct dummy_state *state;
-
-    state = f->ctx;
-    if (state == NULL) {
-       /* First invocation for this response: initialise state structure. */
-       f->ctx = state = apr_palloc(sizeof *state, f->r->pool);
-       
-       state->tmpbb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
-       state->filter_state = ...;
-    }
-    ...
- +

Example code to maintain filter state

+struct dummy_state {
+ + apr_bucket_brigade *tmpbb;
+ int filter_state;
+ ....
+
+};
+
+apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb)
+{
+ + struct dummy_state *state;
+
+ state = f->ctx;
+ if (state == NULL) {
+ + /* First invocation for this response: initialise state structure. + */
+ f->ctx = state = apr_palloc(sizeof *state, f->r->pool);
+
+ state->tmpbb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
+ state->filter_state = ...;
+
+ }
+ ... +
+

+
top

Buffering buckets

@@ -337,7 +361,7 @@ apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb) used, which will move all the buckets into a separate brigade containing buckets with a lifetime as long as the given pool argument. This function must be used with care, taking into - account the following points: + account the following points:

  1. On return, ap_save_brigade guarantees that all @@ -356,7 +380,7 @@ apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb) non-NULL "saveto" (destination) brigade parameter, the function will create a new brigade, which may cause memory use to be proportional to content size as described in the Brigade structure section.
  2. -

+
Filters must ensure that any buffered data is processed and passed down the filter chain during the last @@ -386,31 +410,40 @@ apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb) script; reading from such a bucket will block when waiting for the CGI script to produce more output.

-

Example code using non-blocking bucket reads

apr_bucket *e;
-apr_read_type_e mode = APR_NONBLOCK_READ;
-
-while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) {
-    apr_status_t rv;
-
-    rv = apr_bucket_read(e, &data, &length, mode);
-    if (rv == APR_EAGAIN && mode == APR_NONBLOCK_READ) {
-        /* Pass down a brigade containing a flush bucket: */
-        APR_BRIGADE_INSERT_TAIL(tmpbb, apr_bucket_flush_create(...));
-        rv = ap_pass_brigade(f->next, tmpbb);
-        apr_brigade_cleanup(tmpbb);
-        if (rv != APR_SUCCESS) return rv;
-
-        /* Retry, using a blocking read. */
-        mode = APR_BLOCK_READ;
-        continue;
-    } else if (rv != APR_SUCCESS) { 
-        /* handle errors */
-    }
-
-    /* Next time, try a non-blocking read first. */
-    mode = APR_NONBLOCK_READ;
-    ...
-}
+

Example code using non-blocking bucket reads

+ +apr_bucket *e;
+apr_read_type_e mode = APR_NONBLOCK_READ;
+
+while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) {
+ + apr_status_t rv;
+
+ rv = apr_bucket_read(e, &data, &length, mode);
+ if (rv == APR_EAGAIN && mode == APR_NONBLOCK_READ) {
+ + /* Pass down a brigade containing a flush bucket: */
+ APR_BRIGADE_INSERT_TAIL(tmpbb, apr_bucket_flush_create(...));
+ rv = ap_pass_brigade(f->next, tmpbb);
+ apr_brigade_cleanup(tmpbb);
+ if (rv != APR_SUCCESS) return rv;
+
+ /* Retry, using a blocking read. */
+ mode = APR_BLOCK_READ;
+ continue;
+
+ } else if (rv != APR_SUCCESS) {
+ + /* handle errors */
+
+ }
+
+ /* Next time, try a non-blocking read first. */
+ mode = APR_NONBLOCK_READ;
+ ...
+
+} +

top
diff --git a/docs/manual/mod/mod_proxy.html.en b/docs/manual/mod/mod_proxy.html.en index 6680f20a47..5ffdc1bdca 100644 --- a/docs/manual/mod/mod_proxy.html.en +++ b/docs/manual/mod/mod_proxy.html.en @@ -324,8 +324,8 @@ proxy and later.

This directive adds a member to a load balancing group. It must be used - within a <Proxy balancer://...> container directive, and can take any - of the parameters available to + within a <Proxy balancer://...> container + directive, and can take any of the parameters available to ProxyPass directives.

One additional parameter is available only to BalancerMember directives: loadfactor. This is the member load factor - a number between 1 diff --git a/docs/manual/mod/mod_proxy.xml.ja b/docs/manual/mod/mod_proxy.xml.ja index bf67fa0960..e42f062dcf 100644 --- a/docs/manual/mod/mod_proxy.xml.ja +++ b/docs/manual/mod/mod_proxy.xml.ja @@ -1,7 +1,7 @@ - +