]> granicus.if.org Git - apache/commitdiff
mod_http2: new H2CopyFiles directive
authorStefan Eissing <icing@apache.org>
Wed, 20 Jul 2016 13:04:57 +0000 (13:04 +0000)
committerStefan Eissing <icing@apache.org>
Wed, 20 Jul 2016 13:04:57 +0000 (13:04 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1753498 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/manual/mod/mod_http2.xml
modules/http2/h2_bucket_beam.c
modules/http2/h2_bucket_beam.h
modules/http2/h2_config.c
modules/http2/h2_config.h
modules/http2/h2_h2.c
modules/http2/h2_mplx.c
modules/http2/h2_task.c
modules/http2/h2_task.h
modules/http2/mod_http2.c

diff --git a/CHANGES b/CHANGES
index 5b6de8c8b3ad5b2112f2ca0d08fd06ddfc0a274a..79d3959e5ddee356fd863a5f2d2f1db9783a9a7a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_http2: new H2CopyFiles directive that changes treatment of file
+     handles in responses. Necessary in order to fix broken lifetime handling
+     in modules such as mod_wsgi.
+  
   *) mod_proxy_fcgi: avoid loops when ProxyErrorOverride is enabled
      and the error documents are proxied. PR 55415. [Luca Toscano]
 
index 6eb829acda27460931b22683ea8d09b83f6080dc..34cefeb382b50d4cb109c0dc0afe0639aa3767c4 100644 (file)
@@ -897,4 +897,41 @@ H2TLSCoolDownSecs 0
         </usage>
     </directivesynopsis>
     
+    <directivesynopsis>
+        <name>H2CopyFiles</name>
+        <description>Determine file handling in responses</description>
+        <syntax>H2CopyFiles on|off</syntax>
+        <default>H2CopyFiles off</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+            <context>directory</context>
+            <context>.htaccess</context>
+        </contextlist>
+        <compatibility>Available in version 2.4.24 and later.</compatibility>
+        
+        <usage>
+            <p>
+                This directive influences how file content is handled in
+                responses. When off, which is the default, file handles are 
+                passed from the requestion processing down to the main
+                connection, using the usual Apache setaside handling for
+                manaaging the lifetime of the file.
+            </p>
+            <p>
+                When set to <code>on</code>, file content is copied while the
+                request is still being processed and the buffered data is passed
+                on to the main connection. This is better if a third party
+                module is injecting files with different lifetimes into the response. 
+            </p>
+            <p>
+                An example for such a module is <code>mod_wsgi</code> that may place
+                Python file handles into the response. Those files get close down when
+                Python thinks processing has finished. That may be well before
+                <code>mod_http2</code> is done with them.
+            </p>
+        </usage>
+    </directivesynopsis>
+    
+    
 </modulesynopsis>
index cf2cb84dad1c57041def20c2f64385ef28dfee8b..6a1e74d3e7fb5d3c532c8d18cd055c4b1227952e 100644 (file)
@@ -1013,3 +1013,8 @@ apr_size_t h2_beam_get_files_beamed(h2_bucket_beam *beam)
     return n;
 }
 
