httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From minf...@apache.org
Subject svn commit: r910017 - in /httpd/httpd/trunk: CHANGES docs/manual/filter.xml docs/manual/mod/allmodules.xml docs/manual/mod/mod_reflector.xml modules/filters/config.m4 modules/filters/mod_reflector.c
Date Sun, 14 Feb 2010 15:09:57 GMT
Author: minfrin
Date: Sun Feb 14 15:09:53 2010
New Revision: 910017

URL: http://svn.apache.org/viewvc?rev=910017&view=rev
Log:
Introduce mod_reflector, a handler capable of reflecting POSTed
request bodies back within the response through the output filter
stack. Can be used to turn an output filter into a web service.

Added:
    httpd/httpd/trunk/docs/manual/mod/mod_reflector.xml
    httpd/httpd/trunk/modules/filters/mod_reflector.c
Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/docs/manual/filter.xml
    httpd/httpd/trunk/docs/manual/mod/allmodules.xml
    httpd/httpd/trunk/modules/filters/config.m4

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=910017&r1=910016&r2=910017&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sun Feb 14 15:09:53 2010
@@ -2,6 +2,11 @@
 
 Changes with Apache 2.3.7
 
+  *) Introduce mod_reflector, a handler capable of reflecting POSTed
+     request bodies back within the response through the output filter
+     stack. Can be used to turn an output filter into a web service.
+     [Graham Leggett]
+
   *) mod_proxy_http: Make sure that when an ErrorDocument is served
      from a reverse proxied URL, that the subrequest respects the status
      of the original request. This brings the behaviour of proxy_handler

Modified: httpd/httpd/trunk/docs/manual/filter.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/filter.xml?rev=910017&r1=910016&r2=910017&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/filter.xml (original)
+++ httpd/httpd/trunk/docs/manual/filter.xml Sun Feb 14 15:09:53 2010
@@ -37,6 +37,7 @@
         <module>mod_ext_filter</module>
         <module>mod_include</module>
         <module>mod_charset_lite</module>
+        <module>mod_reflector</module>
       </modulelist>
       <directivelist>
         <directive module="mod_filter">FilterChain</directive>
@@ -47,6 +48,7 @@
         <directive module="mod_mime">AddOutputFilter</directive>
         <directive module="mod_mime">RemoveInputFilter</directive>
         <directive module="mod_mime">RemoveOutputFilter</directive>
+        <directive module="mod_reflector">ReflectorHeader</directive>
         <directive module="mod_ext_filter">ExtFilterDefine</directive>
         <directive module="mod_ext_filter">ExtFilterOptions</directive>
         <directive module="core">SetInputFilter</directive>
@@ -118,6 +120,25 @@
 </ul>
 </section>
 
+<section id="service">
+
+<title>Exposing Filters as an HTTP Service</title>
+<p>Filters can be used to process content originating from the client in
+addition to processing content originating on the server using the
+<module>mod_reflector</module> module.</p>
+
+<p><module>mod_reflector</module> accepts POST requests from clients, and
reflects
+the content request body received within the POST request back in the response,
+passing through the output filter stack on the way back to the client.</p>
+
+<p>This technique can be used as an alternative to a web service running within
+an application server stack, where an output filter provides the transformation
+required on the request body. For example, the <module>mod_deflate</module>
+module might be used to provide a general compression service, or an image
+transformation filter might be turned into an image transformation service.</p>
+    
+</section>
+  
 <section id="using">
 <title>Using Filters</title>
 <p>There are two ways to use filtering: Simple and Dynamic.

Modified: httpd/httpd/trunk/docs/manual/mod/allmodules.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/allmodules.xml?rev=910017&r1=910016&r2=910017&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/allmodules.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/allmodules.xml Sun Feb 14 15:09:53 2010
@@ -75,6 +75,7 @@
   <modulefile>mod_proxy_ftp.xml</modulefile>
   <modulefile>mod_proxy_http.xml</modulefile>
   <modulefile>mod_proxy_scgi.xml</modulefile>
+  <modulefile>mod_reflector.xml</modulefile>
   <modulefile>mod_remoteip.xml</modulefile>
   <modulefile>mod_reqtimeout.xml</modulefile>
   <modulefile>mod_request.xml</modulefile>

