#include <http_config.h>
#include <http_connection.h>
#include <http_protocol.h>
+#include <http_request.h>
#include <http_log.h>
#include "h2_private.h"
#include "h2_config.h"
#include "h2_ctx.h"
#include "h2_conn.h"
+#include "h2_request.h"
#include "h2_session.h"
#include "h2_util.h"
#include "h2_h2.h"
*/
static int h2_h2_process_conn(conn_rec* c);
static int h2_h2_post_read_req(request_rec *r);
-
+static int h2_h2_fixups(request_rec *r);
/*******************************************************************************
* Once per lifetime init, retrieve optional functions
* never see the response.
*/
ap_hook_post_read_request(h2_h2_post_read_req, NULL, NULL, APR_HOOK_REALLY_FIRST);
+
+ /* Setup subprocess env for certain variables
+ */
+ ap_hook_fixups(h2_h2_fixups, NULL,NULL, APR_HOOK_MIDDLE);
}
int h2_h2_process_conn(conn_rec* c)
}
return DECLINED;
}
+
+static int h2_h2_fixups(request_rec *r)
+{
+ if (r->connection->master) {
+ h2_ctx *ctx = h2_ctx_rget(r);
+ struct h2_task *task = h2_ctx_get_task(ctx);
+ if (task) {
+ apr_table_setn(r->subprocess_env, "HTTP2", "on");
+ if (task->request->push) {
+ apr_table_setn(r->subprocess_env, "H2PUSH", "on");
+ }
+ }
+ }
+ return DECLINED;
+}
\ No newline at end of file
status = apr_brigade_puts(bb, NULL, NULL, "0\r\n\r\n");
}
}
- APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(io->bbin->bucket_alloc));
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(io->bucket_alloc));
return status;
}
}
if (!h2_util_has_eos(io->bbout, -1)) {
APR_BRIGADE_INSERT_TAIL(io->bbout,
- apr_bucket_eos_create(io->bbout->bucket_alloc));
+ apr_bucket_eos_create(io->bucket_alloc));
}
}
return APR_SUCCESS;
struct h2_io {
int id; /* stream identifier */
apr_pool_t *pool; /* stream pool */
- int orphaned; /* h2_stream is gone for this io */
+ apr_bucket_alloc_t *bucket_alloc;
- int task_done;
const struct h2_request *request; /* request on this io */
- int request_body; /* == 0 iff request has no body */
- struct h2_response *response;/* response for submit, once created */
- int rst_error;
+ struct h2_response *response;/* response to request */
+ int rst_error; /* h2 related stream abort error */
- h2_io_op timed_op; /* which operation is waited on */
- struct apr_thread_cond_t *timed_cond; /* condition to wait on */
- apr_time_t timeout_at; /* when IO wait will time out */
-
- int eos_in;
- int eos_in_written;
apr_bucket_brigade *bbin; /* input data for stream */
- apr_size_t input_consumed; /* how many bytes have been read */
-
- int eos_out;
apr_bucket_brigade *bbout; /* output data from stream */
- apr_bucket_alloc_t *bucket_alloc;
+ apr_bucket_brigade *tmp; /* temporary data for chunking */
+
+ int orphaned : 1; /* h2_stream is gone for this io */
+ int task_done : 1; /* h2_task has finished for this io */
+ int request_body : 1; /* iff request has body */
+ int eos_in : 1; /* input eos has been seen */
+ int eos_in_written : 1; /* input eos has been forwarded */
+ int eos_out : 1; /* output eos has been seen */
+
+ h2_io_op timed_op; /* which operation is waited on, if any */
+ struct apr_thread_cond_t *timed_cond; /* condition to wait on, maybe NULL */
+ apr_time_t timeout_at; /* when IO wait will time out */
+ apr_size_t input_consumed; /* how many bytes have been read */
+
int files_handles_owned;
- apr_bucket_brigade *tmp; /* temporary data for chunking */
};
/*******************************************************************************
apr_pool_t *pool;
apr_bucket_alloc_t *bucket_alloc;
+ int aborted : 1;
+
struct h2_task_queue *q;
struct h2_io_set *stream_ios;
struct h2_io_set *ready_ios;
struct apr_thread_cond_t *added_output;
struct apr_thread_cond_t *join_wait;
- int aborted;
apr_size_t stream_max_mem;
int stream_timeout_secs;
"GET", ctx->req->scheme,
ctx->req->authority,
path, headers);
- h2_request_end_headers(req, ctx->pool, 1);
+ /* atm, we do not push on pushes */
+ h2_request_end_headers(req, ctx->pool, 1, 0);
push->req = req;
if (!ctx->pushes) {
return status;
}
-apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos)
+apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool,
+ int eos, int push)
{
const char *s;
}
req->eoh = 1;
+ req->push = push;
/* In the presence of trailers, force behaviour of chunked encoding */
s = apr_table_get(req->headers, "Trailer");
typedef struct h2_request h2_request;
struct h2_request {
- int id; /* stream id */
+ int id; /* stream id */
- /* pseudo header values, see ch. 8.1.2.3 */
- const char *method;
+ const char *method; /* pseudo header values, see ch. 8.1.2.3 */
const char *scheme;
const char *authority;
const char *path;
apr_time_t request_time;
apr_off_t content_length;
- int chunked;
- int eoh;
+
+ int chunked : 1; /* iff requst body needs to be forwarded as chunked */
+ int eoh : 1; /* iff end-of-headers has been seen and request is complete */
+ int push : 1; /* iff server push is possible for this request */
const struct h2_config *config;
};
const char *name, size_t nlen,
const char *value, size_t vlen);
-apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos);
+apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool,
+ int eos, int push);
void h2_request_copy(apr_pool_t *p, h2_request *dst, const h2_request *src);
h2_stream *stream, int eos)
{
(void)session;
- return h2_stream_schedule(stream, eos, stream_pri_cmp, session);
+ return h2_stream_schedule(stream, eos, h2_session_push_enabled(session),
+ stream_pri_cmp, session);
}
/*
* also have the pushed ones as well.
*/
if (!stream->initiated_on
- && h2_config_geti(session->config, H2_CONF_PUSH)
&& H2_HTTP_2XX(response->http_status)
&& h2_session_push_enabled(session)) {
int h2_session_push_enabled(h2_session *session)
{
- return nghttp2_session_get_remote_settings(session->ngh2,
- NGHTTP2_SETTINGS_ENABLE_PUSH);
+ /* iff we can and they can */
+ return (h2_config_geti(session->config, H2_CONF_PUSH)
+ && nghttp2_session_get_remote_settings(session->ngh2,
+ NGHTTP2_SETTINGS_ENABLE_PUSH));
}
static apr_status_t h2_session_send(h2_session *session)
server_rec *s; /* server/vhost we're starting on */
const struct h2_config *config; /* Relevant config for this session */
- int started;
- int aborted; /* this session is being aborted */
- int reprioritize; /* scheduled streams priority needs to
- * be re-evaluated */
+ int started : 1; /* session startup done */
+ int aborted : 1; /* this session is being aborted */
+ int reprioritize : 1; /* scheduled streams priority changed */
apr_interval_time_t wait_micros;
int unsent_submits; /* number of submitted, but not yet sent
}
}
-apr_status_t h2_stream_schedule(h2_stream *stream, int eos,
+apr_status_t h2_stream_schedule(h2_stream *stream, int eos, int push_enabled,
h2_stream_pri_cmp *cmp, void *ctx)
{
apr_status_t status;
/* Seeing the end-of-headers, we have everything we need to
* start processing it.
*/
- status = h2_request_end_headers(stream->request, stream->pool, eos);
+ status = h2_request_end_headers(stream->request, stream->pool,
+ eos, push_enabled);
if (status == APR_SUCCESS) {
if (!eos) {
stream->bbin = apr_brigade_create(stream->pool,
apr_pool_t *pool; /* the memory pool for this stream */
struct h2_request *request; /* the request made in this stream */
struct h2_response *response; /* the response, once ready */
-
- int aborted; /* was aborted */
- int suspended; /* DATA sending has been suspended */
int rst_error; /* stream error for RST_STREAM */
- int scheduled; /* stream has been scheduled */
- int submitted; /* response HEADER has been sent */
+
+ int aborted : 1; /* was aborted */
+ int suspended : 1; /* DATA sending has been suspended */
+ int scheduled : 1; /* stream has been scheduled */
+ int submitted : 1; /* response HEADER has been sent */
apr_off_t input_remaining; /* remaining bytes on input as advertised via content-length */
apr_bucket_brigade *bbin; /* input DATA */
* @param cmp priority comparision
* @param ctx context for comparision
*/
-apr_status_t h2_stream_schedule(h2_stream *stream, int eos,
+apr_status_t h2_stream_schedule(h2_stream *stream, int eos, int push_enabled,
h2_stream_pri_cmp *cmp, void *ctx);
/**
*/
ap_hook_pre_connection(h2_task_pre_conn,
NULL, mod_ssl, APR_HOOK_FIRST);
- /* When the connection processing actually starts, we might to
+ /* When the connection processing actually starts, we might
* take over, if the connection is for a task.
*/
ap_hook_process_connection(h2_task_process_conn,
struct h2_task {
const char *id;
int stream_id;
- struct h2_mplx *mplx;
-
- const struct h2_request *request;
- int filters_set;
- int input_eos;
-
- int serialize_headers;
-
- struct conn_rec *c;
apr_pool_t *pool;
apr_bucket_alloc_t *bucket_alloc;
+
+ struct h2_mplx *mplx;
+ struct conn_rec *c;
+ const struct h2_request *request;
+
+ int filters_set : 1;
+ int input_eos : 1;
+ int serialize_headers : 1;
+
struct h2_task_input *input;
struct h2_task_output *output;
struct h2_task *task;
h2_task_output_state_t state;
struct h2_from_h1 *from_h1;
- int trailers_passed;
+ int trailers_passed : 1;
};
h2_task_output *h2_task_output_create(struct h2_task *task, apr_pool_t *pool);
h2_worker_done_fn *worker_done;
void *ctx;
- int aborted;
+ int aborted : 1;
int pool_reuses;
struct h2_task *task;
};
struct h2_workers {
server_rec *s;
apr_pool_t *pool;
- int aborted;
int next_worker_id;
int min_size;
int max_size;
+ int aborted : 1;
+
apr_threadattr_t *thread_attr;
APR_RING_HEAD(h2_worker_list, h2_worker) workers;