+int h2_beam_no_files(void *ctx, h2_bucket_beam *beam, apr_file_t *file)
+{
+    return 0;
+}
+
index 5c5d65de2eec2c4f4a842d2bf028884229ee89d7..fcafb063ddd441efcab6c34afcaae0c04b77e8c3 100644 (file)
@@ -163,6 +163,12 @@ typedef struct {
 typedef int h2_beam_can_beam_callback(void *ctx, h2_bucket_beam *beam,
                                       apr_file_t *file);
 
+/**
+ * Will deny all transfer of apr_file_t across the beam and force
+ * a data copy instead.
+ */
+int h2_beam_no_files(void *ctx, h2_bucket_beam *beam, apr_file_t *file);
+
 struct h2_bucket_beam {
     int id;
     const char *tag;
index 0c1e6c469b9806c8a72e2fc4354ba096066faa38..251c3f05d2fb56819a69b4e8de385b8e411c2789 100644 (file)
@@ -61,7 +61,7 @@ static h2_config defconf = {
     1,                      /* HTTP/2 server push enabled */
     NULL,                   /* map of content-type to priorities */
     256,                    /* push diary size */
-    
+    0,                      /* copy files across threads */
 };
 
 void h2_config_init(apr_pool_t *pool)
@@ -95,6 +95,7 @@ static void *h2_config_create(apr_pool_t *pool,
     conf->h2_push              = DEF_VAL;
     conf->priorities           = NULL;
     conf->push_diary_size      = DEF_VAL;
+    conf->copy_files           = DEF_VAL;
     
     return conf;
 }
@@ -141,6 +142,7 @@ void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
         n->priorities       = add->priorities? add->priorities : base->priorities;
     }
     n->push_diary_size      = H2_CONFIG_GET(add, base, push_diary_size);
+    n->copy_files           = H2_CONFIG_GET(add, base, copy_files);
     
     return n;
 }
@@ -185,6 +187,8 @@ apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
             return H2_CONFIG_GET(conf, &defconf, h2_push);
         case H2_CONF_PUSH_DIARY_SIZE:
             return H2_CONFIG_GET(conf, &defconf, push_diary_size);
+        case H2_CONF_COPY_FILES:
+            return H2_CONFIG_GET(conf, &defconf, copy_files);
         default:
             return DEF_VAL;
     }
@@ -500,6 +504,23 @@ static const char *h2_conf_set_push_diary_size(cmd_parms *parms,
     return NULL;
 }
 
+static const char *h2_conf_set_copy_files(cmd_parms *parms,
+                                          void *arg, const char *value)
+{
+    h2_config *cfg = (h2_config *)arg;
+    if (!strcasecmp(value, "On")) {
+        cfg->copy_files = 1;
+        return NULL;
+    }
+    else if (!strcasecmp(value, "Off")) {
+        cfg->copy_files = 0;
+        return NULL;
+    }
+    
+    (void)arg;
+    return "value must be On or Off";
+}
+
 #define AP_END_CMD     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
 
 const command_rec h2_cmds[] = {
@@ -539,6 +560,8 @@ const command_rec h2_cmds[] = {
                   RSRC_CONF, "define priority of PUSHed resources per content type"),
     AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL,
                   RSRC_CONF, "size of push diary"),
+    AP_INIT_TAKE1("H2CopyFiles", h2_conf_set_copy_files, NULL,
+                  OR_ALL, "on to perform copy of file data"),
     AP_END_CMD
 };
 
index 92b222f9f7bda0394b0f3fdb1e60fc61585456a2..4dc5f6c9b974bd509b0bd4557b2f4a2cf99e2af3 100644 (file)
@@ -40,6 +40,7 @@ typedef enum {
     H2_CONF_TLS_COOLDOWN_SECS,
     H2_CONF_PUSH,
     H2_CONF_PUSH_DIARY_SIZE,
+    H2_CONF_COPY_FILES,
 } h2_config_var_t;
 
 struct apr_hash_t;
@@ -68,6 +69,7 @@ typedef struct h2_config {
     struct apr_hash_t *priorities;/* map of content-type to h2_priority records */
     
     int push_diary_size;          /* # of entries in push diary */
+    int copy_files;               /* if files shall be copied vs setaside on output */
 } h2_config;
 
 
index 825cd77e78581eeffd76cc5d0e10216d2b5708d0..fd5338406b0b805e9c50ae67526701998b8baa78 100644 (file)
@@ -433,6 +433,7 @@ static int cipher_is_blacklisted(const char *cipher, const char **psource)
 static int h2_h2_process_conn(conn_rec* c);
 static int h2_h2_pre_close_conn(conn_rec* c);
 static int h2_h2_post_read_req(request_rec *r);
