Skip to content

Commit

Permalink
mod_http2: new H2CopyFiles directive
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1753498 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
icing committed Jul 20, 2016
1 parent 3b5a8d4 commit f631a04
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -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]

Expand Down
37 changes: 37 additions & 0 deletions docs/manual/mod/mod_http2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
5 changes: 5 additions & 0 deletions modules/http2/h2_bucket_beam.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

6 changes: 6 additions & 0 deletions modules/http2/h2_bucket_beam.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
25 changes: 24 additions & 1 deletion modules/http2/h2_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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
};

Expand Down
2 changes: 2 additions & 0 deletions modules/http2/h2_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;


Expand Down
19 changes: 18 additions & 1 deletion modules/http2/h2_h2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}

4 changes: 3 additions & 1 deletion modules/http2/h2_mplx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
7 changes: 6 additions & 1 deletion modules/http2/h2_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions modules/http2/h2_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions modules/http2/mod_http2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit f631a04

Please sign in to comment.