modules/http2/h2_mplx.c modules/http2/h2_push.c
modules/http2/h2_request.c modules/http2/h2_response.c
modules/http2/h2_session.c modules/http2/h2_stream.c
- modules/http2/h2_stream_set.c modules/http2/h2_switch.c
+ modules/http2/h2_switch.c
modules/http2/h2_task.c modules/http2/h2_task_input.c
modules/http2/h2_task_output.c modules/http2/h2_int_queue.c
modules/http2/h2_util.c modules/http2/h2_worker.c
$(OBJDIR)/h2_response.o \
$(OBJDIR)/h2_session.o \
$(OBJDIR)/h2_stream.o \
- $(OBJDIR)/h2_stream_set.o \
$(OBJDIR)/h2_switch.o \
$(OBJDIR)/h2_task.o \
$(OBJDIR)/h2_task_input.o \
h2_response.lo dnl
h2_session.lo dnl
h2_stream.lo dnl
-h2_stream_set.lo dnl
h2_switch.lo dnl
h2_task.lo dnl
h2_task_input.lo dnl
#include "h2_mplx.h"
#include "h2_session.h"
#include "h2_stream.h"
-#include "h2_stream_set.h"
#include "h2_h2.h"
#include "h2_task.h"
#include "h2_worker.h"
#include "h2_push.h"
#include "h2_task.h"
#include "h2_stream.h"
-#include "h2_stream_set.h"
#include "h2_request.h"
#include "h2_response.h"
#include "h2_session.h"
bbout(" \"session_id\": %ld,\n", (long)session->id);
bbout(" \"streams_max\": %d,\n", (int)session->max_stream_count);
bbout(" \"this_stream\": %d,\n", stream->id);
- bbout(" \"streams_open\": %d,\n", (int)h2_stream_set_size(session->streams));
+ bbout(" \"streams_open\": %d,\n", (int)h2_ihash_count(session->streams));
bbout(" \"max_stream_started\": %d,\n", mplx->max_stream_started);
bbout(" \"requests_received\": %d,\n", session->requests_received);
bbout(" \"responses_submitted\": %d,\n", session->responses_submitted);
#include "h2_mplx.h"
#include "h2_request.h"
#include "h2_stream.h"
-#include "h2_stream_set.h"
#include "h2_task.h"
#include "h2_task_input.h"
#include "h2_task_output.h"
return status;
}
-h2_stream *h2_mplx_next_submit(h2_mplx *m, h2_stream_set *streams)
+h2_stream *h2_mplx_next_submit(h2_mplx *m, h2_ihash_t *streams)
{
apr_status_t status;
h2_stream *stream = NULL;
if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
h2_io *io = h2_io_set_shift(m->ready_ios);
if (io && !m->aborted) {
- stream = h2_stream_set_get(streams, io->id);
+ stream = h2_ihash_get(streams, io->id);
if (stream) {
if (io->rst_error) {
h2_stream_rst(stream, io->rst_error);
struct apr_thread_mutex_t;
struct apr_thread_cond_t;
struct h2_config;
+struct h2_ihash_t;
struct h2_response;
struct h2_task;
struct h2_stream;
struct h2_io_set;
struct apr_thread_cond_t;
struct h2_workers;
-struct h2_stream_set;
struct h2_int_queue;
struct h2_req_engine;
* @param bb the brigade to place any existing repsonse body data into
*/
struct h2_stream *h2_mplx_next_submit(h2_mplx *m,
- struct h2_stream_set *streams);
+ struct h2_ihash_t *streams);
/**
* Reads output data from the given stream. Will never block, but
#include "h2_request.h"
#include "h2_response.h"
#include "h2_stream.h"
-#include "h2_stream_set.h"
#include "h2_from_h1.h"
#include "h2_task.h"
#include "h2_session.h"
stream = h2_stream_open(stream_id, stream_pool, session);
- h2_stream_set_add(session->streams, stream);
+ h2_ihash_add(session->streams, stream);
if (H2_STREAM_CLIENT_INITIATED(stream_id)
&& stream_id > session->max_stream_received) {
++session->requests_received;
if (APLOGctrace1(session->c)) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
"h2_session(%ld): destroy, %d streams open",
- session->id, (int)h2_stream_set_size(session->streams));
+ session->id, (int)h2_ihash_count(session->streams));
}
if (session->mplx) {
h2_mplx_set_consumed_cb(session->mplx, NULL, NULL);
h2_mplx_release_and_join(session->mplx, session->iowait);
session->mplx = NULL;
}
- if (session->streams) {
- h2_stream_set_destroy(session->streams);
- session->streams = NULL;
- }
if (session->pool) {
apr_pool_destroy(session->pool);
}
return NULL;
}
- session->streams = h2_stream_set_create(session->pool, session->max_stream_count);
-
+ session->streams = h2_ihash_create(session->pool,offsetof(h2_stream, id));
session->workers = workers;
session->mplx = h2_mplx_create(c, session->pool, session->config,
session->s->timeout, workers);
int resume_count;
} resume_ctx;
-static int resume_on_data(void *ctx, h2_stream *stream)
+static int resume_on_data(void *ctx, void *val)
{
+ h2_stream *stream = val;
resume_ctx *rctx = (resume_ctx*)ctx;
h2_session *session = rctx->session;
AP_DEBUG_ASSERT(session);
static int h2_session_resume_streams_with_data(h2_session *session)
{
AP_DEBUG_ASSERT(session);
- if (!h2_stream_set_is_empty(session->streams)
+ if (!h2_ihash_is_empty(session->streams)
&& session->mplx && !session->mplx->aborted) {
resume_ctx ctx;
/* Resume all streams where we have data in the out queue and
* which had been suspended before. */
- h2_stream_set_iter(session->streams, resume_on_data, &ctx);
+ h2_ihash_iter(session->streams, resume_on_data, &ctx);
return ctx.resume_count;
}
return 0;
h2_stream *h2_session_get_stream(h2_session *session, int stream_id)
{
if (!session->last_stream || stream_id != session->last_stream->id) {
- session->last_stream = h2_stream_set_get(session->streams, stream_id);
+ session->last_stream = h2_ihash_get(session->streams, stream_id);
}
return session->last_stream;
}
session->last_stream = NULL;
}
if (session->streams) {
- h2_stream_set_remove(session->streams, stream->id);
+ h2_ihash_remove(session->streams, stream->id);
}
h2_stream_destroy(stream);
return rstatus;
}
+static int unsubmitted_iter(void *ctx, void *val)
+{
+ h2_stream *stream = val;
+ if (h2_stream_needs_submit(stream)) {
+ *((int *)ctx) = 1;
+ return 0;
+ }
+ return 1;
+}
+
+static int has_unsubmitted_streams(h2_session *session)
+{
+ int has_unsubmitted = 0;
+ h2_ihash_iter(session->streams, unsubmitted_iter, &has_unsubmitted);
+ return has_unsubmitted;
+}
+
+static int suspended_iter(void *ctx, void *val)
+{
+ h2_stream *stream = val;
+ if (h2_stream_is_suspended(stream)) {
+ *((int *)ctx) = 1;
+ return 0;
+ }
+ return 1;
+}
+
+static int has_suspended_streams(h2_session *session)
+{
+ int has_suspended = 0;
+ h2_ihash_iter(session->streams, suspended_iter, &has_suspended);
+ return has_suspended;
+}
+
static apr_status_t h2_session_submit(h2_session *session)
{
apr_status_t status = APR_EAGAIN;
h2_stream *stream;
- if (h2_stream_set_has_unsubmitted(session->streams)) {
+ if (has_unsubmitted_streams(session)) {
/* If we have responses ready, submit them now. */
while ((stream = h2_mplx_next_submit(session->mplx, session->streams))) {
status = submit_response(session, stream);
* CPU cycles. Ideally, we'd like to do a blocking read, but that
* is not possible if we have scheduled tasks and wait
* for them to produce something. */
- if (h2_stream_set_is_empty(session->streams)) {
+ if (h2_ihash_is_empty(session->streams)) {
if (!is_accepting_streams(session)) {
/* We are no longer accepting new streams and have
* finished processing existing ones. Time to leave. */
session->s->timeout) + apr_time_now();
}
}
- else if (!h2_stream_set_has_unsubmitted(session->streams)
- && !h2_stream_set_has_suspended(session->streams)) {
+ else if (!has_unsubmitted_streams(session)
+ && !has_suspended_streams(session)) {
/* none of our streams is waiting for a response or
* new output data from task processing,
* switch to blocking reads. We are probably waiting on
apr_snprintf(session->status, sizeof(session->status),
"%s, streams: %d/%d/%d/%d/%d (open/recv/resp/push/rst)",
msg? msg : "-",
- (int)h2_stream_set_size(session->streams),
+ (int)h2_ihash_count(session->streams),
(int)session->requests_received,
(int)session->responses_submitted,
(int)session->pushes_submitted,
break;
case H2_SESSION_ST_IDLE:
- no_streams = h2_stream_set_is_empty(session->streams);
+ no_streams = h2_ihash_is_empty(session->streams);
update_child_status(session, (no_streams? SERVER_BUSY_KEEPALIVE
: SERVER_BUSY_READ), "idle");
if (async && !session->r && session->requests_received && no_streams) {
}
}
- if (!h2_stream_set_is_empty(session->streams)) {
+ if (!h2_ihash_is_empty(session->streams)) {
/* resume any streams for which data is available again */
h2_session_resume_streams_with_data(session);
/* Submit any responses/push_promises that are ready */
struct h2_ctx;
struct h2_config;
struct h2_filter_cin;
+struct h2_ihash_t;
struct h2_mplx;
struct h2_priority;
struct h2_push;
struct h2_mplx *mplx; /* multiplexer for stream data */
struct h2_stream *last_stream; /* last stream worked with */
- struct h2_stream_set *streams; /* streams handled by this session */
+ struct h2_ihash_t *streams; /* streams handled by this session */
apr_pool_t *spare; /* spare stream pool */
return 1;
}
-static int input_open(h2_stream *stream)
+static int input_open(const h2_stream *stream)
{
switch (stream->state) {
case H2_STREAM_ST_OPEN:
return status;
}
-int h2_stream_is_scheduled(h2_stream *stream)
+int h2_stream_is_scheduled(const h2_stream *stream)
{
return stream->scheduled;
}
stream->session->id, stream->id, stream->suspended);
}
-int h2_stream_is_suspended(h2_stream *stream)
+int h2_stream_is_suspended(const h2_stream *stream)
{
AP_DEBUG_ASSERT(stream);
return stream->suspended;
return stream->sos->read_to(stream->sos, bb, plen, peos);
}
-int h2_stream_input_is_open(h2_stream *stream)
+int h2_stream_input_is_open(const h2_stream *stream)
{
return input_open(stream);
}
-int h2_stream_needs_submit(h2_stream *stream)
+int h2_stream_needs_submit(const h2_stream *stream)
{
switch (stream->state) {
case H2_STREAM_ST_OPEN:
* @param stream the stream to check on
* @return != 0 iff stream has been scheduled
*/
-int h2_stream_is_scheduled(h2_stream *stream);
+int h2_stream_is_scheduled(const h2_stream *stream);
struct h2_response *h2_stream_get_response(h2_stream *stream);
* @param stream the stream to check
* @return != 0 iff stream is suspended.
*/
-int h2_stream_is_suspended(h2_stream *stream);
+int h2_stream_is_suspended(const h2_stream *stream);
/**
* Check if the stream has open input.
* @param stream the stream to check
* @return != 0 iff stream has open input.
*/
-int h2_stream_input_is_open(h2_stream *stream);
+int h2_stream_input_is_open(const h2_stream *stream);
/**
* Check if the stream has not submitted a response or RST yet.
* @param stream the stream to check
* @return != 0 iff stream has not submitted a response or RST.
*/
-int h2_stream_needs_submit(h2_stream *stream);
+int h2_stream_needs_submit(const h2_stream *stream);
/**
* Submit any server push promises on this stream and schedule
+++ /dev/null
-/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
- *
- * Licensed 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 <assert.h>
-#include <stddef.h>
-
-#include <apr_hash.h>
-#include <apr_strings.h>
-
-#include <httpd.h>
-#include <http_log.h>
-
-#include "h2_private.h"
-#include "h2_stream.h"
-#include "h2_stream_set.h"
-
-
-struct h2_stream_set {
- apr_hash_t *hash;
-};
-
-static unsigned int stream_hash(const char *key, apr_ssize_t *klen)
-{
- return (unsigned int)(*((int*)key));
-}
-
-h2_stream_set *h2_stream_set_create(apr_pool_t *pool, int max)
-{
- h2_stream_set *sp = apr_pcalloc(pool, sizeof(h2_stream_set));
- sp->hash = apr_hash_make_custom(pool, stream_hash);
-
- return sp;
-}
-
-void h2_stream_set_destroy(h2_stream_set *sp)
-{
- (void)sp;
-}
-
-h2_stream *h2_stream_set_get(h2_stream_set *sp, int stream_id)
-{
- return apr_hash_get(sp->hash, &stream_id, sizeof(stream_id));
-}
-
-void h2_stream_set_add(h2_stream_set *sp, h2_stream *stream)
-{
- apr_hash_set(sp->hash, &stream->id, sizeof(stream->id), stream);
-}
-
-void h2_stream_set_remove(h2_stream_set *sp, int stream_id)
-{
- apr_hash_set(sp->hash, &stream_id, sizeof(stream_id), NULL);
-}
-
-int h2_stream_set_is_empty(h2_stream_set *sp)
-{
- return apr_hash_count(sp->hash) == 0;
-}
-
-apr_size_t h2_stream_set_size(h2_stream_set *sp)
-{
- return apr_hash_count(sp->hash);
-}
-
-typedef struct {
- h2_stream_set_iter_fn *iter;
- void *ctx;
-} iter_ctx;
-
-static int hash_iter(void *ctx, const void *key, apr_ssize_t klen,
- const void *val)
-{
- iter_ctx *ictx = ctx;
- return ictx->iter(ictx->ctx, (h2_stream*)val);
-}
-
-void h2_stream_set_iter(h2_stream_set *sp,
- h2_stream_set_iter_fn *iter, void *ctx)
-{
- iter_ctx ictx;
- ictx.iter = iter;
- ictx.ctx = ctx;
- apr_hash_do(hash_iter, &ictx, sp->hash);
-}
-
-static int unsubmitted_iter(void *ctx, h2_stream *stream)
-{
- if (h2_stream_needs_submit(stream)) {
- *((int *)ctx) = 1;
- return 0;
- }
- return 1;
-}
-
-int h2_stream_set_has_unsubmitted(h2_stream_set *sp)
-{
- int has_unsubmitted = 0;
- h2_stream_set_iter(sp, unsubmitted_iter, &has_unsubmitted);
- return has_unsubmitted;
-}
-
-static int input_open_iter(void *ctx, h2_stream *stream)
-{
- if (h2_stream_input_is_open(stream)) {
- *((int *)ctx) = 1;
- return 0;
- }
- return 1;
-}
-
-int h2_stream_set_has_open_input(h2_stream_set *sp)
-{
- int has_input_open = 0;
- h2_stream_set_iter(sp, input_open_iter, &has_input_open);
- return has_input_open;
-}
-
-static int suspended_iter(void *ctx, h2_stream *stream)
-{
- if (h2_stream_is_suspended(stream)) {
- *((int *)ctx) = 1;
- return 0;
- }
- return 1;
-}
-
-int h2_stream_set_has_suspended(h2_stream_set *sp)
-{
- int has_suspended = 0;
- h2_stream_set_iter(sp, suspended_iter, &has_suspended);
- return has_suspended;
-}
-
+++ /dev/null
-/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
- *
- * Licensed 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.
- */
-
-#ifndef __mod_h2__h2_stream_set__
-#define __mod_h2__h2_stream_set__
-
-/**
- * A set of h2_stream instances. Allows lookup by stream id
- * and other criteria.
- */
-
-typedef h2_stream *h2_stream_set_match_fn(void *ctx, h2_stream *stream);
-typedef int h2_stream_set_iter_fn(void *ctx, h2_stream *stream);
-
-typedef struct h2_stream_set h2_stream_set;
-
-
-h2_stream_set *h2_stream_set_create(apr_pool_t *pool, int max);
-
-void h2_stream_set_destroy(h2_stream_set *sp);
-
-void h2_stream_set_add(h2_stream_set *sp, h2_stream *stream);
-
-h2_stream *h2_stream_set_get(h2_stream_set *sp, int stream_id);
-
-void h2_stream_set_remove(h2_stream_set *sp, int stream_id);
-
-void h2_stream_set_iter(h2_stream_set *sp,
- h2_stream_set_iter_fn *iter, void *ctx);
-
-int h2_stream_set_is_empty(h2_stream_set *sp);
-
-apr_size_t h2_stream_set_size(h2_stream_set *sp);
-
-int h2_stream_set_has_unsubmitted(h2_stream_set *sp);
-int h2_stream_set_has_open_input(h2_stream_set *sp);
-int h2_stream_set_has_suspended(h2_stream_set *sp);
-
-#endif /* defined(__mod_h2__h2_stream_set__) */
}
+/*******************************************************************************
+ * ihash - hash for structs with int identifier
+ ******************************************************************************/
+struct h2_ihash_t {
+ apr_hash_t *hash;
+ size_t ioff;
+};
+
+static unsigned int ihash(const char *key, apr_ssize_t *klen)
+{
+ return (unsigned int)(*((int*)key));
+}
+
+h2_ihash_t *h2_ihash_create(apr_pool_t *pool, size_t offset_of_int)
+{
+ h2_ihash_t *ih = apr_pcalloc(pool, sizeof(h2_ihash_t));
+ ih->hash = apr_hash_make_custom(pool, ihash);
+ ih->ioff = offset_of_int;
+ return ih;
+}
+
+size_t h2_ihash_count(h2_ihash_t *ih)
+{
+ return apr_hash_count(ih->hash);
+}
+
+int h2_ihash_is_empty(h2_ihash_t *ih)
+{
+ return apr_hash_count(ih->hash) == 0;
+}
+
+void *h2_ihash_get(h2_ihash_t *ih, int id)
+{
+ return apr_hash_get(ih->hash, &id, sizeof(id));
+}
+
+typedef struct {
+ h2_ihash_iter_t *iter;
+ void *ctx;
+} iter_ctx;
+
+static int ihash_iter(void *ctx, const void *key, apr_ssize_t klen,
+ const void *val)
+{
+ iter_ctx *ictx = ctx;
+ return ictx->iter(ictx->ctx, (void*)val); /* why is this passed const?*/
+}
+
+void h2_ihash_iter(h2_ihash_t *ih, h2_ihash_iter_t *fn, void *ctx)
+{
+ iter_ctx ictx;
+ ictx.iter = fn;
+ ictx.ctx = ctx;
+ apr_hash_do(ihash_iter, &ictx, ih->hash);
+}
+
+void h2_ihash_add(h2_ihash_t *ih, void *val)
+{
+ apr_hash_set(ih->hash, ((char *)val + ih->ioff), sizeof(int), val);
+}
+
+void h2_ihash_remove(h2_ihash_t *ih, int id)
+{
+ apr_hash_set(ih->hash, &id, sizeof(id), NULL);
+}
+
/*******************************************************************************
* h2_util for apt_table_t
******************************************************************************/
#ifndef __mod_h2__h2_util__
#define __mod_h2__h2_util__
+/*******************************************************************************
+ * some debugging/format helpers
+ ******************************************************************************/
struct h2_request;
struct nghttp2_frame;
int h2_util_frame_print(const nghttp2_frame *frame, char *buffer, size_t maxlen);
+/*******************************************************************************
+ * ihash - hash for structs with int identifier
+ ******************************************************************************/
+typedef struct h2_ihash_t h2_ihash_t;
+typedef int h2_ihash_iter_t(void *ctx, void *val);
+
+/**
+ * Create a hash for structures that have an identifying int member.
+ * @param pool the pool to use
+ * @param offset_of_int the offsetof() the int member in the struct
+ */
+h2_ihash_t *h2_ihash_create(apr_pool_t *pool, size_t offset_of_int);
+
+size_t h2_ihash_count(h2_ihash_t *ih);
+int h2_ihash_is_empty(h2_ihash_t *ih);
+void *h2_ihash_get(h2_ihash_t *ih, int id);
+
+/**
+ * Iterate over the hash members (without defined order) and invoke
+ * fn for each member until 0 is returned.
+ * @param ih the hash to iterate over
+ * @param fn the function to invoke on each member
+ * @param ctx user supplied data passed into each iteration call
+ */
+void h2_ihash_iter(h2_ihash_t *ih, h2_ihash_iter_t *fn, void *ctx);
+
+void h2_ihash_add(h2_ihash_t *ih, void *val);
+void h2_ihash_remove(h2_ihash_t *ih, int id);
+
+/*******************************************************************************
+ * common helpers
+ ******************************************************************************/
/**
* Count the bytes that all key/value pairs in a table have
* in length (exlucding terminating 0s), plus additional extra per pair.
*/
apr_size_t h2_util_table_bytes(apr_table_t *t, apr_size_t pair_extra);
-int h2_req_ignore_header(const char *name, size_t len);
-int h2_req_ignore_trailer(const char *name, size_t len);
-int h2_res_ignore_trailer(const char *name, size_t len);
-int h2_proxy_res_ignore_header(const char *name, size_t len);
-
/**
* Return != 0 iff the string s contains the token, as specified in
* HTTP header syntax, rfc7230.
const char *h2_util_first_token_match(apr_pool_t *pool, const char *s,
const char *tokens[], apr_size_t len);
+/** Match a header value against a string constance, case insensitive */
+#define H2_HD_MATCH_LIT(l, name, nlen) \
+ ((nlen == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
+
+/*******************************************************************************
+ * HTTP/2 header helpers
+ ******************************************************************************/
+int h2_req_ignore_header(const char *name, size_t len);
+int h2_req_ignore_trailer(const char *name, size_t len);
+int h2_res_ignore_trailer(const char *name, size_t len);
+int h2_proxy_res_ignore_header(const char *name, size_t len);
+
+/**
+ * Set the push policy for the given request. Takes request headers into
+ * account, see draft https://tools.ietf.org/html/draft-ruellan-http-accept-push-policy-00
+ * for details.
+ *
+ * @param req the request to determine the policy for
+ * @param p the pool to use
+ * @param push_enabled if HTTP/2 server push is generally enabled for this request
+ */
+void h2_push_policy_determine(struct h2_request *req, apr_pool_t *p, int push_enabled);
+
+/*******************************************************************************
+ * base64 url encoding, different table from normal base64
+ ******************************************************************************/
/**
* I always wanted to write my own base64url decoder...not. See
* https://tools.ietf.org/html/rfc4648#section-5 for description.
const char *h2_util_base64url_encode(const char *data,
apr_size_t len, apr_pool_t *pool);
-#define H2_HD_MATCH_LIT(l, name, nlen) \
- ((nlen == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
+/*******************************************************************************
+ * nghttp2 helpers
+ ******************************************************************************/
#define H2_HD_MATCH_LIT_CS(l, name) \
((strlen(name) == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
h2_ngheader *h2_util_ngheader_make_req(apr_pool_t *p,
const struct h2_request *req);
+/*******************************************************************************
+ * apr brigade helpers
+ ******************************************************************************/
/**
* Moves data from one brigade into another. If maxlen > 0, it only
* moves up to maxlen bytes into the target brigade, making bucket splits
apr_off_t *plen,
int *peos);
-/**
- * Set the push policy for the given request. Takes request headers into
- * account, see draft https://tools.ietf.org/html/draft-ruellan-http-accept-push-policy-00
- * for details.
- *
- * @param req the request to determine the policy for
- * @param p the pool to use
- * @param push_enabled if HTTP/2 server push is generally enabled for this request
- */
-void h2_push_policy_determine(struct h2_request *req, apr_pool_t *p, int push_enabled);
-
#endif /* defined(__mod_h2__h2_util__) */
# End Source File
# Begin Source File
-SOURCE=./h2_stream_set.c
-# End Source File
-# Begin Source File
-
SOURCE=./h2_switch.c
# End Source File
# Begin Source File
}
}
+static request_rec *next_request(h2_proxy_ctx *ctx, h2_proxy_session *session,
+ request_rec *r)
+{
+ if (!r && !ctx->standalone) {
+ ctx->engine->capacity = session->remote_max_concurrent;
+ if (req_engine_pull(ctx->engine, APR_NONBLOCK_READ, &r) == APR_SUCCESS) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+ "h2_proxy_session(%s): pulled request %s",
+ session->id, r->the_request);
+ }
+ }
+ return r;
+}
+
static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx, request_rec *r) {
apr_status_t status = OK;
h2_proxy_session *session;
-setup_session:
+setup_backend:
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner,
+ "eng(%s): setup backend", ctx->engine->id);
/* Step Two: Make the Connection (or check that an already existing
* socket is still usable). On success, we have a socket connected to
* backend->hostname. */
/* Step Four: Send the Request in a new HTTP/2 stream and
* loop until we got the response or encounter errors.
*/
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner,
+ "eng(%s): setup session", ctx->engine->id);
session = h2_proxy_session_setup(ctx->engine->id, ctx->p_conn,
ctx->conf, request_done);
if (!session) {
}
run_session:
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner,
+ "eng(%s): run session %s", ctx->engine->id, session->id);
session->user_data = ctx;
- add_request(session, r);
- status = APR_EAGAIN;
+ status = h2_proxy_session_process(session);
while (APR_STATUS_IS_EAGAIN(status)) {
- status = h2_proxy_session_process(session);
-
- if (APR_STATUS_IS_EAGAIN(status) && !ctx->standalone) {
- ctx->engine->capacity = session->remote_max_concurrent;
- if (req_engine_pull(ctx->engine, APR_NONBLOCK_READ, &r) == APR_SUCCESS) {
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
- "h2_proxy_session(%s): pulled request %s",
- session->id, r->the_request);
- add_request(session, r);
- }
+ r = next_request(ctx, session, r);
+ if (r) {
+ add_request(session, r);
+ r = NULL;
}
+
+ status = h2_proxy_session_process(session);
}
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner,
+ "eng(%s): end of session run", ctx->engine->id);
if (session->state == H2_PROXYS_ST_DONE || status != APR_SUCCESS) {
ctx->p_conn->close = 1;
}
- if (!ctx->standalone) {
- ctx->engine->capacity = session->remote_max_concurrent;
- if (req_engine_pull(ctx->engine, APR_NONBLOCK_READ, &r) == APR_SUCCESS) {
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
- "h2_proxy_session(%s): idle, pulled request %s",
- session->id, r->the_request);
- add_request(session, r);
- if (ctx->p_conn->close) {
- goto setup_session;
- }
- goto run_session;
+ r = next_request(ctx, session, r);
+ if (r) {
+ if (ctx->p_conn->close) {
+ goto setup_backend;
}
+ add_request(session, r);
+ r = NULL;
+ goto run_session;
}
if (session->streams && !h2_iq_empty(session->streams)) {
"session run done with %d streams unfinished",
h2_iq_size(session->streams));
}
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status,
- ctx->p_conn->connection, "session run done");
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status,
+ ctx->p_conn->connection, "eng(%s): session run done",
+ ctx->engine->id);
session->user_data = NULL;
return status;
}