Added: httpd/httpd/trunk/docs/manual/mod/mod_reflector.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_reflector.xml?rev=910017&view=auto
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_reflector.xml (added)
+++ httpd/httpd/trunk/docs/manual/mod/mod_reflector.xml Sun Feb 14 15:09:53 2010
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
+<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
+<!-- $LastChangedRevision: 894290 $ -->
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<modulesynopsis metafile="mod_reflector.xml.meta">
+
+<name>mod_reflector</name>
+<description>Reflect a request body as a response via the output filter stack.</description>
+<status>Base</status>
+<sourcefile>mod_reflector.c</sourcefile>
+<identifier>reflector_module</identifier>
+<compatibility>Version 2.3 and later</compatibility>
+
+<summary>
+    <p>This module allows request bodies to be reflected back to the
+    client, in the process passing the request through the output filter
+    stack. A suitably configured chain of filters can be used to transform
+    the request into a response. This module can used to turn an output
+    filter into an HTTP service.</p>
+</summary>
+
+<section id="examples"><title>Examples</title>
+    <dl>
+    <dt>Compression service</dt>
+    <dd>Pass the request body through the DEFLATE filter to compress the
+    body. This request requires a Content-Encoding request header containing
+    "gzip" for the filter to return compressed data.
+    <example>
+      &lt;Location /compress&gt;<br/>
+        SetHandler reflector<br/>
+        SetOutputFilter DEFLATE<br/>
+      &lt;/Location&gt;
+    </example>
+    </dd>
+
+    <dt>Image downsampling service</dt>
+    <dd>Pass the request body through an image downsampling filter, and reflect
+    the results to the caller.
+    <example>
+      &lt;Location /downsample&gt;<br/>
+        SetHandler reflector<br/>
+        SetOutputFilter DOWNSAMPLE<br/>
+      &lt;/Location&gt;
+    </example>
+    </dd>
+    </dl>
+</section>
+
+<directivesynopsis>
+<name>ReflectorHeader</name>
+<description>Reflect an input header to the output headers</description>
+<syntax>ReflectorHeader <var>inputheader</var> <var>[outputheader]</var></syntax>
+<contextlist><context>server config</context><context>virtual host</context>
+<context>directory</context><context>.htaccess</context></contextlist>
+<override>Options</override>
+
+<usage>
+    <p>This directive controls the reflection of request headers to the response.
+    The first argument is the name of the request header to copy. If the optional
+    second argument is specified, it will be used as the name of the response
+    header, otherwise the original request header name will be used.</p>
+</usage>
+</directivesynopsis>
+
+</modulesynopsis>

Modified: httpd/httpd/trunk/modules/filters/config.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/config.m4?rev=910017&r1=910016&r2=910017&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/filters/config.m4 (original)
+++ httpd/httpd/trunk/modules/filters/config.m4 Sun Feb 14 15:09:53 2010
@@ -11,6 +11,7 @@
 APACHE_MODULE(request, Request Body Filtering, , , yes)
 APACHE_MODULE(include, Server Side Includes, , , yes)
 APACHE_MODULE(filter, Smart Filtering, , , yes)
+APACHE_MODULE(reflector, Reflect request through the output filter stack, , , yes)
 APACHE_MODULE(substitute, response content rewrite-like filtering, , , most)
 
 sed_obj="mod_sed.lo sed0.lo sed1.lo regexp.lo"

