-*- coding: utf-8 -*-
Changes with Apache 2.5.0
+ *) mod_http2/mod_proxy_http2: h2_request.c is no longer shared between these
+ modules. This simplifies building on platforms such as Windows, as module
+ reference used in logging is now clear.
+
*) mod_proxy, mod_ssl: Handle SSLProxy* directives in <Proxy> sections,
allowing per backend TLS configuration. [Yann Ylavic]
SET(mod_proxy_http2_extra_defines ssize_t=long)
SET(mod_proxy_http2_extra_libs ${NGHTTP2_LIBRARIES})
SET(mod_proxy_http2_extra_sources
- modules/http2/h2_proxy_session.c modules/http2/h2_request.c
- modules/http2/h2_util.c
+ modules/http2/h2_proxy_session.c modules/http2/h2_util.c
)
SET(mod_proxy_http2_extra_libs mod_proxy)
SET(mod_ratelimit_extra_defines AP_RL_DECLARE_EXPORT)
@echo $(DL) h2_iq_remove,$(DL) >> $@
@echo $(DL) h2_log2,$(DL) >> $@
@echo $(DL) h2_proxy_res_ignore_header,$(DL) >> $@
- @echo $(DL) h2_request_create,$(DL) >> $@
- @echo $(DL) h2_request_make,$(DL) >> $@
+ @echo $(DL) h2_headers_add_h1,$(DL) >> $@
+ @echo $(DL) h2_req_create,$(DL) >> $@
+ @echo $(DL) h2_req_createn,$(DL) >> $@
+ @echo $(DL) h2_req_make,$(DL) >> $@
@echo $(DL) h2_util_camel_case_header,$(DL) >> $@
@echo $(DL) h2_util_frame_print,$(DL) >> $@
@echo $(DL) h2_util_ngheader_make_req,$(DL) >> $@
proxy_http2_objs="dnl
mod_proxy_http2.lo dnl
h2_proxy_session.lo dnl
-h2_request.lo dnl
h2_util.lo dnl
"
#include "h2_session.h"
#include "h2_task.h"
#include "h2_ctx.h"
-#include "h2_private.h"
static h2_ctx *h2_ctx_create(const conn_rec *c)
{
#include <nghttp2/nghttp2.h>
+#ifdef IS_MOD_PROXY_HTTP2
+extern module AP_MODULE_DECLARE_DATA proxy_http2_module;
+APLOG_USE_MODULE(proxy_http2);
+#else
extern module AP_MODULE_DECLARE_DATA http2_module;
-
APLOG_USE_MODULE(http2);
+#endif
#endif
#include "mod_http2.h"
#include "h2.h"
-#include "h2_request.h"
#include "h2_util.h"
#include "h2_proxy_session.h"
apr_socket_t *s;
s = ap_get_conn_socket(session->c);
+#if (!defined(WIN32) && !defined(NETWARE)) || defined(DOXYGEN)
if (s) {
ap_sock_disable_nagle(s);
}
+#endif
settings[0].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
settings[0].value = 0;
stream->input = apr_brigade_create(stream->pool, session->c->bucket_alloc);
stream->output = apr_brigade_create(stream->pool, session->c->bucket_alloc);
- stream->req = h2_request_create(1, stream->pool, 0);
+ stream->req = h2_req_create(1, stream->pool, 0);
apr_uri_parse(stream->pool, url, &puri);
scheme = (strcmp(puri.scheme, "h2")? "http" : "https");
authority = apr_psprintf(stream->pool, "%s:%d", authority, puri.port);
}
path = apr_uri_unparse(stream->pool, &puri, APR_URI_UNP_OMITSITEPART);
- h2_request_make(stream->req, stream->pool, r->method, scheme,
- authority, path, r->headers_in);
+ h2_req_make(stream->req, stream->pool, r->method, scheme,
+ authority, path, r->headers_in);
/* Tuck away all already existing cookies */
stream->saves = apr_table_make(r->pool, 2);
}
headers = apr_table_make(ctx->pool, 5);
apr_table_do(set_push_header, headers, ctx->req->headers, NULL);
- req = h2_request_createn(0, ctx->pool, method, ctx->req->scheme,
- ctx->req->authority, path, headers,
- ctx->req->serialize);
+ req = h2_req_createn(0, ctx->pool, method, ctx->req->scheme,
+ ctx->req->authority, path, headers,
+ ctx->req->serialize);
/* atm, we do not push on pushes */
h2_request_end_headers(req, ctx->pool, 1, 0);
push->req = req;
#include "h2_util.h"
-h2_request *h2_request_create(int id, apr_pool_t *pool, int serialize)
-{
- return h2_request_createn(id, pool, NULL, NULL, NULL, NULL, NULL,
- serialize);
-}
-
-h2_request *h2_request_createn(int id, apr_pool_t *pool,
- const char *method, const char *scheme,
- const char *authority, const char *path,
- apr_table_t *header, int serialize)
-{
- h2_request *req = apr_pcalloc(pool, sizeof(h2_request));
-
- req->id = id;
- req->method = method;
- req->scheme = scheme;
- req->authority = authority;
- req->path = path;
- req->headers = header? header : apr_table_make(pool, 10);
- req->request_time = apr_time_now();
- req->serialize = serialize;
-
- return req;
-}
-
static apr_status_t inspect_clen(h2_request *req, const char *s)
{
char *end;
return (s == end)? APR_EINVAL : APR_SUCCESS;
}
-static apr_status_t add_h1_header(h2_request *req, apr_pool_t *pool,
- const char *name, size_t nlen,
- const char *value, size_t vlen)
-{
- char *hname, *hvalue;
-
- if (h2_req_ignore_header(name, nlen)) {
- return APR_SUCCESS;
- }
- else if (H2_HD_MATCH_LIT("cookie", name, nlen)) {
- const char *existing = apr_table_get(req->headers, "cookie");
- if (existing) {
- char *nval;
-
- /* Cookie header come separately in HTTP/2, but need
- * to be merged by "; " (instead of default ", ")
- */
- hvalue = apr_pstrndup(pool, value, vlen);
- nval = apr_psprintf(pool, "%s; %s", existing, hvalue);
- apr_table_setn(req->headers, "Cookie", nval);
- return APR_SUCCESS;
- }
- }
- else if (H2_HD_MATCH_LIT("host", name, nlen)) {
- if (apr_table_get(req->headers, "Host")) {
- return APR_SUCCESS; /* ignore duplicate */
- }
- }
-
- hname = apr_pstrndup(pool, name, nlen);
- hvalue = apr_pstrndup(pool, value, vlen);
- h2_util_camel_case_header(hname, nlen);
- apr_table_mergen(req->headers, hname, hvalue);
-
- return APR_SUCCESS;
-}
-
-typedef struct {
- h2_request *req;
- apr_pool_t *pool;
-} h1_ctx;
-
-static int set_h1_header(void *ctx, const char *key, const char *value)
-{
- h1_ctx *x = ctx;
- size_t klen = strlen(key);
- if (!h2_req_ignore_header(key, klen)) {
- add_h1_header(x->req, x->pool, key, klen, value, strlen(value));
- }
- return 1;
-}
-
-static apr_status_t add_all_h1_header(h2_request *req, apr_pool_t *pool,
- apr_table_t *header)
-{
- h1_ctx x;
- x.req = req;
- x.pool = pool;
- apr_table_do(set_h1_header, &x, header, NULL);
- return APR_SUCCESS;
-}
-
-
-apr_status_t h2_request_make(h2_request *req, apr_pool_t *pool,
- const char *method, const char *scheme,
- const char *authority, const char *path,
- apr_table_t *headers)
-{
- req->method = method;
- req->scheme = scheme;
- req->authority = authority;
- req->path = path;
-
- AP_DEBUG_ASSERT(req->scheme);
- AP_DEBUG_ASSERT(req->authority);
- AP_DEBUG_ASSERT(req->path);
- AP_DEBUG_ASSERT(req->method);
-
- return add_all_h1_header(req, pool, headers);
-}
-
apr_status_t h2_request_rwrite(h2_request *req, request_rec *r)
{
apr_status_t status;
}
}
- status = h2_request_make(req, r->pool, r->method, scheme, authority,
- apr_uri_unparse(r->pool, &r->parsed_uri,
- APR_URI_UNP_OMITSITEPART),
- r->headers_in);
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03058)
- "h2_request(%d): rwrite %s host=%s://%s%s",
- req->id, req->method, req->scheme, req->authority, req->path);
+ status = h2_req_make(req, r->pool, r->method, scheme, authority,
+ apr_uri_unparse(r->pool, &r->parsed_uri,
+ APR_URI_UNP_OMITSITEPART),
+ r->headers_in);
return status;
}
}
else {
/* non-pseudo header, append to work bucket of stream */
- status = add_h1_header(req, pool, name, nlen, value, vlen);
+ status = h2_headers_add_h1(req->headers, pool, name, nlen, value, vlen);
}
return status;
#include "h2.h"
-h2_request *h2_request_create(int id, apr_pool_t *pool, int serialize);
-
-h2_request *h2_request_createn(int id, apr_pool_t *pool,
- const char *method, const char *scheme,
- const char *authority, const char *path,
- apr_table_t *headers, int serialize);
-
-apr_status_t h2_request_make(h2_request *req, apr_pool_t *pool,
- const char *method, const char *scheme,
- const char *authority, const char *path,
- apr_table_t *headers);
-
apr_status_t h2_request_rwrite(h2_request *req, request_rec *r);
apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
/*CL*/{ 1, 1, 0, 0, 1, 1, 1 },
};
-#define H2_STREAM_OUT_LOG(lvl,s,msg) \
- do { \
- if (APLOG_C_IS_LEVEL((s)->session->c,lvl)) \
- h2_util_bb_log((s)->session->c,(s)->session->id,lvl,msg,(s)->buffer); \
- } while(0)
-
+static void H2_STREAM_OUT_LOG(int lvl, h2_stream *s, char *tag)
+{
+ if (APLOG_C_IS_LEVEL(s->session->c, lvl)) {
+ conn_rec *c = s->session->c;
+ char buffer[4 * 1024];
+ const char *line = "(null)";
+ apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]);
+
+ len = h2_util_bb_print(buffer, bmax, tag, "", s->buffer);
+ ap_log_cerror(APLOG_MARK, lvl, 0, c, "bb_dump(%ld-%d): %s",
+ c->id, s->id, len? buffer : line);
+ }
+}
static int set_state(h2_stream *stream, h2_stream_state_t state)
{
req->initiated_on = initiated_on;
}
else {
- req = h2_request_create(id, pool,
+ req = h2_req_create(id, pool,
h2_config_geti(session->config, H2_CONF_SER_HEADERS));
}
stream->request = req;
status = h2_request_rwrite(stream->request, r);
stream->request->serialize = h2_config_geti(h2_config_rget(r),
H2_CONF_SER_HEADERS);
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03058)
+ "h2_request(%d): rwrite %s host=%s://%s%s",
+ stream->request->id, stream->request->method,
+ stream->request->scheme, stream->request->authority,
+ stream->request->path);
return status;
}
#include <nghttp2/nghttp2.h>
-#include "h2_private.h"
-#include "h2_request.h"
+#include "h2.h"
#include "h2_util.h"
/* h2_log2(n) iff n is a power of 2 */
return off;
}
-void h2_util_bb_log(conn_rec *c, int stream_id, int level,
- const char *tag, apr_bucket_brigade *bb)
-{
- char buffer[4 * 1024];
- const char *line = "(null)";
- apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]);
-
- len = h2_util_bb_print(buffer, bmax, tag, "", bb);
- /* Intentional no APLOGNO */
- ap_log_cerror(APLOG_MARK, level, 0, c, "bb_dump(%ld-%d): %s",
- c->id, stream_id, len? buffer : line);
-}
-
apr_status_t h2_append_brigade(apr_bucket_brigade *to,
apr_bucket_brigade *from,
apr_off_t *plen,
|| ignore_header(H2_LIT_ARGS(IgnoredProxyRespHds), name, len));
}
+apr_status_t h2_headers_add_h1(apr_table_t *headers, apr_pool_t *pool,
+ const char *name, size_t nlen,
+ const char *value, size_t vlen)
+{
+ char *hname, *hvalue;
+
+ if (h2_req_ignore_header(name, nlen)) {
+ return APR_SUCCESS;
+ }
+ else if (H2_HD_MATCH_LIT("cookie", name, nlen)) {
+ const char *existing = apr_table_get(headers, "cookie");
+ if (existing) {
+ char *nval;
+
+ /* Cookie header come separately in HTTP/2, but need
+ * to be merged by "; " (instead of default ", ")
+ */
+ hvalue = apr_pstrndup(pool, value, vlen);
+ nval = apr_psprintf(pool, "%s; %s", existing, hvalue);
+ apr_table_setn(headers, "Cookie", nval);
+ return APR_SUCCESS;
+ }
+ }
+ else if (H2_HD_MATCH_LIT("host", name, nlen)) {
+ if (apr_table_get(headers, "Host")) {
+ return APR_SUCCESS; /* ignore duplicate */
+ }
+ }
+
+ hname = apr_pstrndup(pool, name, nlen);
+ hvalue = apr_pstrndup(pool, value, vlen);
+ h2_util_camel_case_header(hname, nlen);
+ apr_table_mergen(headers, hname, hvalue);
+
+ return APR_SUCCESS;
+}
+
+/*******************************************************************************
+ * h2 request handling
+ ******************************************************************************/
+
+h2_request *h2_req_createn(int id, apr_pool_t *pool, const char *method,
+ const char *scheme, const char *authority,
+ const char *path, apr_table_t *header, int serialize)
+{
+ h2_request *req = apr_pcalloc(pool, sizeof(h2_request));
+
+ req->id = id;
+ req->method = method;
+ req->scheme = scheme;
+ req->authority = authority;
+ req->path = path;
+ req->headers = header? header : apr_table_make(pool, 10);
+ req->request_time = apr_time_now();
+ req->serialize = serialize;
+
+ return req;
+}
+
+h2_request *h2_req_create(int id, apr_pool_t *pool, int serialize)
+{
+ return h2_req_createn(id, pool, NULL, NULL, NULL, NULL, NULL, serialize);
+}
+
+typedef struct {
+ apr_table_t *headers;
+ apr_pool_t *pool;
+} h1_ctx;
+
+static int set_h1_header(void *ctx, const char *key, const char *value)
+{
+ h1_ctx *x = ctx;
+ size_t klen = strlen(key);
+ if (!h2_req_ignore_header(key, klen)) {
+ h2_headers_add_h1(x->headers, x->pool, key, klen, value, strlen(value));
+ }
+ return 1;
+}
+
+apr_status_t h2_req_make(h2_request *req, apr_pool_t *pool,
+ const char *method, const char *scheme,
+ const char *authority, const char *path,
+ apr_table_t *headers)
+{
+ h1_ctx x;
+
+ req->method = method;
+ req->scheme = scheme;
+ req->authority = authority;
+ req->path = path;
+
+ AP_DEBUG_ASSERT(req->scheme);
+ AP_DEBUG_ASSERT(req->authority);
+ AP_DEBUG_ASSERT(req->path);
+ AP_DEBUG_ASSERT(req->method);
+
+ x.pool = pool;
+ x.headers = req->headers;
+ apr_table_do(set_h1_header, &x, headers, NULL);
+ return APR_SUCCESS;
+}
/*******************************************************************************
* frame logging
h2_ngheader *h2_util_ngheader_make_req(apr_pool_t *p,
const struct h2_request *req);
+apr_status_t h2_headers_add_h1(apr_table_t *headers, apr_pool_t *pool,
+ const char *name, size_t nlen,
+ const char *value, size_t vlen);
+
+/*******************************************************************************
+ * h2_request helpers
+ ******************************************************************************/
+
+struct h2_request *h2_req_createn(int id, apr_pool_t *pool, const char *method,
+ const char *scheme, const char *authority,
+ const char *path, apr_table_t *header,
+ int serialize);
+struct h2_request *h2_req_create(int id, apr_pool_t *pool, int serialize);
+
+apr_status_t h2_req_make(struct h2_request *req, apr_pool_t *pool,
+ const char *method, const char *scheme,
+ const char *authority, const char *path,
+ apr_table_t *headers);
+
/*******************************************************************************
* apr brigade helpers
******************************************************************************/
* @param tag a short message text about the context
* @param bb the brigade to log
*/
-void h2_util_bb_log(conn_rec *c, int stream_id, int level,
- const char *tag, apr_bucket_brigade *bb);
+#define h2_util_bb_log(c, i, level, tag, bb) \
+do { \
+ char buffer[4 * 1024]; \
+ const char *line = "(null)"; \
+ apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]); \
+ len = h2_util_bb_print(buffer, bmax, (tag), "", (bb)); \
+ ap_log_cerror(APLOG_MARK, level, 0, (c), "bb_dump(%ld-%d): %s", \
+ (c)->id, (int)(i), (len? buffer : line)); \
+} while(0)
+
/**
* Transfer buckets from one brigade to another with a limit on the
#include "mod_proxy_http2.h"
-#include "h2_request.h"
+#include "h2.h"
#include "h2_util.h"
#include "h2_version.h"
#include "h2_proxy_session.h"