+static int h2_h2_late_fixups(request_rec *r);
 
 /*******************************************************************************
  * Once per lifetime init, retrieve optional functions
@@ -567,6 +568,7 @@ void h2_h2_register_hooks(void)
      * never see the response.
      */
     ap_hook_post_read_request(h2_h2_post_read_req, NULL, NULL, APR_HOOK_REALLY_FIRST);
+    ap_hook_fixups(h2_h2_late_fixups, NULL, NULL, APR_HOOK_LAST);
 }
 
 int h2_h2_process_conn(conn_rec* c)
@@ -682,7 +684,7 @@ static int h2_h2_post_read_req(request_rec *r)
          * that we manipulate filters only once. */
         if (task && !task->filters_set) {
             ap_filter_t *f;
-            
+
             /* setup the correct output filters to process the response
              * on the proper mod_http2 way. */
             ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "adding task output filter");
@@ -712,3 +714,18 @@ static int h2_h2_post_read_req(request_rec *r)
     return DECLINED;
 }
 
+static int h2_h2_late_fixups(request_rec *r)
+{
+    /* slave connection? */
+    if (r->connection->master) {
+        h2_ctx *ctx = h2_ctx_rget(r);
+        struct h2_task *task = h2_ctx_get_task(ctx);
+        if (task) {
+            /* check if we copy vs. setaside files in this location */
+            task->output.copy_files = h2_config_geti(h2_config_rget(r), 
+                                                     H2_CONF_COPY_FILES);
+        }
+    }
+    return DECLINED;
+}
+
index 001eb7f6d3ea2e3aaff4cdb09675a3c40363fb5c..fd6bf6ba29d386750e79fa900147fd2e257912f1 100644 (file)
@@ -686,7 +686,9 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response)
         h2_beam_timeout_set(task->output.beam, m->stream_timeout);
         h2_beam_on_consumed(task->output.beam, stream_output_consumed, task);
         m->tx_handles_reserved -= h2_beam_get_files_beamed(task->output.beam);
-        h2_beam_on_file_beam(task->output.beam, can_beam_file, m);
+        if (!task->output.copy_files) {
+            h2_beam_on_file_beam(task->output.beam, can_beam_file, m);
+        }
         h2_beam_mutex_set(task->output.beam, beam_enter, task->cond, m);
     }
     
index 381d0b1c061d252bba287ce1b2c680714d16d21c..1893b12fad465474899c8c5ae18b7c1f41fb5fa1 100644 (file)
@@ -406,7 +406,12 @@ static apr_status_t output_write(h2_task *task, ap_filter_t* f,
     
     if (!task->output.beam) {
         h2_beam_create(&task->output.beam, task->pool, 
-                       task->stream_id, "output", 0); 
+                       task->stream_id, "output", 0);
+        if (task->output.copy_files) {
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
+                          "h2_task(%s): copy_files on", task->id);
+            h2_beam_on_file_beam(task->output.beam, h2_beam_no_files, NULL);
+        }
     }
     
     /* Attempt to write saved brigade first */
index 010005a374e0aba20e4b80cdd5ca43f343d74e7b..1086e053e99dc0f05abc3453b62a2c29642898cc 100644 (file)
@@ -71,6 +71,7 @@ struct h2_task {
         struct h2_bucket_beam *beam;
         struct h2_from_h1 *from_h1;
         unsigned int response_open : 1;
+        unsigned int copy_files : 1;
         apr_off_t written;
         apr_bucket_brigade *bb;
     } output;
index 480917a4191687975fdc70fc0f7d3d8947fa6470..06410612933ad3d9ab5daf0b961637ba7daabc97 100644 (file)
@@ -47,8 +47,8 @@ static void h2_hooks(apr_pool_t *pool);
 
 AP_DECLARE_MODULE(http2) = {
     STANDARD20_MODULE_STUFF,
-    NULL,
-    NULL,
+    h2_config_create_dir, /* func to create per dir config */
+    h2_config_merge,
     h2_config_create_svr, /* func to create per server config */
     h2_config_merge,      /* func to merge per server config */
     h2_cmds,              /* command handlers */