Added: httpd/httpd/trunk/modules/filters/mod_reflector.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/mod_reflector.c?rev=910017&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/filters/mod_reflector.c (added)
+++ httpd/httpd/trunk/modules/filters/mod_reflector.c Sun Feb 14 15:09:53 2010
@@ -0,0 +1,231 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_tables.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_request.h"
+
+module AP_MODULE_DECLARE_DATA reflector_module;
+
+typedef struct {
+    apr_table_t *headers;
+} reflector_cfg;
+
+static int header_do(void *dummy, const char *key, const char *value)
+{
+    request_rec *r = (request_rec *) dummy;
+    const char *payload;
+
+    payload = apr_table_get(r->headers_in, key);
+    if (payload) {
+        apr_table_setn(r->headers_out, value, payload);
+    }
+
+    return 1;
+}
+
+static int reflector_handler(request_rec * r)
+{
+    apr_bucket_brigade *bbin, *bbout;
+    apr_bucket *e;
+    reflector_cfg *conf;
+    apr_status_t status;
+
+    if (strcmp(r->handler, "reflector")) {
+        return DECLINED;
+    }
+
+    conf = (reflector_cfg *) ap_get_module_config(r->per_dir_config,
+                                                  &reflector_module);
+
+    ap_allow_methods(r, 1, "POST", "OPTIONS", NULL);
+
+    if (r->method_number == M_OPTIONS) {
+        return ap_send_http_options(r);
+    }
+
+    else if (r->method_number == M_POST) {
+        const char *content_length, *content_type;
+        int seen_eos;
+
+        /*
+         * Sometimes we'll get in a state where the input handling has
+         * detected an error where we want to drop the connection, so if
+         * that's the case, don't read the data as that is what we're trying
+         * to avoid.
+         *
+         * This function is also a no-op on a subrequest.
+         */
+        if (r->main || r->connection->keepalive == AP_CONN_CLOSE ||
+            ap_status_drops_connection(r->status)) {
+            return OK;
+        }
+
+        /* copy headers from in to out if configured */
+        apr_table_do(header_do, r, conf->headers, NULL);
+
+        /* last modified defaults to now, unless otherwise set on the way in */
+        if (!apr_table_get(r->headers_out, "Last-Modified")) {
+            ap_update_mtime(r, apr_time_now());
+            ap_set_last_modified(r);
+        }
+        apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");
+
+        /* reflect the content length, if present */
+        if ((content_length = apr_table_get(r->headers_in, "Content-Length"))) {
+            apr_off_t offset;
+
+            apr_strtoff(&offset, content_length, NULL, 10);
+            ap_set_content_length(r, offset);
+
+        }
+
+        /* reflect the content type, if present */
+        if ((content_type = apr_table_get(r->headers_in, "Content-Type"))) {
+
+            ap_set_content_type(r, content_type);
+
+        }
+
+        bbin = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+        bbout = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+
+        seen_eos = 0;
+        do {
+            apr_bucket *bucket;
+
+            status = ap_get_brigade(r->input_filters, bbin, AP_MODE_READBYTES,
+                                    APR_BLOCK_READ, HUGE_STRING_LEN);
+
+            if (status != APR_SUCCESS) {
+                if (status == AP_FILTER_ERROR) {
+                    apr_brigade_destroy(bbin);
+                    return status;
+                }
+                else {
+                    apr_brigade_destroy(bbin);
+                    return HTTP_BAD_REQUEST;
+                }
+            }
+
+            for (bucket = APR_BRIGADE_FIRST(bbin);
+                 bucket != APR_BRIGADE_SENTINEL(bbin);
+                 bucket = APR_BUCKET_NEXT(bucket)) {
+                const char *data;
+                apr_size_t len;
+
+                if (APR_BUCKET_IS_EOS(bucket)) {
+                    seen_eos = 1;
+                    break;
+                }
+
+                /* These are metadata buckets. */
+                if (bucket->length == 0) {
+                    continue;
+                }
+
+                /*
+                 * We MUST read because in case we have an unknown-length
+                 * bucket or one that morphs, we want to exhaust it.
+                 */
+                status = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
+                if (status != APR_SUCCESS) {
+                    apr_brigade_destroy(bbin);
+                    return HTTP_BAD_REQUEST;
+                }
+
+                apr_brigade_write(bbout, NULL, NULL, data, len);
+
+                status = ap_pass_brigade(r->output_filters, bbout);
+                if (status != APR_SUCCESS) {
+                    /* no way to know what type of error occurred */
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r,
+                             "default_handler: ap_pass_brigade returned %i",
+                                  status);
+                    return HTTP_INTERNAL_SERVER_ERROR;
+                }
+
+            }
+
+            apr_brigade_cleanup(bbin);
+
+        } while (!seen_eos);
+
+        return OK;
+
+    }
+
+    else {
+        return HTTP_METHOD_NOT_ALLOWED;
+    }
+
+}
+
+static void *create_reflector_dir_config(apr_pool_t * p, char *d)
+{
+    reflector_cfg *conf = apr_pcalloc(p, sizeof(reflector_cfg));
+
+    conf->headers = apr_table_make(p, 8);
+
+    return conf;
+}
+
+static void *merge_reflector_dir_config(apr_pool_t * p, void *basev, void *addv)
+{
+    reflector_cfg *new = (reflector_cfg *) apr_pcalloc(p,
+            sizeof(reflector_cfg));
+    reflector_cfg *add = (reflector_cfg *) addv;
+    reflector_cfg *base = (reflector_cfg *) basev;
+
+    new->headers = apr_table_overlay(p, add->headers, base->headers);
+
+    return new;
+}
+
+static const char *reflector_header(cmd_parms * cmd, void *dummy, const char *in,
+        const char *out)
+{
+    reflector_cfg *cfg = (reflector_cfg *) dummy;
+
+    apr_table_addn(cfg->headers, in, out ? out : in);
+
+    return NULL;
+}
+
+static void reflector_hooks(apr_pool_t * p)
+{
+    ap_hook_handler(reflector_handler, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+static const command_rec reflector_cmds[] = {
+    AP_INIT_TAKE12("ReflectorHeader", reflector_header, NULL, OR_OPTIONS,
+      "Header to reflect back in the response, with an optional new name."),
+    {NULL}
+};
+
+module AP_MODULE_DECLARE_DATA reflector_module = {
+    STANDARD20_MODULE_STUFF,
+    create_reflector_dir_config,
+    merge_reflector_dir_config,
+    NULL,
+    NULL,
+    reflector_cmds,
+    reflector_hooks
+};



Mime
View raw message