static void fix_event_conn(conn_rec *c, conn_rec *master);
+/*
+ * We would like to create the connection more lightweight like
+ * slave connections in 2.5-DEV. But we get 500 responses on long
+ * cgi tests in modules/h2.t as the script parsing seems to see an
+ * EOF from the cgi before anything is sent.
+ *
+conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *pool)
+{
+ conn_rec *c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
+
+ memcpy(c, master, sizeof(conn_rec));
+ c->id = (master->id & (long)pool);
+ c->slaves = NULL;
+ c->master = master;
+ c->input_filters = NULL;
+ c->output_filters = NULL;
+ c->pool = pool;
+
+ return c;
+}
+*/
+
conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *pool)
{
apr_socket_t *socket;
ap_hook_process_connection(h2_h2_remove_timeout,
mod_reqtimeout, NULL, APR_HOOK_LAST);
- ap_hook_post_read_request(h2_h2_post_read_req, NULL, NULL, APR_HOOK_MIDDLE);
/* With "H2SerializeHeaders On", we install the filter in this hook
* that parses the response. This needs to happen before any other post
* read function terminates the request with an error. Otherwise we will
static void h2_io_cleanup(h2_io *io)
{
- if (io->response) {
- h2_response_cleanup(io->response);
- }
}
void h2_io_destroy(h2_io *io)
if (f) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c,
"h2_mplx(%ld-%d): open response: %s",
- m->id, stream_id, response->headers->status);
+ m->id, stream_id, response->status);
}
- h2_response_copy(io->response, response);
+ io->response = h2_response_copy(io->pool, response);
h2_io_set_add(m->ready_ios, io);
if (bb) {
status = out_write(m, io, f, bb, iowait);
if (!m->aborted) {
h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
if (io) {
- if (!io->response->headers) {
+ if (!io->response->ngheader) {
/* In case a close comes before a response was created,
* insert an error one so that our streams can properly
* reset.
#include "h2_util.h"
#include "h2_response.h"
-static void convert_header(h2_response *response, apr_table_t *headers,
- const char *http_status, request_rec *r);
+static h2_ngheader *make_ngheader(apr_pool_t *pool, const char *status,
+ apr_table_t *header);
+
static int ignore_header(const char *name)
{
return (H2_HD_MATCH_LIT_CS("connection", name)
}
response->stream_id = stream_id;
+ response->status = http_status;
response->content_length = -1;
if (hlines) {
else {
header = apr_table_make(pool, 0);
}
-
- convert_header(response, header, http_status, NULL);
- return response->headers? response : NULL;
+
+ response->rheader = header;
+ return response;
}
h2_response *h2_response_rcreate(int stream_id, request_rec *r,
}
response->stream_id = stream_id;
+ response->status = apr_psprintf(pool, "%d", r->status);
response->content_length = -1;
- convert_header(response, header, apr_psprintf(pool, "%d", r->status), r);
+ response->rheader = header;
- return response->headers? response : NULL;
-}
-
-void h2_response_cleanup(h2_response *response)
-{
- if (response->headers) {
- if (--response->headers->refs == 0) {
- free(response->headers);
- }
- response->headers = NULL;
- }
+ return response;
}
void h2_response_destroy(h2_response *response)
{
- h2_response_cleanup(response);
}
-void h2_response_copy(h2_response *to, h2_response *from)
+h2_response *h2_response_copy(apr_pool_t *pool, h2_response *from)
{
- h2_response_cleanup(to);
- *to = *from;
- if (from->headers) {
- ++from->headers->refs;
+ h2_response *to = apr_pcalloc(pool, sizeof(h2_response));
+ to->stream_id = from->stream_id;
+ to->status = apr_pstrdup(pool, from->status);
+ to->content_length = from->content_length;
+ if (from->rheader) {
+ to->ngheader = make_ngheader(pool, to->status, from->rheader);
}
+ return to;
}
typedef struct {
size_t nvstrlen;
size_t offset;
char *strbuf;
- h2_response *response;
- int debug;
- request_rec *r;
+ apr_pool_t *pool;
} nvctx_t;
-static int count_headers(void *ctx, const char *key, const char *value)
+static int count_header(void *ctx, const char *key, const char *value)
{
if (!ignore_header(key)) {
nvctx_t *nvctx = (nvctx_t*)ctx;
{
if (!ignore_header(key)) {
nvctx_t *nvctx = (nvctx_t*)ctx;
- if (nvctx->debug) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_EINVAL,
- nvctx->r, "h2_response(%d) header -> %s: %s",
- nvctx->response->stream_id, key, value);
- }
- NV_ADD_CS_CS(ctx, key, value);
+ NV_ADD_CS_CS(nvctx, key, value);
}
return 1;
}
-static void convert_header(h2_response *response, apr_table_t *headers,
- const char *status, request_rec *r)
+static h2_ngheader *make_ngheader(apr_pool_t *pool, const char *status,
+ apr_table_t *header)
{
size_t n;
- h2_headers *h;
- nvctx_t ctx = { NULL, 1, strlen(status) + 1, 0, NULL,
- response, r? APLOGrdebug(r) : 0, r };
+ h2_ngheader *h;
+ nvctx_t ctx = { NULL, 1, strlen(status) + 1, 0, NULL, pool };
- apr_table_do(count_headers, &ctx, headers, NULL);
+ apr_table_do(count_header, &ctx, header, NULL);
- n = (sizeof(h2_headers)
+ n = (sizeof(h2_ngheader)
+ (ctx.nvlen * sizeof(nghttp2_nv)) + ctx.nvstrlen);
- /* XXX: Why calloc, Why not on the pool of the request? */
- h = calloc(1, n);
+ h = apr_pcalloc(pool, n);
if (h) {
ctx.nv = (nghttp2_nv*)(h + 1);
ctx.strbuf = (char*)&ctx.nv[ctx.nvlen];
NV_ADD_LIT_CS(&ctx, ":status", status);
- apr_table_do(add_header, &ctx, headers, NULL);
+ apr_table_do(add_header, &ctx, header, NULL);
h->nv = ctx.nv;
h->nvlen = ctx.nvlen;
- h->status = (const char *)ctx.nv[0].value;
- h->refs = 1;
- response->headers = h;
}
+ return h;
}
/* h2_response is just the data belonging the the head of a HTTP response,
* suitable prepared to be fed to nghttp2 for response submit.
*/
-typedef struct h2_headers {
+typedef struct h2_ngheader {
nghttp2_nv *nv;
apr_size_t nvlen;
- const char *status;
- volatile int refs;
-} h2_headers;
+} h2_ngheader;
typedef struct h2_response {
int stream_id;
+ const char *status;
apr_off_t content_length;
- h2_headers *headers;
+ apr_table_t *rheader;
+ h2_ngheader *ngheader;
} h2_response;
h2_response *h2_response_create(int stream_id,
h2_response *h2_response_rcreate(int stream_id, request_rec *r,
apr_table_t *header, apr_pool_t *pool);
-void h2_response_cleanup(h2_response *response);
void h2_response_destroy(h2_response *response);
-void h2_response_copy(h2_response *to, h2_response *from);
+h2_response *h2_response_copy(apr_pool_t *pool, h2_response *from);
#endif /* defined(__mod_h2__h2_response__) */
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
"h2_stream(%ld-%d): submitting response %s",
- session->id, response->stream_id, response->headers->status);
+ session->id, response->stream_id, response->status);
rv = nghttp2_submit_response(session->ngh2, response->stream_id,
- response->headers->nv,
- response->headers->nvlen, &provider);
+ response->ngheader->nv,
+ response->ngheader->nvlen, &provider);
if (rv != 0) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, session->c,
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
"h2_stream(%ld-%d): submitted response %s, rv=%d",
session->id, response->stream_id,
- response->headers->status, rv);
+ response->status, rv);
}
return rv;
}
AP_DEBUG_ASSERT(stream);
AP_DEBUG_ASSERT(stream->response);
- if (stream->response->headers) {
+ if (stream->response->ngheader) {
rv = submit_response(session, stream->response);
}
else {
* @macro
* Version number of the h2 module as c string
*/
-#define MOD_H2_VERSION "0.9.1"
+#define MOD_H2_VERSION "0.9.2"
/**
* @macro
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define MOD_H2_VERSION_NUM 0x010000
+#define MOD_H2_VERSION_NUM 0x000902
#endif /* mod_h2_h2_version_h */