Compare commits
15 Commits
imports/c8
...
c8-stream-
Author | SHA1 | Date |
---|---|---|
eabdullin | 414eaf2ac7 | |
eabdullin | c10b412a0d | |
eabdullin | 82c2115e0f | |
CentOS Sources | 1007e8ea16 | |
CentOS Sources | 0a9df3405e | |
CentOS Sources | 203fa9fde1 | |
CentOS Sources | 7e7354bff1 | |
CentOS Sources | 6be70187c2 | |
CentOS Sources | eeec984029 | |
CentOS Sources | f49445b5d8 | |
CentOS Sources | ce3ab9660e | |
CentOS Sources | e774410994 | |
CentOS Sources | 407b246534 | |
CentOS Sources | 76565bc628 | |
CentOS Sources | 101cf8a43f |
|
@ -0,0 +1,20 @@
|
|||
diff --git a/modules/dav/main/util.c b/modules/dav/main/util.c
|
||||
index 1ae5914027c..3f7822fc931 100644
|
||||
--- a/modules/dav/main/util.c
|
||||
+++ b/modules/dav/main/util.c
|
||||
@@ -801,8 +801,14 @@ static dav_error * dav_process_if_header(request_rec *r, dav_if_header **p_ih)
|
||||
"for the same state.");
|
||||
}
|
||||
condition = DAV_IF_COND_NOT;
|
||||
+ list += 2;
|
||||
+ }
|
||||
+ else {
|
||||
+ return dav_new_error(r->pool, HTTP_BAD_REQUEST,
|
||||
+ DAV_ERR_IF_UNK_CHAR, 0,
|
||||
+ "Invalid \"If:\" header: "
|
||||
+ "Unexpected character in List");
|
||||
}
|
||||
- list += 2;
|
||||
break;
|
||||
|
||||
case ' ':
|
|
@ -0,0 +1,12 @@
|
|||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index 5786ea8..7da9bde 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -637,7 +637,6 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
"chunked body with Content-Length (C-L ignored)",
|
||||
c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
req->old_cl_val = NULL;
|
||||
- origin->keepalive = AP_CONN_CLOSE;
|
||||
p_conn->close = 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c
|
||||
index b760941..0825b1b 100644
|
||||
--- a/modules/aaa/mod_auth_digest.c
|
||||
+++ b/modules/aaa/mod_auth_digest.c
|
||||
@@ -1422,9 +1422,14 @@ static int check_nonce(request_rec *r, digest_header_rec *resp,
|
||||
time_rec nonce_time;
|
||||
char tmp, hash[NONCE_HASH_LEN+1];
|
||||
|
||||
- if (strlen(resp->nonce) != NONCE_LEN) {
|
||||
+ /* Since the time part of the nonce is a base64 encoding of an
|
||||
+ * apr_time_t (8 bytes), it should end with a '=', fail early otherwise.
|
||||
+ */
|
||||
+ if (strlen(resp->nonce) != NONCE_LEN
|
||||
+ || resp->nonce[NONCE_TIME_LEN - 1] != '=') {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01775)
|
||||
- "invalid nonce %s received - length is not %d",
|
||||
+ "invalid nonce '%s' received - length is not %d "
|
||||
+ "or time encoding is incorrect",
|
||||
resp->nonce, NONCE_LEN);
|
||||
note_digest_auth_failure(r, conf, resp, 1);
|
||||
return HTTP_UNAUTHORIZED;
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c
|
||||
index 049255d..af70f6b 100644
|
||||
--- a/modules/session/mod_session.c
|
||||
+++ b/modules/session/mod_session.c
|
||||
@@ -317,7 +317,7 @@ static apr_status_t ap_session_set(request_rec * r, session_rec * z,
|
||||
static int identity_count(void *v, const char *key, const char *val)
|
||||
{
|
||||
int *count = v;
|
||||
- *count += strlen(key) * 3 + strlen(val) * 3 + 1;
|
||||
+ *count += strlen(key) * 3 + strlen(val) * 3 + 2;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,706 @@
|
|||
diff --git a/include/http_core.h b/include/http_core.h
|
||||
index 8e10988..3ba8069 100644
|
||||
--- a/include/http_core.h
|
||||
+++ b/include/http_core.h
|
||||
@@ -741,6 +741,7 @@ typedef struct {
|
||||
#define AP_HTTP_METHODS_REGISTERED 2
|
||||
char http_methods;
|
||||
unsigned int merge_slashes;
|
||||
+ unsigned int strict_host_check;
|
||||
} core_server_config;
|
||||
|
||||
/* for AddOutputFiltersByType in core.c */
|
||||
@@ -769,6 +770,11 @@ AP_DECLARE(void) ap_set_server_protocol(server_rec* s, const char* proto);
|
||||
typedef struct core_output_filter_ctx core_output_filter_ctx_t;
|
||||
typedef struct core_filter_ctx core_ctx_t;
|
||||
|
||||
+struct core_filter_ctx {
|
||||
+ apr_bucket_brigade *b;
|
||||
+ apr_bucket_brigade *tmpbb;
|
||||
+};
|
||||
+
|
||||
typedef struct core_net_rec {
|
||||
/** Connection to the client */
|
||||
apr_socket_t *client_socket;
|
||||
diff --git a/include/http_protocol.h b/include/http_protocol.h
|
||||
index 11c7b2d..e7abdd9 100644
|
||||
--- a/include/http_protocol.h
|
||||
+++ b/include/http_protocol.h
|
||||
@@ -53,6 +53,13 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func;
|
||||
* or control the ones that eventually do.
|
||||
*/
|
||||
|
||||
+/**
|
||||
+ * Read an empty request and set reasonable defaults.
|
||||
+ * @param c The current connection
|
||||
+ * @return The new request_rec
|
||||
+ */
|
||||
+AP_DECLARE(request_rec *) ap_create_request(conn_rec *c);
|
||||
+
|
||||
/**
|
||||
* Read a request and fill in the fields.
|
||||
* @param c The current connection
|
||||
@@ -60,6 +67,20 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func;
|
||||
*/
|
||||
request_rec *ap_read_request(conn_rec *c);
|
||||
|
||||
+/**
|
||||
+ * Parse and validate the request line.
|
||||
+ * @param r The current request
|
||||
+ * @return 1 on success, 0 on failure
|
||||
+ */
|
||||
+AP_DECLARE(int) ap_parse_request_line(request_rec *r);
|
||||
+
|
||||
+/**
|
||||
+ * Validate the request header and select vhost.
|
||||
+ * @param r The current request
|
||||
+ * @return 1 on success, 0 on failure
|
||||
+ */
|
||||
+AP_DECLARE(int) ap_check_request_header(request_rec *r);
|
||||
+
|
||||
/**
|
||||
* Read the mime-encoded headers.
|
||||
* @param r The current request
|
||||
diff --git a/include/http_vhost.h b/include/http_vhost.h
|
||||
index 473c9c7..d2d9c97 100644
|
||||
--- a/include/http_vhost.h
|
||||
+++ b/include/http_vhost.h
|
||||
@@ -99,6 +99,19 @@ AP_DECLARE(void) ap_update_vhost_given_ip(conn_rec *conn);
|
||||
*/
|
||||
AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r);
|
||||
|
||||
+/**
|
||||
+ * Updates r->server with the best name-based virtual host match, within
|
||||
+ * the chain of matching virtual hosts selected by ap_update_vhost_given_ip.
|
||||
+ * @param r The current request
|
||||
+ * @param require_match 1 to return an HTTP error if the requested hostname is
|
||||
+ * not explicitly matched to a VirtualHost.
|
||||
+ * @return return HTTP_OK unless require_match was specified and the requested
|
||||
+ * hostname did not match any ServerName, ServerAlias, or VirtualHost
|
||||
+ * address-spec.
|
||||
+ */
|
||||
+AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* Match the host in the header with the hostname of the server for this
|
||||
* request.
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index 84e80f2..23abf57 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -498,6 +498,8 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s)
|
||||
conf->protocols = apr_array_make(a, 5, sizeof(const char *));
|
||||
conf->protocols_honor_order = -1;
|
||||
|
||||
+ conf->strict_host_check= AP_CORE_CONFIG_UNSET;
|
||||
+
|
||||
return (void *)conf;
|
||||
}
|
||||
|
||||
@@ -565,6 +567,12 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
|
||||
|
||||
AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt);
|
||||
|
||||
+ conf->strict_host_check = (virt->strict_host_check != AP_CORE_CONFIG_UNSET)
|
||||
+ ? virt->strict_host_check
|
||||
+ : base->strict_host_check;
|
||||
+
|
||||
+ AP_CORE_MERGE_FLAG(strict_host_check, conf, base, virt);
|
||||
+
|
||||
return conf;
|
||||
}
|
||||
|
||||
@@ -4546,7 +4554,10 @@ AP_INIT_TAKE2("CGIVar", set_cgi_var, NULL, OR_FILEINFO,
|
||||
AP_INIT_FLAG("QualifyRedirectURL", set_qualify_redirect_url, NULL, OR_FILEINFO,
|
||||
"Controls whether HTTP authorization headers, normally hidden, will "
|
||||
"be passed to scripts"),
|
||||
-
|
||||
+AP_INIT_FLAG("StrictHostCheck", set_core_server_flag,
|
||||
+ (void *)APR_OFFSETOF(core_server_config, strict_host_check),
|
||||
+ RSRC_CONF,
|
||||
+ "Controls whether a hostname match is required"),
|
||||
AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
|
||||
(void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
|
||||
"a mime type that overrides other configured type"),
|
||||
@@ -5581,4 +5592,3 @@ AP_DECLARE_MODULE(core) = {
|
||||
core_cmds, /* command apr_table_t */
|
||||
register_hooks /* register hooks */
|
||||
};
|
||||
-
|
||||
diff --git a/server/core_filters.c b/server/core_filters.c
|
||||
index a6c2bd6..e08801f 100644
|
||||
--- a/server/core_filters.c
|
||||
+++ b/server/core_filters.c
|
||||
@@ -84,11 +84,6 @@ struct core_output_filter_ctx {
|
||||
apr_size_t bytes_written;
|
||||
};
|
||||
|
||||
-struct core_filter_ctx {
|
||||
- apr_bucket_brigade *b;
|
||||
- apr_bucket_brigade *tmpbb;
|
||||
-};
|
||||
-
|
||||
|
||||
apr_status_t ap_core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
|
||||
ap_input_mode_t mode, apr_read_type_e block,
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index 8d1fdd2..430d91e 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -609,8 +609,15 @@ AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri)
|
||||
}
|
||||
|
||||
r->args = r->parsed_uri.query;
|
||||
- r->uri = r->parsed_uri.path ? r->parsed_uri.path
|
||||
- : apr_pstrdup(r->pool, "/");
|
||||
+ if (r->parsed_uri.path) {
|
||||
+ r->uri = r->parsed_uri.path;
|
||||
+ }
|
||||
+ else if (r->method_number == M_OPTIONS) {
|
||||
+ r->uri = apr_pstrdup(r->pool, "*");
|
||||
+ }
|
||||
+ else {
|
||||
+ r->uri = apr_pstrdup(r->pool, "/");
|
||||
+ }
|
||||
|
||||
#if defined(OS2) || defined(WIN32)
|
||||
/* Handle path translations for OS/2 and plug security hole.
|
||||
@@ -645,13 +652,6 @@ static int field_name_len(const char *field)
|
||||
|
||||
static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
|
||||
{
|
||||
- enum {
|
||||
- rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
|
||||
- rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
|
||||
- rrl_badmethod09, rrl_reject09
|
||||
- } deferred_error = rrl_none;
|
||||
- char *ll;
|
||||
- char *uri;
|
||||
apr_size_t len;
|
||||
int num_blank_lines = DEFAULT_LIMIT_BLANK_LINES;
|
||||
core_server_config *conf = ap_get_core_module_config(r->server->module_config);
|
||||
@@ -711,6 +711,20 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
|
||||
}
|
||||
|
||||
r->request_time = apr_time_now();
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+AP_DECLARE(int) ap_parse_request_line(request_rec *r)
|
||||
+{
|
||||
+ core_server_config *conf = ap_get_core_module_config(r->server->module_config);
|
||||
+ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
|
||||
+ enum {
|
||||
+ rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
|
||||
+ rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
|
||||
+ rrl_badmethod09, rrl_reject09
|
||||
+ } deferred_error = rrl_none;
|
||||
+ apr_size_t len = 0;
|
||||
+ char *uri, *ll;
|
||||
|
||||
r->method = r->the_request;
|
||||
|
||||
@@ -742,7 +756,6 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
|
||||
if (deferred_error == rrl_none)
|
||||
deferred_error = rrl_missinguri;
|
||||
r->protocol = uri = "";
|
||||
- len = 0;
|
||||
goto rrl_done;
|
||||
}
|
||||
else if (strict && ll[0] && apr_isspace(ll[1])
|
||||
@@ -773,7 +786,6 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
|
||||
/* Verify URI terminated with a single SP, or mark as specific error */
|
||||
if (!ll) {
|
||||
r->protocol = "";
|
||||
- len = 0;
|
||||
goto rrl_done;
|
||||
}
|
||||
else if (strict && ll[0] && apr_isspace(ll[1])
|
||||
@@ -866,6 +878,14 @@ rrl_done:
|
||||
r->header_only = 1;
|
||||
|
||||
ap_parse_uri(r, uri);
|
||||
+ if (r->status == HTTP_OK
|
||||
+ && (r->parsed_uri.path != NULL)
|
||||
+ && (r->parsed_uri.path[0] != '/')
|
||||
+ && (r->method_number != M_OPTIONS
|
||||
+ || strcmp(r->parsed_uri.path, "*") != 0)) {
|
||||
+ /* Invalid request-target per RFC 7230 section 5.3 */
|
||||
+ r->status = HTTP_BAD_REQUEST;
|
||||
+ }
|
||||
|
||||
/* With the request understood, we can consider HTTP/0.9 specific errors */
|
||||
if (r->proto_num == HTTP_VERSION(0, 9) && deferred_error == rrl_none) {
|
||||
@@ -973,6 +993,79 @@ rrl_failed:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+AP_DECLARE(int) ap_check_request_header(request_rec *r)
|
||||
+{
|
||||
+ core_server_config *conf;
|
||||
+ int strict_host_check;
|
||||
+ const char *expect;
|
||||
+ int access_status;
|
||||
+
|
||||
+ conf = ap_get_core_module_config(r->server->module_config);
|
||||
+
|
||||
+ /* update what we think the virtual host is based on the headers we've
|
||||
+ * now read. may update status.
|
||||
+ */
|
||||
+ strict_host_check = (conf->strict_host_check == AP_CORE_CONFIG_ON);
|
||||
+ access_status = ap_update_vhost_from_headers_ex(r, strict_host_check);
|
||||
+ if (strict_host_check && access_status != HTTP_OK) {
|
||||
+ if (r->server == ap_server_conf) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10156)
|
||||
+ "Requested hostname '%s' did not match any ServerName/ServerAlias "
|
||||
+ "in the global server configuration ", r->hostname);
|
||||
+ }
|
||||
+ else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10157)
|
||||
+ "Requested hostname '%s' did not match any ServerName/ServerAlias "
|
||||
+ "in the matching virtual host (default vhost for "
|
||||
+ "current connection is %s:%u)",
|
||||
+ r->hostname, r->server->defn_name, r->server->defn_line_number);
|
||||
+ }
|
||||
+ r->status = access_status;
|
||||
+ }
|
||||
+ if (r->status != HTTP_OK) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1, 1)))
|
||||
+ || ((r->proto_num == HTTP_VERSION(1, 1))
|
||||
+ && !apr_table_get(r->headers_in, "Host"))) {
|
||||
+ /*
|
||||
+ * Client sent us an HTTP/1.1 or later request without telling us the
|
||||
+ * hostname, either with a full URL or a Host: header. We therefore
|
||||
+ * need to (as per the 1.1 spec) send an error. As a special case,
|
||||
+ * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
|
||||
+ * a Host: header, and the server MUST respond with 400 if it doesn't.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569)
|
||||
+ "client sent HTTP/1.1 request without hostname "
|
||||
+ "(see RFC2616 section 14.23): %s", r->uri);
|
||||
+ r->status = HTTP_BAD_REQUEST;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL)
|
||||
+ && (expect[0] != '\0')) {
|
||||
+ /*
|
||||
+ * The Expect header field was added to HTTP/1.1 after RFC 2068
|
||||
+ * as a means to signal when a 100 response is desired and,
|
||||
+ * unfortunately, to signal a poor man's mandatory extension that
|
||||
+ * the server must understand or return 417 Expectation Failed.
|
||||
+ */
|
||||
+ if (ap_cstr_casecmp(expect, "100-continue") == 0) {
|
||||
+ r->expecting_100 = 1;
|
||||
+ }
|
||||
+ else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570)
|
||||
+ "client sent an unrecognized expectation value "
|
||||
+ "of Expect: %s", expect);
|
||||
+ r->status = HTTP_EXPECTATION_FAILED;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
static int table_do_fn_check_lengths(void *r_, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
@@ -1256,16 +1349,10 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec *r)
|
||||
apr_brigade_destroy(tmp_bb);
|
||||
}
|
||||
|
||||
-request_rec *ap_read_request(conn_rec *conn)
|
||||
+AP_DECLARE(request_rec *) ap_create_request(conn_rec *conn)
|
||||
{
|
||||
request_rec *r;
|
||||
apr_pool_t *p;
|
||||
- const char *expect;
|
||||
- int access_status;
|
||||
- apr_bucket_brigade *tmp_bb;
|
||||
- apr_socket_t *csd;
|
||||
- apr_interval_time_t cur_timeout;
|
||||
-
|
||||
|
||||
apr_pool_create(&p, conn->pool);
|
||||
apr_pool_tag(p, "request");
|
||||
@@ -1304,6 +1391,7 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
r->read_body = REQUEST_NO_BODY;
|
||||
|
||||
r->status = HTTP_OK; /* Until further notice */
|
||||
+ r->header_only = 0;
|
||||
r->the_request = NULL;
|
||||
|
||||
/* Begin by presuming any module can make its own path_info assumptions,
|
||||
@@ -1314,12 +1402,33 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
r->useragent_addr = conn->client_addr;
|
||||
r->useragent_ip = conn->client_ip;
|
||||
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+/* Apply the server's timeout/config to the connection/request. */
|
||||
+static void apply_server_config(request_rec *r)
|
||||
+{
|
||||
+ apr_socket_t *csd;
|
||||
+
|
||||
+ csd = ap_get_conn_socket(r->connection);
|
||||
+ apr_socket_timeout_set(csd, r->server->timeout);
|
||||
+
|
||||
+ r->per_dir_config = r->server->lookup_defaults;
|
||||
+}
|
||||
+
|
||||
+request_rec *ap_read_request(conn_rec *conn)
|
||||
+{
|
||||
+ int access_status;
|
||||
+ apr_bucket_brigade *tmp_bb;
|
||||
+
|
||||
+ request_rec *r = ap_create_request(conn);
|
||||
tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
|
||||
ap_run_pre_read_request(r, conn);
|
||||
|
||||
/* Get the request... */
|
||||
- if (!read_request_line(r, tmp_bb)) {
|
||||
+ if (!read_request_line(r, tmp_bb) || !ap_parse_request_line(r)) {
|
||||
+ apr_brigade_cleanup(tmp_bb);
|
||||
switch (r->status) {
|
||||
case HTTP_REQUEST_URI_TOO_LARGE:
|
||||
case HTTP_BAD_REQUEST:
|
||||
@@ -1335,49 +1444,38 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
"request failed: malformed request line");
|
||||
}
|
||||
access_status = r->status;
|
||||
- r->status = HTTP_OK;
|
||||
- ap_die(access_status, r);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- r = NULL;
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- goto traceout;
|
||||
+ goto die_unusable_input;
|
||||
+
|
||||
case HTTP_REQUEST_TIME_OUT:
|
||||
+ /* Just log, no further action on this connection. */
|
||||
ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, NULL);
|
||||
if (!r->connection->keepalives)
|
||||
ap_run_log_transaction(r);
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- goto traceout;
|
||||
- default:
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- r = NULL;
|
||||
- goto traceout;
|
||||
+ break;
|
||||
}
|
||||
+ /* Not worth dying with. */
|
||||
+ conn->keepalive = AP_CONN_CLOSE;
|
||||
+ apr_pool_destroy(r->pool);
|
||||
+ goto ignore;
|
||||
}
|
||||
+ apr_brigade_cleanup(tmp_bb);
|
||||
|
||||
/* We may have been in keep_alive_timeout mode, so toggle back
|
||||
* to the normal timeout mode as we fetch the header lines,
|
||||
* as necessary.
|
||||
*/
|
||||
- csd = ap_get_conn_socket(conn);
|
||||
- apr_socket_timeout_get(csd, &cur_timeout);
|
||||
- if (cur_timeout != conn->base_server->timeout) {
|
||||
- apr_socket_timeout_set(csd, conn->base_server->timeout);
|
||||
- cur_timeout = conn->base_server->timeout;
|
||||
- }
|
||||
+ apply_server_config(r);
|
||||
|
||||
if (!r->assbackwards) {
|
||||
const char *tenc;
|
||||
|
||||
ap_get_mime_headers_core(r, tmp_bb);
|
||||
+ apr_brigade_cleanup(tmp_bb);
|
||||
if (r->status != HTTP_OK) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00567)
|
||||
"request failed: error reading the headers");
|
||||
- ap_send_error_response(r, 0);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- goto traceout;
|
||||
+ access_status = r->status;
|
||||
+ goto die_unusable_input;
|
||||
}
|
||||
|
||||
tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
|
||||
@@ -1393,13 +1491,8 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02539)
|
||||
"client sent unknown Transfer-Encoding "
|
||||
"(%s): %s", tenc, r->uri);
|
||||
- r->status = HTTP_BAD_REQUEST;
|
||||
- conn->keepalive = AP_CONN_CLOSE;
|
||||
- ap_send_error_response(r, 0);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
- goto traceout;
|
||||
+ access_status = HTTP_BAD_REQUEST;
|
||||
+ goto die_unusable_input;
|
||||
}
|
||||
|
||||
/* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23
|
||||
@@ -1412,88 +1505,81 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
}
|
||||
}
|
||||
|
||||
- apr_brigade_destroy(tmp_bb);
|
||||
-
|
||||
- /* update what we think the virtual host is based on the headers we've
|
||||
- * now read. may update status.
|
||||
- */
|
||||
- ap_update_vhost_from_headers(r);
|
||||
- access_status = r->status;
|
||||
-
|
||||
- /* Toggle to the Host:-based vhost's timeout mode to fetch the
|
||||
- * request body and send the response body, if needed.
|
||||
- */
|
||||
- if (cur_timeout != r->server->timeout) {
|
||||
- apr_socket_timeout_set(csd, r->server->timeout);
|
||||
- cur_timeout = r->server->timeout;
|
||||
- }
|
||||
-
|
||||
- /* we may have switched to another server */
|
||||
- r->per_dir_config = r->server->lookup_defaults;
|
||||
-
|
||||
- if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1, 1)))
|
||||
- || ((r->proto_num == HTTP_VERSION(1, 1))
|
||||
- && !apr_table_get(r->headers_in, "Host"))) {
|
||||
- /*
|
||||
- * Client sent us an HTTP/1.1 or later request without telling us the
|
||||
- * hostname, either with a full URL or a Host: header. We therefore
|
||||
- * need to (as per the 1.1 spec) send an error. As a special case,
|
||||
- * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
|
||||
- * a Host: header, and the server MUST respond with 400 if it doesn't.
|
||||
- */
|
||||
- access_status = HTTP_BAD_REQUEST;
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569)
|
||||
- "client sent HTTP/1.1 request without hostname "
|
||||
- "(see RFC2616 section 14.23): %s", r->uri);
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* Add the HTTP_IN filter here to ensure that ap_discard_request_body
|
||||
* called by ap_die and by ap_send_error_response works correctly on
|
||||
* status codes that do not cause the connection to be dropped and
|
||||
* in situations where the connection should be kept alive.
|
||||
*/
|
||||
-
|
||||
ap_add_input_filter_handle(ap_http_input_filter_handle,
|
||||
NULL, r, r->connection);
|
||||
|
||||
- if (access_status != HTTP_OK
|
||||
- || (access_status = ap_run_post_read_request(r))) {
|
||||
- ap_die(access_status, r);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- r = NULL;
|
||||
- goto traceout;
|
||||
+ /* Validate Host/Expect headers and select vhost. */
|
||||
+ if (!ap_check_request_header(r)) {
|
||||
+ /* we may have switched to another server still */
|
||||
+ apply_server_config(r);
|
||||
+ access_status = r->status;
|
||||
+ goto die_before_hooks;
|
||||
}
|
||||
|
||||
- if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL)
|
||||
- && (expect[0] != '\0')) {
|
||||
- /*
|
||||
- * The Expect header field was added to HTTP/1.1 after RFC 2068
|
||||
- * as a means to signal when a 100 response is desired and,
|
||||
- * unfortunately, to signal a poor man's mandatory extension that
|
||||
- * the server must understand or return 417 Expectation Failed.
|
||||
- */
|
||||
- if (strcasecmp(expect, "100-continue") == 0) {
|
||||
- r->expecting_100 = 1;
|
||||
- }
|
||||
- else {
|
||||
- r->status = HTTP_EXPECTATION_FAILED;
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570)
|
||||
- "client sent an unrecognized expectation value of "
|
||||
- "Expect: %s", expect);
|
||||
- ap_send_error_response(r, 0);
|
||||
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
|
||||
- ap_run_log_transaction(r);
|
||||
- goto traceout;
|
||||
- }
|
||||
+ /* we may have switched to another server */
|
||||
+ apply_server_config(r);
|
||||
+
|
||||
+ if ((access_status = ap_run_post_read_request(r))) {
|
||||
+ goto die;
|
||||
}
|
||||
|
||||
- AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, (char *)r->uri, (char *)r->server->defn_name, r->status);
|
||||
+ AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
|
||||
+ (char *)r->uri, (char *)r->server->defn_name,
|
||||
+ r->status);
|
||||
+
|
||||
return r;
|
||||
- traceout:
|
||||
+
|
||||
+ /* Everything falls through on failure */
|
||||
+
|
||||
+die_unusable_input:
|
||||
+ /* Input filters are in an undeterminate state, cleanup (including
|
||||
+ * CORE_IN's socket) such that any further attempt to read is EOF.
|
||||
+ */
|
||||
+ {
|
||||
+ ap_filter_t *f = conn->input_filters;
|
||||
+ while (f) {
|
||||
+ if (f->frec == ap_core_input_filter_handle) {
|
||||
+ core_net_rec *net = f->ctx;
|
||||
+ apr_brigade_cleanup(net->in_ctx->b);
|
||||
+ break;
|
||||
+ }
|
||||
+ ap_remove_input_filter(f);
|
||||
+ f = f->next;
|
||||
+ }
|
||||
+ conn->input_filters = r->input_filters = f;
|
||||
+ conn->keepalive = AP_CONN_CLOSE;
|
||||
+ }
|
||||
+
|
||||
+die_before_hooks:
|
||||
+ /* First call to ap_die() (non recursive) */
|
||||
+ r->status = HTTP_OK;
|
||||
+
|
||||
+die:
|
||||
+ ap_die(access_status, r);
|
||||
+
|
||||
+ /* ap_die() sent the response through the output filters, we must now
|
||||
+ * end the request with an EOR bucket for stream/pipeline accounting.
|
||||
+ */
|
||||
+ {
|
||||
+ apr_bucket_brigade *eor_bb;
|
||||
+ eor_bb = apr_brigade_create(conn->pool, conn->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(eor_bb,
|
||||
+ ap_bucket_eor_create(conn->bucket_alloc, r));
|
||||
+ ap_pass_brigade(conn->output_filters, eor_bb);
|
||||
+ apr_brigade_cleanup(eor_bb);
|
||||
+ }
|
||||
+
|
||||
+ignore:
|
||||
+ r = NULL;
|
||||
+
|
||||
AP_READ_REQUEST_FAILURE((uintptr_t)r);
|
||||
- return r;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
/* if a request with a body creates a subrequest, remove original request's
|
||||
diff --git a/server/vhost.c b/server/vhost.c
|
||||
index b23b2dd..6e233b5 100644
|
||||
--- a/server/vhost.c
|
||||
+++ b/server/vhost.c
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "http_vhost.h"
|
||||
#include "http_protocol.h"
|
||||
#include "http_core.h"
|
||||
+#include "http_main.h"
|
||||
|
||||
#if APR_HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
@@ -973,7 +974,13 @@ AP_DECLARE(int) ap_matches_request_vhost(request_rec *r, const char *host,
|
||||
}
|
||||
|
||||
|
||||
-static void check_hostalias(request_rec *r)
|
||||
+/*
|
||||
+ * Updates r->server from ServerName/ServerAlias. Per the interaction
|
||||
+ * of ip and name-based vhosts, it only looks in the best match from the
|
||||
+ * connection-level ip-based matching.
|
||||
+ * Returns HTTP_BAD_REQUEST if there was no match.
|
||||
+ */
|
||||
+static int update_server_from_aliases(request_rec *r)
|
||||
{
|
||||
/*
|
||||
* Even if the request has a Host: header containing a port we ignore
|
||||
@@ -1050,11 +1057,18 @@ static void check_hostalias(request_rec *r)
|
||||
goto found;
|
||||
}
|
||||
|
||||
- return;
|
||||
+ if (!r->connection->vhost_lookup_data) {
|
||||
+ if (matches_aliases(r->server, host)) {
|
||||
+ s = r->server;
|
||||
+ goto found;
|
||||
+ }
|
||||
+ }
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
|
||||
found:
|
||||
/* s is the first matching server, we're done */
|
||||
r->server = s;
|
||||
+ return HTTP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1071,7 +1085,7 @@ static void check_serverpath(request_rec *r)
|
||||
* This is in conjunction with the ServerPath code in http_core, so we
|
||||
* get the right host attached to a non- Host-sending request.
|
||||
*
|
||||
- * See the comment in check_hostalias about how each vhost can be
|
||||
+ * See the comment in update_server_from_aliases about how each vhost can be
|
||||
* listed multiple times.
|
||||
*/
|
||||
|
||||
@@ -1134,11 +1148,17 @@ static APR_INLINE const char *construct_host_header(request_rec *r,
|
||||
}
|
||||
|
||||
AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
|
||||
+{
|
||||
+ ap_update_vhost_from_headers_ex(r, 0);
|
||||
+}
|
||||
+
|
||||
+AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match)
|
||||
{
|
||||
core_server_config *conf = ap_get_core_module_config(r->server->module_config);
|
||||
const char *host_header = apr_table_get(r->headers_in, "Host");
|
||||
int is_v6literal = 0;
|
||||
int have_hostname_from_url = 0;
|
||||
+ int rc = HTTP_OK;
|
||||
|
||||
if (r->hostname) {
|
||||
/*
|
||||
@@ -1151,8 +1171,8 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
|
||||
else if (host_header != NULL) {
|
||||
is_v6literal = fix_hostname(r, host_header, conf->http_conformance);
|
||||
}
|
||||
- if (r->status != HTTP_OK)
|
||||
- return;
|
||||
+ if (!require_match && r->status != HTTP_OK)
|
||||
+ return HTTP_OK;
|
||||
|
||||
if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) {
|
||||
/*
|
||||
@@ -1173,10 +1193,16 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
|
||||
/* check if we tucked away a name_chain */
|
||||
if (r->connection->vhost_lookup_data) {
|
||||
if (r->hostname)
|
||||
- check_hostalias(r);
|
||||
+ rc = update_server_from_aliases(r);
|
||||
else
|
||||
check_serverpath(r);
|
||||
}
|
||||
+ else if (require_match && r->hostname) {
|
||||
+ /* check the base server config */
|
||||
+ rc = update_server_from_aliases(r);
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/**
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/server/scoreboard.c b/server/scoreboard.c
|
||||
index 23e3d70..7b01bdf 100644
|
||||
--- a/server/scoreboard.c
|
||||
+++ b/server/scoreboard.c
|
||||
@@ -376,7 +376,7 @@ AP_DECLARE(void) ap_increment_counts(ap_sb_handle_t *sb, request_rec *r)
|
||||
if (pfn_ap_logio_get_last_bytes != NULL) {
|
||||
bytes = pfn_ap_logio_get_last_bytes(r->connection);
|
||||
}
|
||||
- else if (r->method_number == M_GET && r->method[0] == 'H') {
|
||||
+ else if (r->method_number == M_GET && r->method && r->method[0] == 'H') {
|
||||
bytes = 0;
|
||||
}
|
||||
else {
|
|
@ -0,0 +1,45 @@
|
|||
diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
|
||||
index 792d35e..9dcbed1 100644
|
||||
--- a/modules/proxy/mod_proxy_uwsgi.c
|
||||
+++ b/modules/proxy/mod_proxy_uwsgi.c
|
||||
@@ -453,11 +453,8 @@ static int uwsgi_handler(request_rec *r, proxy_worker * worker,
|
||||
const char *proxyname, apr_port_t proxyport)
|
||||
{
|
||||
int status;
|
||||
- int delta = 0;
|
||||
- int decode_status;
|
||||
proxy_conn_rec *backend = NULL;
|
||||
apr_pool_t *p = r->pool;
|
||||
- size_t w_len;
|
||||
char server_portstr[32];
|
||||
char *u_path_info;
|
||||
apr_uri_t *uri;
|
||||
@@ -469,23 +466,14 @@ static int uwsgi_handler(request_rec *r, proxy_worker * worker,
|
||||
|
||||
uri = apr_palloc(r->pool, sizeof(*uri));
|
||||
|
||||
- /* ADD PATH_INFO */
|
||||
-#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
- w_len = strlen(worker->s->name);
|
||||
-#else
|
||||
- w_len = strlen(worker->name);
|
||||
-#endif
|
||||
- u_path_info = r->filename + 6 + w_len;
|
||||
- if (u_path_info[0] != '/') {
|
||||
- delta = 1;
|
||||
- }
|
||||
- decode_status = ap_unescape_url(url + w_len - delta);
|
||||
- if (decode_status) {
|
||||
+ /* ADD PATH_INFO (unescaped) */
|
||||
+ u_path_info = ap_strchr(url + sizeof(UWSGI_SCHEME) + 2, '/');
|
||||
+ if (!u_path_info || ap_unescape_url(u_path_info) != OK) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10100)
|
||||
- "unable to decode uri: %s", url + w_len - delta);
|
||||
+ "unable to decode uwsgi uri: %s", url);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
- apr_table_add(r->subprocess_env, "PATH_INFO", url + w_len - delta);
|
||||
+ apr_table_add(r->subprocess_env, "PATH_INFO", u_path_info);
|
||||
|
||||
|
||||
/* Create space for state information */
|
|
@ -0,0 +1,21 @@
|
|||
diff --git a/server/util.c b/server/util.c
|
||||
index e0c558c..2a5dd04 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -2460,13 +2460,12 @@ AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
|
||||
* in front of every " that doesn't already have one.
|
||||
*/
|
||||
while (*inchr != '\0') {
|
||||
- if ((*inchr == '\\') && (inchr[1] != '\0')) {
|
||||
- *outchr++ = *inchr++;
|
||||
- *outchr++ = *inchr++;
|
||||
- }
|
||||
if (*inchr == '"') {
|
||||
*outchr++ = '\\';
|
||||
}
|
||||
+ if ((*inchr == '\\') && (inchr[1] != '\0')) {
|
||||
+ *outchr++ = *inchr++;
|
||||
+ }
|
||||
if (*inchr != '\0') {
|
||||
*outchr++ = *inchr++;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
|
||||
index fb897a9..38dbb24 100644
|
||||
--- a/modules/mappers/mod_rewrite.c
|
||||
+++ b/modules/mappers/mod_rewrite.c
|
||||
@@ -619,6 +619,13 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
|
||||
return 6;
|
||||
}
|
||||
break;
|
||||
+
|
||||
+ case 'u':
|
||||
+ case 'U':
|
||||
+ if (!ap_cstr_casecmpn(uri, "nix:", 4)) { /* unix: */
|
||||
+ *sqs = 1;
|
||||
+ return (uri[4] == '/' && uri[5] == '/') ? 7 : 5;
|
||||
+ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
|
||||
index f383996..6a9ef55 100644
|
||||
--- a/modules/proxy/mod_proxy.c
|
||||
+++ b/modules/proxy/mod_proxy.c
|
||||
@@ -1717,7 +1717,8 @@ PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url)
|
||||
* the UDS path... ignore it
|
||||
*/
|
||||
if (!strncasecmp(url, "unix:", 5) &&
|
||||
- ((ptr = ap_strchr_c(url, '|')) != NULL)) {
|
||||
+ ((ptr = ap_strchr_c(url + 5, '|')) != NULL)) {
|
||||
+
|
||||
/* move past the 'unix:...|' UDS path info */
|
||||
const char *ret, *c;
|
||||
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 7714b6c..3dd570c 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -2084,33 +2084,45 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke
|
||||
* were passed a UDS url (eg: from mod_proxy) and adjust uds_path
|
||||
* as required.
|
||||
*/
|
||||
-static void fix_uds_filename(request_rec *r, char **url)
|
||||
+static int fix_uds_filename(request_rec *r, char **url)
|
||||
{
|
||||
- char *ptr, *ptr2;
|
||||
- if (!r || !r->filename) return;
|
||||
+ char *uds_url = r->filename + 6, *origin_url;
|
||||
|
||||
if (!strncmp(r->filename, "proxy:", 6) &&
|
||||
- (ptr2 = ap_strcasestr(r->filename, "unix:")) &&
|
||||
- (ptr = ap_strchr(ptr2, '|'))) {
|
||||
+ !ap_cstr_casecmpn(uds_url, "unix:", 5) &&
|
||||
+ (origin_url = ap_strchr(uds_url + 5, '|'))) {
|
||||
+ char *uds_path = NULL;
|
||||
+ apr_size_t url_len;
|
||||
apr_uri_t urisock;
|
||||
apr_status_t rv;
|
||||
- *ptr = '\0';
|
||||
- rv = apr_uri_parse(r->pool, ptr2, &urisock);
|
||||
- if (rv == APR_SUCCESS) {
|
||||
- char *rurl = ptr+1;
|
||||
- char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path);
|
||||
- apr_table_setn(r->notes, "uds_path", sockpath);
|
||||
- *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */
|
||||
- /* r->filename starts w/ "proxy:", so add after that */
|
||||
- memmove(r->filename+6, rurl, strlen(rurl)+1);
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
- "*: rewrite of url due to UDS(%s): %s (%s)",
|
||||
- sockpath, *url, r->filename);
|
||||
- }
|
||||
- else {
|
||||
- *ptr = '|';
|
||||
- }
|
||||
- }
|
||||
+
|
||||
+ *origin_url = '\0';
|
||||
+ rv = apr_uri_parse(r->pool, uds_url, &urisock);
|
||||
+ *origin_url++ = '|';
|
||||
+
|
||||
+ if (rv == APR_SUCCESS && urisock.path && (!urisock.hostname
|
||||
+ || !urisock.hostname[0])) {
|
||||
+ uds_path = ap_runtime_dir_relative(r->pool, urisock.path);
|
||||
+ }
|
||||
+
|
||||
+ if (!uds_path) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10292)
|
||||
+ "Invalid proxy UDS filename (%s)", r->filename);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ apr_table_setn(r->notes, "uds_path", uds_path);
|
||||
+
|
||||
+ /* Remove the UDS path from *url and r->filename */
|
||||
+ url_len = strlen(origin_url);
|
||||
+ *url = apr_pstrmemdup(r->pool, origin_url, url_len);
|
||||
+ memcpy(uds_url, *url, url_len + 1);
|
||||
+
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
+ "*: rewrite of url due to UDS(%s): %s (%s)",
|
||||
+ uds_path, *url, r->filename);
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
@@ -2128,7 +2140,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
"%s: found worker %s for %s",
|
||||
(*worker)->s->scheme, (*worker)->s->name, *url);
|
||||
*balancer = NULL;
|
||||
- fix_uds_filename(r, url);
|
||||
+ if (!fix_uds_filename(r, url)) {
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
access_status = OK;
|
||||
}
|
||||
else if (r->proxyreq == PROXYREQ_PROXY) {
|
||||
@@ -2159,7 +2173,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
* regarding the Connection header in the request.
|
||||
*/
|
||||
apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1");
|
||||
- fix_uds_filename(r, url);
|
||||
+ if (!fix_uds_filename(r, url)) {
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,315 @@
|
|||
diff --git a/include/http_protocol.h b/include/http_protocol.h
|
||||
index e7abdd9..e1572dc 100644
|
||||
--- a/include/http_protocol.h
|
||||
+++ b/include/http_protocol.h
|
||||
@@ -96,6 +96,13 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec *r);
|
||||
AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r,
|
||||
apr_bucket_brigade *bb);
|
||||
|
||||
+/**
|
||||
+ * Run post_read_request hook and validate.
|
||||
+ * @param r The current request
|
||||
+ * @return OK or HTTP_...
|
||||
+ */
|
||||
+AP_DECLARE(int) ap_post_read_request(request_rec *r);
|
||||
+
|
||||
/* Finish up stuff after a request */
|
||||
|
||||
/**
|
||||
diff --git a/modules/http/http_request.c b/modules/http/http_request.c
|
||||
index 9e7c4db..e873aab 100644
|
||||
--- a/modules/http/http_request.c
|
||||
+++ b/modules/http/http_request.c
|
||||
@@ -681,7 +681,7 @@ static request_rec *internal_internal_redirect(const char *new_uri,
|
||||
* to do their thing on internal redirects as well. Perhaps this is a
|
||||
* misnamed function.
|
||||
*/
|
||||
- if ((access_status = ap_run_post_read_request(new))) {
|
||||
+ if ((access_status = ap_post_read_request(new))) {
|
||||
ap_die(access_status, new);
|
||||
return NULL;
|
||||
}
|
||||
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
|
||||
index 6a9ef55..a6df1b8 100644
|
||||
--- a/modules/proxy/mod_proxy.c
|
||||
+++ b/modules/proxy/mod_proxy.c
|
||||
@@ -584,11 +584,12 @@ static int proxy_detect(request_rec *r)
|
||||
|
||||
if (conf->req && r->parsed_uri.scheme) {
|
||||
/* but it might be something vhosted */
|
||||
- if (!(r->parsed_uri.hostname
|
||||
- && !strcasecmp(r->parsed_uri.scheme, ap_http_scheme(r))
|
||||
- && ap_matches_request_vhost(r, r->parsed_uri.hostname,
|
||||
- (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port
|
||||
- : ap_default_port(r))))) {
|
||||
+ if (!r->parsed_uri.hostname
|
||||
+ || ap_cstr_casecmp(r->parsed_uri.scheme, ap_http_scheme(r)) != 0
|
||||
+ || !ap_matches_request_vhost(r, r->parsed_uri.hostname,
|
||||
+ (apr_port_t)(r->parsed_uri.port_str
|
||||
+ ? r->parsed_uri.port
|
||||
+ : ap_default_port(r)))) {
|
||||
r->proxyreq = PROXYREQ_PROXY;
|
||||
r->uri = r->unparsed_uri;
|
||||
r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
|
||||
@@ -1750,6 +1751,7 @@ static const char *
|
||||
struct proxy_alias *new;
|
||||
char *f = cmd->path;
|
||||
char *r = NULL;
|
||||
+ const char *real;
|
||||
char *word;
|
||||
apr_table_t *params = apr_table_make(cmd->pool, 5);
|
||||
const apr_array_header_t *arr;
|
||||
@@ -1815,6 +1817,10 @@ static const char *
|
||||
if (r == NULL) {
|
||||
return "ProxyPass|ProxyPassMatch needs a path when not defined in a location";
|
||||
}
|
||||
+ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, r))) {
|
||||
+ return "ProxyPass|ProxyPassMatch uses an invalid \"unix:\" URL";
|
||||
+ }
|
||||
+
|
||||
|
||||
/* if per directory, save away the single alias */
|
||||
if (cmd->path) {
|
||||
@@ -1831,7 +1837,7 @@ static const char *
|
||||
}
|
||||
|
||||
new->fake = apr_pstrdup(cmd->pool, f);
|
||||
- new->real = apr_pstrdup(cmd->pool, ap_proxy_de_socketfy(cmd->pool, r));
|
||||
+ new->real = apr_pstrdup(cmd->pool, real);
|
||||
new->flags = flags;
|
||||
if (use_regex) {
|
||||
new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED);
|
||||
@@ -2316,6 +2322,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
|
||||
proxy_worker *worker;
|
||||
char *path = cmd->path;
|
||||
char *name = NULL;
|
||||
+ const char *real;
|
||||
char *word;
|
||||
apr_table_t *params = apr_table_make(cmd->pool, 5);
|
||||
const apr_array_header_t *arr;
|
||||
@@ -2356,6 +2363,9 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
|
||||
return "BalancerMember must define balancer name when outside <Proxy > section";
|
||||
if (!name)
|
||||
return "BalancerMember must define remote proxy server";
|
||||
+ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, name))) {
|
||||
+ return "BalancerMember uses an invalid \"unix:\" URL";
|
||||
+ }
|
||||
|
||||
ap_str_tolower(path); /* lowercase scheme://hostname */
|
||||
|
||||
@@ -2368,7 +2378,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
|
||||
}
|
||||
|
||||
/* Try to find existing worker */
|
||||
- worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
|
||||
+ worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, real);
|
||||
if (!worker) {
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147)
|
||||
"Defining worker '%s' for balancer '%s'",
|
||||
@@ -2457,7 +2467,13 @@ static const char *
|
||||
}
|
||||
}
|
||||
else {
|
||||
- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
|
||||
+ const char *real;
|
||||
+
|
||||
+ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, name))) {
|
||||
+ return "ProxySet uses an invalid \"unix:\" URL";
|
||||
+ }
|
||||
+
|
||||
+ worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, real);
|
||||
if (!worker) {
|
||||
if (in_proxy_section) {
|
||||
err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
|
||||
@@ -2599,8 +2615,14 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg)
|
||||
}
|
||||
}
|
||||
else {
|
||||
+ const char *real;
|
||||
+
|
||||
+ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, conf->p))) {
|
||||
+ return "<Proxy/ProxyMatch > uses an invalid \"unix:\" URL";
|
||||
+ }
|
||||
+
|
||||
worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf,
|
||||
- ap_proxy_de_socketfy(cmd->temp_pool, (char*)conf->p));
|
||||
+ real);
|
||||
if (!worker) {
|
||||
err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
|
||||
sconf, conf->p, 0);
|
||||
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
|
||||
index fbbd508..dca6f69 100644
|
||||
--- a/modules/proxy/mod_proxy.h
|
||||
+++ b/modules/proxy/mod_proxy.h
|
||||
@@ -713,6 +713,8 @@ typedef __declspec(dllimport) const char *
|
||||
proxy_dir_conf *, const char *);
|
||||
#endif
|
||||
|
||||
+#define AP_PROXY_WORKER_NO_UDS (1u << 3)
|
||||
+
|
||||
|
||||
/* Connection pool API */
|
||||
/**
|
||||
@@ -725,6 +727,24 @@ typedef __declspec(dllimport) const char *
|
||||
PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p,
|
||||
proxy_worker *worker);
|
||||
|
||||
+
|
||||
+/**
|
||||
+ * Get the worker from proxy configuration, looking for either PREFIXED or
|
||||
+ * MATCHED or both types of workers according to given mask
|
||||
+ * @param p memory pool used for finding worker
|
||||
+ * @param balancer the balancer that the worker belongs to
|
||||
+ * @param conf current proxy server configuration
|
||||
+ * @param url url to find the worker from
|
||||
+ * @param mask bitmask of AP_PROXY_WORKER_IS_*
|
||||
+ * @return proxy_worker or NULL if not found
|
||||
+ */
|
||||
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p,
|
||||
+ proxy_balancer *balancer,
|
||||
+ proxy_server_conf *conf,
|
||||
+ const char *url,
|
||||
+ unsigned int mask);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* Get the worker from proxy configuration
|
||||
* @param p memory pool used for finding worker
|
||||
@@ -737,6 +757,8 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
proxy_balancer *balancer,
|
||||
proxy_server_conf *conf,
|
||||
const char *url);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* Define and Allocate space for the worker to proxy configuration
|
||||
* @param p memory pool to allocate worker from
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index 032e0c4..3d5b220 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -1643,10 +1643,11 @@ PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p,
|
||||
return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL);
|
||||
}
|
||||
|
||||
-PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
- proxy_balancer *balancer,
|
||||
- proxy_server_conf *conf,
|
||||
- const char *url)
|
||||
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p,
|
||||
+ proxy_balancer *balancer,
|
||||
+ proxy_server_conf *conf,
|
||||
+ const char *url,
|
||||
+ unsigned int mask)
|
||||
{
|
||||
proxy_worker *worker;
|
||||
proxy_worker *max_worker = NULL;
|
||||
@@ -1662,7 +1663,12 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- url = ap_proxy_de_socketfy(p, url);
|
||||
+ if (!(mask & AP_PROXY_WORKER_NO_UDS)) {
|
||||
+ url = ap_proxy_de_socketfy(p, url);
|
||||
+ if (!url) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
c = ap_strchr_c(url, ':');
|
||||
if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
|
||||
@@ -1727,6 +1733,14 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
return max_worker;
|
||||
}
|
||||
|
||||
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
|
||||
+ proxy_balancer *balancer,
|
||||
+ proxy_server_conf *conf,
|
||||
+ const char *url)
|
||||
+{
|
||||
+ return ap_proxy_get_worker_ex(p, balancer, conf, url, 0);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* To create a worker from scratch first we define the
|
||||
* specifics of the worker; this is all local data.
|
||||
@@ -2134,22 +2148,22 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
|
||||
access_status = proxy_run_pre_request(worker, balancer, r, conf, url);
|
||||
if (access_status == DECLINED && *balancer == NULL) {
|
||||
- *worker = ap_proxy_get_worker(r->pool, NULL, conf, *url);
|
||||
+ const int forward = (r->proxyreq == PROXYREQ_PROXY);
|
||||
+ *worker = ap_proxy_get_worker_ex(r->pool, NULL, conf, *url,
|
||||
+ forward ? AP_PROXY_WORKER_NO_UDS : 0);
|
||||
if (*worker) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
"%s: found worker %s for %s",
|
||||
(*worker)->s->scheme, (*worker)->s->name, *url);
|
||||
- *balancer = NULL;
|
||||
- if (!fix_uds_filename(r, url)) {
|
||||
+ if (!forward && !fix_uds_filename(r, url)) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
access_status = OK;
|
||||
}
|
||||
- else if (r->proxyreq == PROXYREQ_PROXY) {
|
||||
+ else if (forward) {
|
||||
if (conf->forward) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
"*: found forward proxy worker for %s", *url);
|
||||
- *balancer = NULL;
|
||||
*worker = conf->forward;
|
||||
access_status = OK;
|
||||
/*
|
||||
@@ -2163,8 +2177,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
|
||||
else if (r->proxyreq == PROXYREQ_REVERSE) {
|
||||
if (conf->reverse) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
||||
- "*: using default reverse proxy worker for %s (no keepalive)", *url);
|
||||
- *balancer = NULL;
|
||||
+ "*: using default reverse proxy worker for %s "
|
||||
+ "(no keepalive)", *url);
|
||||
*worker = conf->reverse;
|
||||
access_status = OK;
|
||||
/*
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index 430d91e..a2aa081 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -1525,7 +1525,7 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
/* we may have switched to another server */
|
||||
apply_server_config(r);
|
||||
|
||||
- if ((access_status = ap_run_post_read_request(r))) {
|
||||
+ if ((access_status = ap_post_read_request(r))) {
|
||||
goto die;
|
||||
}
|
||||
|
||||
@@ -1582,6 +1582,27 @@ ignore:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+AP_DECLARE(int) ap_post_read_request(request_rec *r)
|
||||
+{
|
||||
+ int status;
|
||||
+
|
||||
+ if ((status = ap_run_post_read_request(r))) {
|
||||
+ return status;
|
||||
+ }
|
||||
+
|
||||
+ /* Enforce http(s) only scheme for non-forward-proxy requests */
|
||||
+ if (!r->proxyreq
|
||||
+ && r->parsed_uri.scheme
|
||||
+ && (ap_cstr_casecmpn(r->parsed_uri.scheme, "http", 4) != 0
|
||||
+ || (r->parsed_uri.scheme[4] != '\0'
|
||||
+ && (apr_tolower(r->parsed_uri.scheme[4]) != 's'
|
||||
+ || r->parsed_uri.scheme[5] != '\0')))) {
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
+ }
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
/* if a request with a body creates a subrequest, remove original request's
|
||||
* input headers which pertain to the body which has already been read.
|
||||
* out-of-line helper function for ap_set_sub_req_protocol.
|
|
@ -0,0 +1,12 @@
|
|||
diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c
|
||||
index 77a88b4..1d8be2e 100644
|
||||
--- a/modules/lua/lua_request.c
|
||||
+++ b/modules/lua/lua_request.c
|
||||
@@ -376,6 +376,7 @@ static int req_parsebody(lua_State *L)
|
||||
if (end == NULL) break;
|
||||
key = (char *) apr_pcalloc(r->pool, 256);
|
||||
filename = (char *) apr_pcalloc(r->pool, 256);
|
||||
+ if (end - crlf <= 8) break;
|
||||
vlen = end - crlf - 8;
|
||||
buffer = (char *) apr_pcalloc(r->pool, vlen+1);
|
||||
memcpy(buffer, crlf + 4, vlen);
|
|
@ -0,0 +1,70 @@
|
|||
--- a/modules/lua/lua_request.c 2022/03/07 14:48:54 1898693
|
||||
+++ b/modules/lua/lua_request.c 2022/03/07 14:51:19 1898694
|
||||
@@ -235,14 +235,16 @@
|
||||
{
|
||||
int rc = OK;
|
||||
|
||||
+ *rbuf = NULL;
|
||||
+ *size = 0;
|
||||
+
|
||||
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
|
||||
return (rc);
|
||||
}
|
||||
if (ap_should_client_block(r)) {
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
- char argsbuffer[HUGE_STRING_LEN];
|
||||
- apr_off_t rsize, len_read, rpos = 0;
|
||||
+ apr_off_t len_read, rpos = 0;
|
||||
apr_off_t length = r->remaining;
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
@@ -250,18 +252,18 @@
|
||||
return APR_EINCOMPLETE; /* Only room for incomplete data chunk :( */
|
||||
}
|
||||
*rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1));
|
||||
- *size = length;
|
||||
- while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) {
|
||||
- if ((rpos + len_read) > length) {
|
||||
- rsize = length - rpos;
|
||||
- }
|
||||
- else {
|
||||
- rsize = len_read;
|
||||
- }
|
||||
-
|
||||
- memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize);
|
||||
- rpos += rsize;
|
||||
+ while ((rpos < length)
|
||||
+ && (len_read = ap_get_client_block(r, (char *) *rbuf + rpos,
|
||||
+ length - rpos)) > 0) {
|
||||
+ rpos += len_read;
|
||||
}
|
||||
+ if (len_read < 0) {
|
||||
+ return APR_EINCOMPLETE;
|
||||
+ }
|
||||
+ *size = rpos;
|
||||
+ }
|
||||
+ else {
|
||||
+ rc = DONE;
|
||||
}
|
||||
|
||||
return (rc);
|
||||
@@ -278,6 +280,8 @@
|
||||
{
|
||||
apr_status_t rc = OK;
|
||||
|
||||
+ *size = 0;
|
||||
+
|
||||
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
|
||||
return rc;
|
||||
if (ap_should_client_block(r)) {
|
||||
@@ -303,6 +307,9 @@
|
||||
rpos += rsize;
|
||||
}
|
||||
}
|
||||
+ else {
|
||||
+ rc = DONE;
|
||||
+ }
|
||||
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
|
||||
index 9828cdf..6bedcac 100644
|
||||
--- a/modules/http/http_filters.c
|
||||
+++ b/modules/http/http_filters.c
|
||||
@@ -1605,9 +1605,9 @@ AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status)
|
||||
*/
|
||||
AP_DECLARE(int) ap_discard_request_body(request_rec *r)
|
||||
{
|
||||
+ int rc = OK;
|
||||
+ conn_rec *c = r->connection;
|
||||
apr_bucket_brigade *bb;
|
||||
- int seen_eos;
|
||||
- apr_status_t rv;
|
||||
|
||||
/* Sometimes we'll get in a state where the input handling has
|
||||
* detected an error where we want to drop the connection, so if
|
||||
@@ -1616,54 +1616,57 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r)
|
||||
*
|
||||
* This function is also a no-op on a subrequest.
|
||||
*/
|
||||
- if (r->main || r->connection->keepalive == AP_CONN_CLOSE ||
|
||||
- ap_status_drops_connection(r->status)) {
|
||||
+ if (r->main || c->keepalive == AP_CONN_CLOSE) {
|
||||
+ return OK;
|
||||
+ }
|
||||
+ if (ap_status_drops_connection(r->status)) {
|
||||
+ c->keepalive = AP_CONN_CLOSE;
|
||||
return OK;
|
||||
}
|
||||
|
||||
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
- seen_eos = 0;
|
||||
- do {
|
||||
- apr_bucket *bucket;
|
||||
+ for (;;) {
|
||||
+ apr_status_t rv;
|
||||
|
||||
rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
|
||||
APR_BLOCK_READ, HUGE_STRING_LEN);
|
||||
-
|
||||
if (rv != APR_SUCCESS) {
|
||||
- apr_brigade_destroy(bb);
|
||||
- return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
|
||||
+ rc = ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
|
||||
+ goto cleanup;
|
||||
}
|
||||
|
||||
- for (bucket = APR_BRIGADE_FIRST(bb);
|
||||
- bucket != APR_BRIGADE_SENTINEL(bb);
|
||||
- bucket = APR_BUCKET_NEXT(bucket))
|
||||
- {
|
||||
- const char *data;
|
||||
- apr_size_t len;
|
||||
+ while (!APR_BRIGADE_EMPTY(bb)) {
|
||||
+ apr_bucket *b = APR_BRIGADE_FIRST(bb);
|
||||
|
||||
- if (APR_BUCKET_IS_EOS(bucket)) {
|
||||
- seen_eos = 1;
|
||||
- break;
|
||||
+ if (APR_BUCKET_IS_EOS(b)) {
|
||||
+ goto cleanup;
|
||||
}
|
||||
|
||||
- /* These are metadata buckets. */
|
||||
- if (bucket->length == 0) {
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- /* We MUST read because in case we have an unknown-length
|
||||
- * bucket or one that morphs, we want to exhaust it.
|
||||
+ /* There is no need to read empty or metadata buckets or
|
||||
+ * buckets of known length, but we MUST read buckets of
|
||||
+ * unknown length in order to exhaust them.
|
||||
*/
|
||||
- rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
|
||||
+ if (b->length == (apr_size_t)-1) {
|
||||
+ apr_size_t len;
|
||||
+ const char *data;
|
||||
+
|
||||
+ rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
|
||||
if (rv != APR_SUCCESS) {
|
||||
- apr_brigade_destroy(bb);
|
||||
- return HTTP_BAD_REQUEST;
|
||||
+ rc = HTTP_BAD_REQUEST;
|
||||
+ goto cleanup;
|
||||
}
|
||||
}
|
||||
- apr_brigade_cleanup(bb);
|
||||
- } while (!seen_eos);
|
||||
|
||||
- return OK;
|
||||
+ apr_bucket_delete(b);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+cleanup:
|
||||
+ apr_brigade_cleanup(bb);
|
||||
+ if (rc != OK) {
|
||||
+ c->keepalive = AP_CONN_CLOSE;
|
||||
+ }
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/* Here we deal with getting the request message body from the client.
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index a2aa081..a554970 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -1666,23 +1666,29 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew,
|
||||
rnew->main = (request_rec *) r;
|
||||
}
|
||||
|
||||
-static void end_output_stream(request_rec *r)
|
||||
+static void end_output_stream(request_rec *r, int status)
|
||||
{
|
||||
conn_rec *c = r->connection;
|
||||
apr_bucket_brigade *bb;
|
||||
apr_bucket *b;
|
||||
|
||||
bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
+ if (status != OK) {
|
||||
+ b = ap_bucket_error_create(status, NULL, r->pool, c->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
+ }
|
||||
b = apr_bucket_eos_create(c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
+
|
||||
ap_pass_brigade(r->output_filters, bb);
|
||||
+ apr_brigade_cleanup(bb);
|
||||
}
|
||||
|
||||
AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub)
|
||||
{
|
||||
/* tell the filter chain there is no more content coming */
|
||||
if (!sub->eos_sent) {
|
||||
- end_output_stream(sub);
|
||||
+ end_output_stream(sub, OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1693,11 +1699,11 @@ AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub)
|
||||
*/
|
||||
AP_DECLARE(void) ap_finalize_request_protocol(request_rec *r)
|
||||
{
|
||||
- (void) ap_discard_request_body(r);
|
||||
+ int status = ap_discard_request_body(r);
|
||||
|
||||
/* tell the filter chain there is no more content coming */
|
||||
if (!r->eos_sent) {
|
||||
- end_output_stream(r);
|
||||
+ end_output_stream(r, status);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
|
||||
index 20d1e5a..e1ec8d0 100644
|
||||
--- a/docs/manual/mod/core.html.en
|
||||
+++ b/docs/manual/mod/core.html.en
|
||||
@@ -2935,12 +2935,19 @@ from the client</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
|
||||
</table>
|
||||
- <p>Limit (in bytes) on maximum size of an XML-based request
|
||||
- body. A value of <code>0</code> will disable any checking.</p>
|
||||
+ <p>Limit (in bytes) on the maximum size of an XML-based request
|
||||
+ body. A value of <code>0</code> will apply a hard limit (depending on
|
||||
+ 32bit vs 64bit system) allowing for XML escaping within the bounds of
|
||||
+ the system addressable memory, but it exists for compatibility only
|
||||
+ and is not recommended since it does not account for memory consumed
|
||||
+ elsewhere or concurrent requests, which might result in an overall
|
||||
+ system out-of-memory.
|
||||
+ </p>
|
||||
|
||||
<p>Example:</p>
|
||||
|
||||
- <pre class="prettyprint lang-config">LimitXMLRequestBody 0</pre>
|
||||
+ <pre class="prettyprint lang-config"># Limit of 1 MiB
|
||||
+ LimitXMLRequestBody 1073741824</pre>
|
||||
|
||||
|
||||
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index e32613d..8abfa65 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -70,6 +70,8 @@
|
||||
/* LimitXMLRequestBody handling */
|
||||
#define AP_LIMIT_UNSET ((long) -1)
|
||||
#define AP_DEFAULT_LIMIT_XML_BODY ((apr_size_t)1000000)
|
||||
+/* Hard limit for ap_escape_html2() */
|
||||
+#define AP_MAX_LIMIT_XML_BODY ((apr_size_t)(APR_SIZE_MAX / 6 - 1))
|
||||
|
||||
#define AP_MIN_SENDFILE_BYTES (256)
|
||||
|
||||
@@ -3689,6 +3691,11 @@ static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
|
||||
if (conf->limit_xml_body < 0)
|
||||
return "LimitXMLRequestBody requires a non-negative integer.";
|
||||
|
||||
+ /* zero is AP_MAX_LIMIT_XML_BODY (implicitly) */
|
||||
+ if ((apr_size_t)conf->limit_xml_body > AP_MAX_LIMIT_XML_BODY)
|
||||
+ return apr_psprintf(cmd->pool, "LimitXMLRequestBody must not exceed "
|
||||
+ "%" APR_SIZE_T_FMT, AP_MAX_LIMIT_XML_BODY);
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3777,6 +3784,8 @@ AP_DECLARE(apr_size_t) ap_get_limit_xml_body(const request_rec *r)
|
||||
conf = ap_get_core_module_config(r->per_dir_config);
|
||||
if (conf->limit_xml_body == AP_LIMIT_UNSET)
|
||||
return AP_DEFAULT_LIMIT_XML_BODY;
|
||||
+ if (conf->limit_xml_body == 0)
|
||||
+ return AP_MAX_LIMIT_XML_BODY;
|
||||
|
||||
return (apr_size_t)conf->limit_xml_body;
|
||||
}
|
||||
diff --git a/server/util.c b/server/util.c
|
||||
index 2a5dd04..eefdafa 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -2037,11 +2037,14 @@ AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
|
||||
|
||||
AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
|
||||
{
|
||||
- int i, j;
|
||||
+ apr_size_t i, j;
|
||||
char *x;
|
||||
|
||||
/* first, count the number of extra characters */
|
||||
- for (i = 0, j = 0; s[i] != '\0'; i++)
|
||||
+ for (i = 0, j = 0; s[i] != '\0'; i++) {
|
||||
+ if (i + j > APR_SIZE_MAX - 6) {
|
||||
+ abort();
|
||||
+ }
|
||||
if (s[i] == '<' || s[i] == '>')
|
||||
j += 3;
|
||||
else if (s[i] == '&')
|
||||
@@ -2050,6 +2053,7 @@ AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
|
||||
j += 5;
|
||||
else if (toasc && !apr_isascii(s[i]))
|
||||
j += 5;
|
||||
+ }
|
||||
|
||||
if (j == 0)
|
||||
return apr_pstrmemdup(p, s, i);
|
||||
diff --git a/server/util_xml.c b/server/util_xml.c
|
||||
index 4845194..22806fa 100644
|
||||
--- a/server/util_xml.c
|
||||
+++ b/server/util_xml.c
|
||||
@@ -85,7 +85,7 @@ AP_DECLARE(int) ap_xml_parse_input(request_rec * r, apr_xml_doc **pdoc)
|
||||
}
|
||||
|
||||
total_read += len;
|
||||
- if (limit_xml_body && total_read > limit_xml_body) {
|
||||
+ if (total_read > limit_xml_body) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00539)
|
||||
"XML request body is larger than the configured "
|
||||
"limit of %lu", (unsigned long)limit_xml_body);
|
|
@ -0,0 +1,377 @@
|
|||
diff --git a/modules/filters/libsed.h b/modules/filters/libsed.h
|
||||
index 76cbc0c..0256b1e 100644
|
||||
--- a/modules/filters/libsed.h
|
||||
+++ b/modules/filters/libsed.h
|
||||
@@ -60,7 +60,7 @@ struct sed_label_s {
|
||||
};
|
||||
|
||||
typedef apr_status_t (sed_err_fn_t)(void *data, const char *error);
|
||||
-typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, int sz);
|
||||
+typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, apr_size_t sz);
|
||||
|
||||
typedef struct sed_commands_s sed_commands_t;
|
||||
#define NWFILES 11 /* 10 plus one for standard output */
|
||||
@@ -69,7 +69,7 @@ struct sed_commands_s {
|
||||
sed_err_fn_t *errfn;
|
||||
void *data;
|
||||
|
||||
- unsigned lsize;
|
||||
+ apr_size_t lsize;
|
||||
char *linebuf;
|
||||
char *lbend;
|
||||
const char *saveq;
|
||||
@@ -116,15 +116,15 @@ struct sed_eval_s {
|
||||
apr_int64_t lnum;
|
||||
void *fout;
|
||||
|
||||
- unsigned lsize;
|
||||
+ apr_size_t lsize;
|
||||
char *linebuf;
|
||||
char *lspend;
|
||||
|
||||
- unsigned hsize;
|
||||
+ apr_size_t hsize;
|
||||
char *holdbuf;
|
||||
char *hspend;
|
||||
|
||||
- unsigned gsize;
|
||||
+ apr_size_t gsize;
|
||||
char *genbuf;
|
||||
char *lcomend;
|
||||
|
||||
@@ -160,7 +160,7 @@ apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands,
|
||||
sed_err_fn_t *errfn, void *data,
|
||||
sed_write_fn_t *writefn, apr_pool_t *p);
|
||||
apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data);
|
||||
-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout);
|
||||
+apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout);
|
||||
apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout);
|
||||
apr_status_t sed_finalize_eval(sed_eval_t *eval, void *f);
|
||||
void sed_destroy_eval(sed_eval_t *eval);
|
||||
diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c
|
||||
index 346c210..8595e41 100644
|
||||
--- a/modules/filters/mod_sed.c
|
||||
+++ b/modules/filters/mod_sed.c
|
||||
@@ -51,7 +51,7 @@ typedef struct sed_filter_ctxt
|
||||
apr_bucket_brigade *bbinp;
|
||||
char *outbuf;
|
||||
char *curoutbuf;
|
||||
- int bufsize;
|
||||
+ apr_size_t bufsize;
|
||||
apr_pool_t *tpool;
|
||||
int numbuckets;
|
||||
} sed_filter_ctxt;
|
||||
@@ -100,7 +100,7 @@ static void alloc_outbuf(sed_filter_ctxt* ctx)
|
||||
/* append_bucket
|
||||
* Allocate a new bucket from buf and sz and append to ctx->bb
|
||||
*/
|
||||
-static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
|
||||
+static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, apr_size_t sz)
|
||||
{
|
||||
apr_status_t status = APR_SUCCESS;
|
||||
apr_bucket *b;
|
||||
@@ -133,7 +133,7 @@ static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
|
||||
*/
|
||||
static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx)
|
||||
{
|
||||
- int size = ctx->curoutbuf - ctx->outbuf;
|
||||
+ apr_size_t size = ctx->curoutbuf - ctx->outbuf;
|
||||
char *out;
|
||||
apr_status_t status = APR_SUCCESS;
|
||||
if ((ctx->outbuf == NULL) || (size <=0))
|
||||
@@ -147,12 +147,12 @@ static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx)
|
||||
/* This is a call back function. When libsed wants to generate the output,
|
||||
* this function will be invoked.
|
||||
*/
|
||||
-static apr_status_t sed_write_output(void *dummy, char *buf, int sz)
|
||||
+static apr_status_t sed_write_output(void *dummy, char *buf, apr_size_t sz)
|
||||
{
|
||||
/* dummy is basically filter context. Context is passed during invocation
|
||||
* of sed_eval_buffer
|
||||
*/
|
||||
- int remainbytes = 0;
|
||||
+ apr_size_t remainbytes = 0;
|
||||
apr_status_t status = APR_SUCCESS;
|
||||
sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy;
|
||||
if (ctx->outbuf == NULL) {
|
||||
@@ -168,21 +168,29 @@ static apr_status_t sed_write_output(void *dummy, char *buf, int sz)
|
||||
}
|
||||
/* buffer is now full */
|
||||
status = append_bucket(ctx, ctx->outbuf, ctx->bufsize);
|
||||
- /* old buffer is now used so allocate new buffer */
|
||||
- alloc_outbuf(ctx);
|
||||
- /* if size is bigger than the allocated buffer directly add to output
|
||||
- * brigade */
|
||||
- if ((status == APR_SUCCESS) && (sz >= ctx->bufsize)) {
|
||||
- char* newbuf = apr_pmemdup(ctx->tpool, buf, sz);
|
||||
- status = append_bucket(ctx, newbuf, sz);
|
||||
- /* pool might get clear after append_bucket */
|
||||
- if (ctx->outbuf == NULL) {
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ /* if size is bigger than the allocated buffer directly add to output
|
||||
+ * brigade */
|
||||
+ if (sz >= ctx->bufsize) {
|
||||
+ char* newbuf = apr_pmemdup(ctx->tpool, buf, sz);
|
||||
+ status = append_bucket(ctx, newbuf, sz);
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ /* old buffer is now used so allocate new buffer */
|
||||
+ alloc_outbuf(ctx);
|
||||
+ }
|
||||
+ else {
|
||||
+ clear_ctxpool(ctx);
|
||||
+ }
|
||||
+ }
|
||||
+ else {
|
||||
+ /* old buffer is now used so allocate new buffer */
|
||||
alloc_outbuf(ctx);
|
||||
+ memcpy(ctx->curoutbuf, buf, sz);
|
||||
+ ctx->curoutbuf += sz;
|
||||
}
|
||||
}
|
||||
else {
|
||||
- memcpy(ctx->curoutbuf, buf, sz);
|
||||
- ctx->curoutbuf += sz;
|
||||
+ clear_ctxpool(ctx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c
|
||||
index be03506..67a8d06 100644
|
||||
--- a/modules/filters/sed1.c
|
||||
+++ b/modules/filters/sed1.c
|
||||
@@ -71,7 +71,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2);
|
||||
static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
step_vars_storage *step_vars);
|
||||
-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz);
|
||||
+static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz);
|
||||
static apr_status_t arout(sed_eval_t *eval);
|
||||
|
||||
static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
|
||||
@@ -92,11 +92,11 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
|
||||
* grow_buffer
|
||||
*/
|
||||
static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
- char **spend, unsigned int *cursize,
|
||||
- unsigned int newsize)
|
||||
+ char **spend, apr_size_t *cursize,
|
||||
+ apr_size_t newsize)
|
||||
{
|
||||
char* newbuffer = NULL;
|
||||
- int spendsize = 0;
|
||||
+ apr_size_t spendsize = 0;
|
||||
if (*cursize >= newsize)
|
||||
return;
|
||||
/* Avoid number of times realloc is called. It could cause huge memory
|
||||
@@ -124,7 +124,7 @@ static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
/*
|
||||
* grow_line_buffer
|
||||
*/
|
||||
-static void grow_line_buffer(sed_eval_t *eval, int newsize)
|
||||
+static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
{
|
||||
grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
|
||||
&eval->lsize, newsize);
|
||||
@@ -133,7 +133,7 @@ static void grow_line_buffer(sed_eval_t *eval, int newsize)
|
||||
/*
|
||||
* grow_hold_buffer
|
||||
*/
|
||||
-static void grow_hold_buffer(sed_eval_t *eval, int newsize)
|
||||
+static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
{
|
||||
grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
|
||||
&eval->hsize, newsize);
|
||||
@@ -142,7 +142,7 @@ static void grow_hold_buffer(sed_eval_t *eval, int newsize)
|
||||
/*
|
||||
* grow_gen_buffer
|
||||
*/
|
||||
-static void grow_gen_buffer(sed_eval_t *eval, int newsize,
|
||||
+static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize,
|
||||
char **gspend)
|
||||
{
|
||||
if (gspend == NULL) {
|
||||
@@ -156,9 +156,9 @@ static void grow_gen_buffer(sed_eval_t *eval, int newsize,
|
||||
/*
|
||||
* appendmem_to_linebuf
|
||||
*/
|
||||
-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
|
||||
+static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len)
|
||||
{
|
||||
- unsigned int reqsize = (eval->lspend - eval->linebuf) + len;
|
||||
+ apr_size_t reqsize = (eval->lspend - eval->linebuf) + len;
|
||||
if (eval->lsize < reqsize) {
|
||||
grow_line_buffer(eval, reqsize);
|
||||
}
|
||||
@@ -169,21 +169,36 @@ static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
|
||||
/*
|
||||
* append_to_linebuf
|
||||
*/
|
||||
-static void append_to_linebuf(sed_eval_t *eval, const char* sz)
|
||||
+static void append_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
+ step_vars_storage *step_vars)
|
||||
{
|
||||
- int len = strlen(sz);
|
||||
+ apr_size_t len = strlen(sz);
|
||||
+ char *old_linebuf = eval->linebuf;
|
||||
/* Copy string including null character */
|
||||
appendmem_to_linebuf(eval, sz, len + 1);
|
||||
--eval->lspend; /* lspend will now point to NULL character */
|
||||
+ /* Sync step_vars after a possible linebuf expansion */
|
||||
+ if (step_vars && old_linebuf != eval->linebuf) {
|
||||
+ if (step_vars->loc1) {
|
||||
+ step_vars->loc1 = step_vars->loc1 - old_linebuf + eval->linebuf;
|
||||
+ }
|
||||
+ if (step_vars->loc2) {
|
||||
+ step_vars->loc2 = step_vars->loc2 - old_linebuf + eval->linebuf;
|
||||
+ }
|
||||
+ if (step_vars->locs) {
|
||||
+ step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_to_linebuf
|
||||
*/
|
||||
-static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
|
||||
+static void copy_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
+ step_vars_storage *step_vars)
|
||||
{
|
||||
eval->lspend = eval->linebuf;
|
||||
- append_to_linebuf(eval, sz);
|
||||
+ append_to_linebuf(eval, sz, step_vars);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -191,8 +206,8 @@ static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
|
||||
*/
|
||||
static void append_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
- int len = strlen(sz);
|
||||
- unsigned int reqsize = (eval->hspend - eval->holdbuf) + len + 1;
|
||||
+ apr_size_t len = strlen(sz);
|
||||
+ apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1;
|
||||
if (eval->hsize <= reqsize) {
|
||||
grow_hold_buffer(eval, reqsize);
|
||||
}
|
||||
@@ -215,8 +230,8 @@ static void copy_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
*/
|
||||
static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
||||
{
|
||||
- int len = strlen(sz);
|
||||
- unsigned int reqsize = (*gspend - eval->genbuf) + len + 1;
|
||||
+ apr_size_t len = strlen(sz);
|
||||
+ apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1;
|
||||
if (eval->gsize < reqsize) {
|
||||
grow_gen_buffer(eval, reqsize, gspend);
|
||||
}
|
||||
@@ -230,8 +245,8 @@ static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
||||
*/
|
||||
static void copy_to_genbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
- int len = strlen(sz);
|
||||
- unsigned int reqsize = len + 1;
|
||||
+ apr_size_t len = strlen(sz);
|
||||
+ apr_size_t reqsize = len + 1;
|
||||
if (eval->gsize < reqsize) {
|
||||
grow_gen_buffer(eval, reqsize, NULL);
|
||||
}
|
||||
@@ -353,7 +368,7 @@ apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout)
|
||||
/*
|
||||
* sed_eval_buffer
|
||||
*/
|
||||
-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout)
|
||||
+apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout)
|
||||
{
|
||||
apr_status_t rv;
|
||||
|
||||
@@ -383,7 +398,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void
|
||||
|
||||
while (bufsz) {
|
||||
char *n;
|
||||
- int llen;
|
||||
+ apr_size_t llen;
|
||||
|
||||
n = memchr(buf, '\n', bufsz);
|
||||
if (n == NULL)
|
||||
@@ -442,7 +457,7 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
|
||||
* buffer is not a newline.
|
||||
*/
|
||||
/* Assure space for NULL */
|
||||
- append_to_linebuf(eval, "");
|
||||
+ append_to_linebuf(eval, "", NULL);
|
||||
}
|
||||
|
||||
*eval->lspend = '\0';
|
||||
@@ -666,7 +681,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
lp = step_vars->loc2;
|
||||
step_vars->loc2 = sp - eval->genbuf + eval->linebuf;
|
||||
append_to_genbuf(eval, lp, &sp);
|
||||
- copy_to_linebuf(eval, eval->genbuf);
|
||||
+ copy_to_linebuf(eval, eval->genbuf, step_vars);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -676,8 +691,8 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
|
||||
{
|
||||
char *sp = asp;
|
||||
- int n = al2 - al1;
|
||||
- unsigned int reqsize = (sp - eval->genbuf) + n + 1;
|
||||
+ apr_size_t n = al2 - al1;
|
||||
+ apr_size_t reqsize = (sp - eval->genbuf) + n + 1;
|
||||
|
||||
if (eval->gsize < reqsize) {
|
||||
grow_gen_buffer(eval, reqsize, &sp);
|
||||
@@ -735,7 +750,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
}
|
||||
|
||||
p1++;
|
||||
- copy_to_linebuf(eval, p1);
|
||||
+ copy_to_linebuf(eval, p1, step_vars);
|
||||
eval->jflag++;
|
||||
break;
|
||||
|
||||
@@ -745,12 +760,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
break;
|
||||
|
||||
case GCOM:
|
||||
- copy_to_linebuf(eval, eval->holdbuf);
|
||||
+ copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
break;
|
||||
|
||||
case CGCOM:
|
||||
- append_to_linebuf(eval, "\n");
|
||||
- append_to_linebuf(eval, eval->holdbuf);
|
||||
+ append_to_linebuf(eval, "\n", step_vars);
|
||||
+ append_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
break;
|
||||
|
||||
case HCOM:
|
||||
@@ -881,7 +896,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
}
|
||||
- append_to_linebuf(eval, "\n");
|
||||
+ append_to_linebuf(eval, "\n", step_vars);
|
||||
eval->pending = ipc->next;
|
||||
break;
|
||||
|
||||
@@ -956,7 +971,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
|
||||
case XCOM:
|
||||
copy_to_genbuf(eval, eval->linebuf);
|
||||
- copy_to_linebuf(eval, eval->holdbuf);
|
||||
+ copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
copy_to_holdbuf(eval, eval->genbuf);
|
||||
break;
|
||||
|
||||
@@ -1013,7 +1028,7 @@ static apr_status_t arout(sed_eval_t *eval)
|
||||
/*
|
||||
* wline
|
||||
*/
|
||||
-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz)
|
||||
+static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
rv = eval->writefn(eval->fout, buf, sz);
|
|
@ -0,0 +1,26 @@
|
|||
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
|
||||
index 6faabea..058b03f 100644
|
||||
--- a/modules/proxy/mod_proxy_ajp.c
|
||||
+++ b/modules/proxy/mod_proxy_ajp.c
|
||||
@@ -249,9 +249,18 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
|
||||
/* read the first bloc of data */
|
||||
input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
|
||||
tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
|
||||
- if (tenc && (strcasecmp(tenc, "chunked") == 0)) {
|
||||
- /* The AJP protocol does not want body data yet */
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870) "request is chunked");
|
||||
+ if (tenc) {
|
||||
+ if (ap_cstr_casecmp(tenc, "chunked") == 0) {
|
||||
+ /* The AJP protocol does not want body data yet */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870)
|
||||
+ "request is chunked");
|
||||
+ }
|
||||
+ else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10396)
|
||||
+ "%s Transfer-Encoding is not supported",
|
||||
+ tenc);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
} else {
|
||||
/* Get client provided Content-Length header */
|
||||
content_length = get_content_length(r);
|
|
@ -0,0 +1,47 @@
|
|||
diff --git a/include/http_protocol.h b/include/http_protocol.h
|
||||
index e1572dc..8ed77ac 100644
|
||||
--- a/include/http_protocol.h
|
||||
+++ b/include/http_protocol.h
|
||||
@@ -439,7 +439,27 @@ AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r);
|
||||
*/
|
||||
static APR_INLINE int ap_rputs(const char *str, request_rec *r)
|
||||
{
|
||||
- return ap_rwrite(str, (int)strlen(str), r);
|
||||
+ apr_size_t len;
|
||||
+
|
||||
+ len = strlen(str);
|
||||
+
|
||||
+ for (;;) {
|
||||
+ if (len <= INT_MAX) {
|
||||
+ return ap_rwrite(str, (int)len, r);
|
||||
+ }
|
||||
+ else {
|
||||
+ int rc;
|
||||
+
|
||||
+ rc = ap_rwrite(str, INT_MAX, r);
|
||||
+ if (rc < 0) {
|
||||
+ return rc;
|
||||
+ }
|
||||
+ else {
|
||||
+ str += INT_MAX;
|
||||
+ len -= INT_MAX;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index a554970..ea461a2 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -2107,6 +2107,9 @@ AP_DECLARE(int) ap_rputc(int c, request_rec *r)
|
||||
|
||||
AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
|
||||
{
|
||||
+ if (nbyte < 0)
|
||||
+ return -1;
|
||||
+
|
||||
if (r->connection->aborted)
|
||||
return -1;
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
diff --git a/server/util.c b/server/util.c
|
||||
index eefdafa..45051b7 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -186,7 +186,7 @@ AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
|
||||
*/
|
||||
AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
|
||||
{
|
||||
- int x, y;
|
||||
+ apr_size_t x, y;
|
||||
|
||||
for (x = 0, y = 0; expected[y]; ++y, ++x) {
|
||||
if ((!str[x]) && (expected[y] != '*'))
|
||||
@@ -210,7 +210,7 @@ AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
|
||||
|
||||
AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
|
||||
{
|
||||
- int x, y;
|
||||
+ apr_size_t x, y;
|
||||
|
||||
for (x = 0, y = 0; expected[y]; ++y, ++x) {
|
||||
if (!str[x] && expected[y] != '*')
|
|
@ -0,0 +1,90 @@
|
|||
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
|
||||
index e1ec8d0..833fa7b 100644
|
||||
--- a/docs/manual/mod/core.html.en
|
||||
+++ b/docs/manual/mod/core.html.en
|
||||
@@ -2748,16 +2748,16 @@ subrequests</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Restricts the total size of the HTTP request body sent
|
||||
from the client</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>LimitRequestBody <var>bytes</var></code></td></tr>
|
||||
-<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>LimitRequestBody 0</code></td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>LimitRequestBody 1073741824</code></td></tr>
|
||||
<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host, directory, .htaccess</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Override">Override:</a></th><td>All</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
|
||||
<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
|
||||
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>In Apache HTTP Server 2.4.53 and earlier, the default value
|
||||
+ was 0 (unlimited)</td></tr>
|
||||
</table>
|
||||
- <p>This directive specifies the number of <var>bytes</var> from 0
|
||||
- (meaning unlimited) to 2147483647 (2GB) that are allowed in a
|
||||
- request body. See the note below for the limited applicability
|
||||
- to proxy requests.</p>
|
||||
+ <p>This directive specifies the number of <var>bytes</var>
|
||||
+ that are allowed in a request body. A value of <var>0</var> means unlimited.</p>
|
||||
|
||||
<p>The <code class="directive">LimitRequestBody</code> directive allows
|
||||
the user to set a limit on the allowed size of an HTTP request
|
||||
@@ -2783,12 +2783,6 @@ from the client</td></tr>
|
||||
|
||||
<pre class="prettyprint lang-config">LimitRequestBody 102400</pre>
|
||||
|
||||
-
|
||||
- <div class="note"><p>For a full description of how this directive is interpreted by
|
||||
- proxy requests, see the <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code> documentation.</p>
|
||||
- </div>
|
||||
-
|
||||
-
|
||||
</div>
|
||||
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="directive-section"><h2><a name="LimitRequestFields" id="LimitRequestFields">LimitRequestFields</a> <a name="limitrequestfields" id="limitrequestfields">Directive</a></h2>
|
||||
diff --git a/docs/manual/mod/mod_proxy.html.en b/docs/manual/mod/mod_proxy.html.en
|
||||
index 2cc6ace..c9e4634 100644
|
||||
--- a/docs/manual/mod/mod_proxy.html.en
|
||||
+++ b/docs/manual/mod/mod_proxy.html.en
|
||||
@@ -459,9 +459,6 @@ ProxyPass "/examples" "http://backend.example.com/examples" timeout=10</pre>
|
||||
Content-Length header, but the server is configured to filter incoming
|
||||
request bodies.</p>
|
||||
|
||||
- <p><code class="directive"><a href="../mod/core.html#limitrequestbody">LimitRequestBody</a></code> only applies to
|
||||
- request bodies that the server will spool to disk</p>
|
||||
-
|
||||
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="section">
|
||||
<h2><a name="x-headers" id="x-headers">Reverse Proxy Request Headers</a></h2>
|
||||
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
|
||||
index 6bedcac..393343a 100644
|
||||
--- a/modules/http/http_filters.c
|
||||
+++ b/modules/http/http_filters.c
|
||||
@@ -1710,6 +1710,7 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy)
|
||||
{
|
||||
const char *tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
|
||||
const char *lenp = apr_table_get(r->headers_in, "Content-Length");
|
||||
+ apr_off_t limit_req_body = ap_get_limit_req_body(r);
|
||||
|
||||
r->read_body = read_policy;
|
||||
r->read_chunked = 0;
|
||||
@@ -1748,6 +1749,11 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy)
|
||||
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
}
|
||||
|
||||
+ if (limit_req_body > 0 && (r->remaining > limit_req_body)) {
|
||||
+ /* will be logged when the body is discarded */
|
||||
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
+ }
|
||||
+
|
||||
#ifdef AP_DEBUG
|
||||
{
|
||||
/* Make sure ap_getline() didn't leave any droppings. */
|
||||
diff --git a/server/core.c b/server/core.c
|
||||
index a0bfaad..6556f20 100644
|
||||
--- a/server/core.c
|
||||
+++ b/server/core.c
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
/* LimitRequestBody handling */
|
||||
#define AP_LIMIT_REQ_BODY_UNSET ((apr_off_t) -1)
|
||||
-#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 0)
|
||||
+#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 1<<30) /* 1GB */
|
||||
|
||||
/* LimitXMLRequestBody handling */
|
||||
#define AP_LIMIT_UNSET ((long) -1)
|
|
@ -0,0 +1,541 @@
|
|||
diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c
|
||||
index 8595e41..9b99a6b 100644
|
||||
--- a/modules/filters/mod_sed.c
|
||||
+++ b/modules/filters/mod_sed.c
|
||||
@@ -59,7 +59,7 @@ typedef struct sed_filter_ctxt
|
||||
module AP_MODULE_DECLARE_DATA sed_module;
|
||||
|
||||
/* This function will be call back from libsed functions if there is any error
|
||||
- * happend during execution of sed scripts
|
||||
+ * happened during execution of sed scripts
|
||||
*/
|
||||
static apr_status_t log_sed_errf(void *data, const char *error)
|
||||
{
|
||||
@@ -276,7 +276,7 @@ static apr_status_t sed_response_filter(ap_filter_t *f,
|
||||
apr_bucket_brigade *bb)
|
||||
{
|
||||
apr_bucket *b;
|
||||
- apr_status_t status;
|
||||
+ apr_status_t status = APR_SUCCESS;
|
||||
sed_config *cfg = ap_get_module_config(f->r->per_dir_config,
|
||||
&sed_module);
|
||||
sed_filter_ctxt *ctx = f->ctx;
|
||||
@@ -301,9 +301,9 @@ static apr_status_t sed_response_filter(ap_filter_t *f,
|
||||
return status;
|
||||
ctx = f->ctx;
|
||||
apr_table_unset(f->r->headers_out, "Content-Length");
|
||||
- }
|
||||
|
||||
- ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
|
||||
+ ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
|
||||
+ }
|
||||
|
||||
/* Here is the main logic. Iterate through all the buckets, read the
|
||||
* content of the bucket, call sed_eval_buffer on the data.
|
||||
@@ -325,63 +325,52 @@ static apr_status_t sed_response_filter(ap_filter_t *f,
|
||||
* in sed's internal buffer which can't be flushed until new line
|
||||
* character is arrived.
|
||||
*/
|
||||
- for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb);) {
|
||||
- const char *buf = NULL;
|
||||
- apr_size_t bytes = 0;
|
||||
+ while (!APR_BRIGADE_EMPTY(bb)) {
|
||||
+ b = APR_BRIGADE_FIRST(bb);
|
||||
if (APR_BUCKET_IS_EOS(b)) {
|
||||
- apr_bucket *b1 = APR_BUCKET_NEXT(b);
|
||||
/* Now clean up the internal sed buffer */
|
||||
sed_finalize_eval(&ctx->eval, ctx);
|
||||
status = flush_output_buffer(ctx);
|
||||
if (status != APR_SUCCESS) {
|
||||
- clear_ctxpool(ctx);
|
||||
- return status;
|
||||
+ break;
|
||||
}
|
||||
+ /* Move the eos bucket to ctx->bb brigade */
|
||||
APR_BUCKET_REMOVE(b);
|
||||
- /* Insert the eos bucket to ctx->bb brigade */
|
||||
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
|
||||
- b = b1;
|
||||
}
|
||||
else if (APR_BUCKET_IS_FLUSH(b)) {
|
||||
- apr_bucket *b1 = APR_BUCKET_NEXT(b);
|
||||
- APR_BUCKET_REMOVE(b);
|
||||
status = flush_output_buffer(ctx);
|
||||
if (status != APR_SUCCESS) {
|
||||
- clear_ctxpool(ctx);
|
||||
- return status;
|
||||
+ break;
|
||||
}
|
||||
+ /* Move the flush bucket to ctx->bb brigade */
|
||||
+ APR_BUCKET_REMOVE(b);
|
||||
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
|
||||
- b = b1;
|
||||
- }
|
||||
- else if (APR_BUCKET_IS_METADATA(b)) {
|
||||
- b = APR_BUCKET_NEXT(b);
|
||||
}
|
||||
- else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
|
||||
- == APR_SUCCESS) {
|
||||
- apr_bucket *b1 = APR_BUCKET_NEXT(b);
|
||||
- status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- clear_ctxpool(ctx);
|
||||
- return status;
|
||||
+ else {
|
||||
+ if (!APR_BUCKET_IS_METADATA(b)) {
|
||||
+ const char *buf = NULL;
|
||||
+ apr_size_t bytes = 0;
|
||||
+
|
||||
+ status = apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ);
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
|
||||
+ }
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, f->r, APLOGNO(10394) "error evaluating sed on output");
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- APR_BUCKET_REMOVE(b);
|
||||
apr_bucket_delete(b);
|
||||
- b = b1;
|
||||
- }
|
||||
- else {
|
||||
- apr_bucket *b1 = APR_BUCKET_NEXT(b);
|
||||
- APR_BUCKET_REMOVE(b);
|
||||
- b = b1;
|
||||
}
|
||||
}
|
||||
- apr_brigade_cleanup(bb);
|
||||
- status = flush_output_buffer(ctx);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- clear_ctxpool(ctx);
|
||||
- return status;
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ status = flush_output_buffer(ctx);
|
||||
}
|
||||
if (!APR_BRIGADE_EMPTY(ctx->bb)) {
|
||||
- status = ap_pass_brigade(f->next, ctx->bb);
|
||||
+ if (status == APR_SUCCESS) {
|
||||
+ status = ap_pass_brigade(f->next, ctx->bb);
|
||||
+ }
|
||||
apr_brigade_cleanup(ctx->bb);
|
||||
}
|
||||
clear_ctxpool(ctx);
|
||||
@@ -432,7 +421,7 @@ static apr_status_t sed_request_filter(ap_filter_t *f,
|
||||
* the buckets in bbinp and read the data from buckets and invoke
|
||||
* sed_eval_buffer on the data. libsed will generate its output using
|
||||
* sed_write_output which will add data in ctx->bb. Do it until it have
|
||||
- * atleast one bucket in ctx->bb. At the end of data eos bucket
|
||||
+ * at least one bucket in ctx->bb. At the end of data eos bucket
|
||||
* should be there.
|
||||
*
|
||||
* Once eos bucket is seen, then invoke sed_finalize_eval to clear the
|
||||
@@ -474,8 +463,10 @@ static apr_status_t sed_request_filter(ap_filter_t *f,
|
||||
if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
|
||||
== APR_SUCCESS) {
|
||||
status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
|
||||
- if (status != APR_SUCCESS)
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, f->r, APLOGNO(10395) "error evaluating sed on input");
|
||||
return status;
|
||||
+ }
|
||||
flush_output_buffer(ctx);
|
||||
}
|
||||
}
|
||||
diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c
|
||||
index 67a8d06..047f49b 100644
|
||||
--- a/modules/filters/sed1.c
|
||||
+++ b/modules/filters/sed1.c
|
||||
@@ -87,18 +87,20 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
|
||||
}
|
||||
|
||||
#define INIT_BUF_SIZE 1024
|
||||
+#define MAX_BUF_SIZE 1024*8192
|
||||
|
||||
/*
|
||||
* grow_buffer
|
||||
*/
|
||||
-static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
+static apr_status_t grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
char **spend, apr_size_t *cursize,
|
||||
apr_size_t newsize)
|
||||
{
|
||||
char* newbuffer = NULL;
|
||||
apr_size_t spendsize = 0;
|
||||
- if (*cursize >= newsize)
|
||||
- return;
|
||||
+ if (*cursize >= newsize) {
|
||||
+ return APR_SUCCESS;
|
||||
+ }
|
||||
/* Avoid number of times realloc is called. It could cause huge memory
|
||||
* requirement if line size is huge e.g 2 MB */
|
||||
if (newsize < *cursize * 2) {
|
||||
@@ -107,6 +109,9 @@ static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
|
||||
/* Align it to 4 KB boundary */
|
||||
newsize = (newsize + ((1 << 12) - 1)) & ~((1 << 12) - 1);
|
||||
+ if (newsize > MAX_BUF_SIZE) {
|
||||
+ return APR_ENOMEM;
|
||||
+ }
|
||||
newbuffer = apr_pcalloc(pool, newsize);
|
||||
if (*spend && *buffer && (*cursize > 0)) {
|
||||
spendsize = *spend - *buffer;
|
||||
@@ -119,63 +124,77 @@ static void grow_buffer(apr_pool_t *pool, char **buffer,
|
||||
if (spend != buffer) {
|
||||
*spend = *buffer + spendsize;
|
||||
}
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* grow_line_buffer
|
||||
*/
|
||||
-static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
+static apr_status_t grow_line_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
{
|
||||
- grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
|
||||
+ return grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
|
||||
&eval->lsize, newsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* grow_hold_buffer
|
||||
*/
|
||||
-static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
+static apr_status_t grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize)
|
||||
{
|
||||
- grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
|
||||
+ return grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
|
||||
&eval->hsize, newsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* grow_gen_buffer
|
||||
*/
|
||||
-static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize,
|
||||
+static apr_status_t grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize,
|
||||
char **gspend)
|
||||
{
|
||||
+ apr_status_t rc = 0;
|
||||
if (gspend == NULL) {
|
||||
gspend = &eval->genbuf;
|
||||
}
|
||||
- grow_buffer(eval->pool, &eval->genbuf, gspend,
|
||||
- &eval->gsize, newsize);
|
||||
- eval->lcomend = &eval->genbuf[71];
|
||||
+ rc = grow_buffer(eval->pool, &eval->genbuf, gspend,
|
||||
+ &eval->gsize, newsize);
|
||||
+ if (rc == APR_SUCCESS) {
|
||||
+ eval->lcomend = &eval->genbuf[71];
|
||||
+ }
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* appendmem_to_linebuf
|
||||
*/
|
||||
-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len)
|
||||
+static apr_status_t appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len)
|
||||
{
|
||||
+ apr_status_t rc = 0;
|
||||
apr_size_t reqsize = (eval->lspend - eval->linebuf) + len;
|
||||
if (eval->lsize < reqsize) {
|
||||
- grow_line_buffer(eval, reqsize);
|
||||
+ rc = grow_line_buffer(eval, reqsize);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
memcpy(eval->lspend, sz, len);
|
||||
eval->lspend += len;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* append_to_linebuf
|
||||
*/
|
||||
-static void append_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
+static apr_status_t append_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
step_vars_storage *step_vars)
|
||||
{
|
||||
apr_size_t len = strlen(sz);
|
||||
char *old_linebuf = eval->linebuf;
|
||||
+ apr_status_t rc = 0;
|
||||
/* Copy string including null character */
|
||||
- appendmem_to_linebuf(eval, sz, len + 1);
|
||||
+ rc = appendmem_to_linebuf(eval, sz, len + 1);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
--eval->lspend; /* lspend will now point to NULL character */
|
||||
/* Sync step_vars after a possible linebuf expansion */
|
||||
if (step_vars && old_linebuf != eval->linebuf) {
|
||||
@@ -189,68 +208,84 @@ static void append_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf;
|
||||
}
|
||||
}
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_to_linebuf
|
||||
*/
|
||||
-static void copy_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
+static apr_status_t copy_to_linebuf(sed_eval_t *eval, const char* sz,
|
||||
step_vars_storage *step_vars)
|
||||
{
|
||||
eval->lspend = eval->linebuf;
|
||||
- append_to_linebuf(eval, sz, step_vars);
|
||||
+ return append_to_linebuf(eval, sz, step_vars);
|
||||
}
|
||||
|
||||
/*
|
||||
* append_to_holdbuf
|
||||
*/
|
||||
-static void append_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
+static apr_status_t append_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
apr_size_t len = strlen(sz);
|
||||
apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1;
|
||||
+ apr_status_t rc = 0;
|
||||
if (eval->hsize <= reqsize) {
|
||||
- grow_hold_buffer(eval, reqsize);
|
||||
+ rc = grow_hold_buffer(eval, reqsize);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
memcpy(eval->hspend, sz, len + 1);
|
||||
/* hspend will now point to NULL character */
|
||||
eval->hspend += len;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_to_holdbuf
|
||||
*/
|
||||
-static void copy_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
+static apr_status_t copy_to_holdbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
eval->hspend = eval->holdbuf;
|
||||
- append_to_holdbuf(eval, sz);
|
||||
+ return append_to_holdbuf(eval, sz);
|
||||
}
|
||||
|
||||
/*
|
||||
* append_to_genbuf
|
||||
*/
|
||||
-static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
||||
+static apr_status_t append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
||||
{
|
||||
apr_size_t len = strlen(sz);
|
||||
apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1;
|
||||
+ apr_status_t rc = 0;
|
||||
if (eval->gsize < reqsize) {
|
||||
- grow_gen_buffer(eval, reqsize, gspend);
|
||||
+ rc = grow_gen_buffer(eval, reqsize, gspend);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
memcpy(*gspend, sz, len + 1);
|
||||
/* *gspend will now point to NULL character */
|
||||
*gspend += len;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_to_genbuf
|
||||
*/
|
||||
-static void copy_to_genbuf(sed_eval_t *eval, const char* sz)
|
||||
+static apr_status_t copy_to_genbuf(sed_eval_t *eval, const char* sz)
|
||||
{
|
||||
apr_size_t len = strlen(sz);
|
||||
apr_size_t reqsize = len + 1;
|
||||
+ apr_status_t rc = APR_SUCCESS;;
|
||||
if (eval->gsize < reqsize) {
|
||||
- grow_gen_buffer(eval, reqsize, NULL);
|
||||
+ rc = grow_gen_buffer(eval, reqsize, NULL);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
memcpy(eval->genbuf, sz, len + 1);
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -397,6 +432,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz
|
||||
}
|
||||
|
||||
while (bufsz) {
|
||||
+ apr_status_t rc = 0;
|
||||
char *n;
|
||||
apr_size_t llen;
|
||||
|
||||
@@ -411,7 +447,10 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz
|
||||
break;
|
||||
}
|
||||
|
||||
- appendmem_to_linebuf(eval, buf, llen + 1);
|
||||
+ rc = appendmem_to_linebuf(eval, buf, llen + 1);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
--eval->lspend;
|
||||
/* replace new line character with NULL */
|
||||
*eval->lspend = '\0';
|
||||
@@ -426,7 +465,10 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz
|
||||
|
||||
/* Save the leftovers for later */
|
||||
if (bufsz) {
|
||||
- appendmem_to_linebuf(eval, buf, bufsz);
|
||||
+ apr_status_t rc = appendmem_to_linebuf(eval, buf, bufsz);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
@@ -448,6 +490,7 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
|
||||
/* Process leftovers */
|
||||
if (eval->lspend > eval->linebuf) {
|
||||
apr_status_t rv;
|
||||
+ apr_status_t rc = 0;
|
||||
|
||||
if (eval->lreadyflag) {
|
||||
eval->lreadyflag = 0;
|
||||
@@ -457,7 +500,10 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
|
||||
* buffer is not a newline.
|
||||
*/
|
||||
/* Assure space for NULL */
|
||||
- append_to_linebuf(eval, "", NULL);
|
||||
+ rc = append_to_linebuf(eval, "", NULL);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return rc;
|
||||
+ }
|
||||
}
|
||||
|
||||
*eval->lspend = '\0';
|
||||
@@ -655,11 +701,15 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
sp = eval->genbuf;
|
||||
rp = rhsbuf;
|
||||
sp = place(eval, sp, lp, step_vars->loc1);
|
||||
+ if (sp == NULL) {
|
||||
+ return APR_EGENERAL;
|
||||
+ }
|
||||
while ((c = *rp++) != 0) {
|
||||
if (c == '&') {
|
||||
sp = place(eval, sp, step_vars->loc1, step_vars->loc2);
|
||||
- if (sp == NULL)
|
||||
+ if (sp == NULL) {
|
||||
return APR_EGENERAL;
|
||||
+ }
|
||||
}
|
||||
else if (c == '\\') {
|
||||
c = *rp++;
|
||||
@@ -675,13 +725,19 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
||||
*sp++ = c;
|
||||
if (sp >= eval->genbuf + eval->gsize) {
|
||||
/* expand genbuf and set the sp appropriately */
|
||||
- grow_gen_buffer(eval, eval->gsize + 1024, &sp);
|
||||
+ rv = grow_gen_buffer(eval, eval->gsize + 1024, &sp);
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return rv;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
lp = step_vars->loc2;
|
||||
step_vars->loc2 = sp - eval->genbuf + eval->linebuf;
|
||||
- append_to_genbuf(eval, lp, &sp);
|
||||
- copy_to_linebuf(eval, eval->genbuf, step_vars);
|
||||
+ rv = append_to_genbuf(eval, lp, &sp);
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return rv;
|
||||
+ }
|
||||
+ rv = copy_to_linebuf(eval, eval->genbuf, step_vars);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -695,7 +751,10 @@ static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
|
||||
apr_size_t reqsize = (sp - eval->genbuf) + n + 1;
|
||||
|
||||
if (eval->gsize < reqsize) {
|
||||
- grow_gen_buffer(eval, reqsize, &sp);
|
||||
+ apr_status_t rc = grow_gen_buffer(eval, reqsize, &sp);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
}
|
||||
memcpy(sp, al1, n);
|
||||
return sp + n;
|
||||
@@ -750,7 +809,8 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
}
|
||||
|
||||
p1++;
|
||||
- copy_to_linebuf(eval, p1, step_vars);
|
||||
+ rv = copy_to_linebuf(eval, p1, step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
eval->jflag++;
|
||||
break;
|
||||
|
||||
@@ -760,21 +820,27 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
break;
|
||||
|
||||
case GCOM:
|
||||
- copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ rv = copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case CGCOM:
|
||||
- append_to_linebuf(eval, "\n", step_vars);
|
||||
- append_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ rv = append_to_linebuf(eval, "\n", step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
+ rv = append_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case HCOM:
|
||||
- copy_to_holdbuf(eval, eval->linebuf);
|
||||
+ rv = copy_to_holdbuf(eval, eval->linebuf);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case CHCOM:
|
||||
- append_to_holdbuf(eval, "\n");
|
||||
- append_to_holdbuf(eval, eval->linebuf);
|
||||
+ rv = append_to_holdbuf(eval, "\n");
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
+ rv = append_to_holdbuf(eval, eval->linebuf);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case ICOM:
|
||||
@@ -896,7 +962,8 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
if (rv != APR_SUCCESS)
|
||||
return rv;
|
||||
}
|
||||
- append_to_linebuf(eval, "\n", step_vars);
|
||||
+ rv = append_to_linebuf(eval, "\n", step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
eval->pending = ipc->next;
|
||||
break;
|
||||
|
||||
@@ -970,9 +1037,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
||||
break;
|
||||
|
||||
case XCOM:
|
||||
- copy_to_genbuf(eval, eval->linebuf);
|
||||
- copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
- copy_to_holdbuf(eval, eval->genbuf);
|
||||
+ rv = copy_to_genbuf(eval, eval->linebuf);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
+ rv = copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
+ rv = copy_to_holdbuf(eval, eval->genbuf);
|
||||
+ if (rv != APR_SUCCESS) return rv;
|
||||
break;
|
||||
|
||||
case YCOM:
|
|
@ -0,0 +1,233 @@
|
|||
diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c
|
||||
index ba63584..c1ba74a 100644
|
||||
--- a/modules/lua/lua_request.c
|
||||
+++ b/modules/lua/lua_request.c
|
||||
@@ -2193,23 +2193,20 @@ static int lua_websocket_greet(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static apr_status_t lua_websocket_readbytes(conn_rec* c, char* buffer,
|
||||
- apr_off_t len)
|
||||
+static apr_status_t lua_websocket_readbytes(conn_rec* c,
|
||||
+ apr_bucket_brigade *brigade,
|
||||
+ char* buffer, apr_off_t len)
|
||||
{
|
||||
- apr_bucket_brigade *brigade = apr_brigade_create(c->pool, c->bucket_alloc);
|
||||
+ apr_size_t delivered;
|
||||
apr_status_t rv;
|
||||
+
|
||||
rv = ap_get_brigade(c->input_filters, brigade, AP_MODE_READBYTES,
|
||||
APR_BLOCK_READ, len);
|
||||
if (rv == APR_SUCCESS) {
|
||||
- if (!APR_BRIGADE_EMPTY(brigade)) {
|
||||
- apr_bucket* bucket = APR_BRIGADE_FIRST(brigade);
|
||||
- const char* data = NULL;
|
||||
- apr_size_t data_length = 0;
|
||||
- rv = apr_bucket_read(bucket, &data, &data_length, APR_BLOCK_READ);
|
||||
- if (rv == APR_SUCCESS) {
|
||||
- memcpy(buffer, data, len);
|
||||
- }
|
||||
- apr_bucket_delete(bucket);
|
||||
+ delivered = len;
|
||||
+ rv = apr_brigade_flatten(brigade, buffer, &delivered);
|
||||
+ if ((rv == APR_SUCCESS) && (delivered < len)) {
|
||||
+ rv = APR_INCOMPLETE;
|
||||
}
|
||||
}
|
||||
apr_brigade_cleanup(brigade);
|
||||
@@ -2239,35 +2236,28 @@ static int lua_websocket_peek(lua_State *L)
|
||||
|
||||
static int lua_websocket_read(lua_State *L)
|
||||
{
|
||||
- apr_socket_t *sock;
|
||||
apr_status_t rv;
|
||||
int do_read = 1;
|
||||
int n = 0;
|
||||
- apr_size_t len = 1;
|
||||
apr_size_t plen = 0;
|
||||
unsigned short payload_short = 0;
|
||||
apr_uint64_t payload_long = 0;
|
||||
unsigned char *mask_bytes;
|
||||
char byte;
|
||||
- int plaintext;
|
||||
-
|
||||
-
|
||||
+ apr_bucket_brigade *brigade;
|
||||
+ conn_rec* c;
|
||||
+
|
||||
request_rec *r = ap_lua_check_request_rec(L, 1);
|
||||
- plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1;
|
||||
+ c = r->connection;
|
||||
|
||||
-
|
||||
mask_bytes = apr_pcalloc(r->pool, 4);
|
||||
- sock = ap_get_conn_socket(r->connection);
|
||||
+
|
||||
+ brigade = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
while (do_read) {
|
||||
do_read = 0;
|
||||
/* Get opcode and FIN bit */
|
||||
- if (plaintext) {
|
||||
- rv = apr_socket_recv(sock, &byte, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection, &byte, 1);
|
||||
- }
|
||||
+ rv = lua_websocket_readbytes(c, brigade, &byte, 1);
|
||||
if (rv == APR_SUCCESS) {
|
||||
unsigned char ubyte, fin, opcode, mask, payload;
|
||||
ubyte = (unsigned char)byte;
|
||||
@@ -2277,12 +2267,7 @@ static int lua_websocket_read(lua_State *L)
|
||||
opcode = ubyte & 0xf;
|
||||
|
||||
/* Get the payload length and mask bit */
|
||||
- if (plaintext) {
|
||||
- rv = apr_socket_recv(sock, &byte, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection, &byte, 1);
|
||||
- }
|
||||
+ rv = lua_websocket_readbytes(c, brigade, &byte, 1);
|
||||
if (rv == APR_SUCCESS) {
|
||||
ubyte = (unsigned char)byte;
|
||||
/* Mask is the first bit */
|
||||
@@ -2293,40 +2278,25 @@ static int lua_websocket_read(lua_State *L)
|
||||
|
||||
/* Extended payload? */
|
||||
if (payload == 126) {
|
||||
- len = 2;
|
||||
- if (plaintext) {
|
||||
- /* XXX: apr_socket_recv does not receive len bits, only up to len bits! */
|
||||
- rv = apr_socket_recv(sock, (char*) &payload_short, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection,
|
||||
- (char*) &payload_short, 2);
|
||||
- }
|
||||
- payload_short = ntohs(payload_short);
|
||||
+ rv = lua_websocket_readbytes(c, brigade,
|
||||
+ (char*) &payload_short, 2);
|
||||
|
||||
- if (rv == APR_SUCCESS) {
|
||||
- plen = payload_short;
|
||||
- }
|
||||
- else {
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+ plen = ntohs(payload_short);
|
||||
}
|
||||
/* Super duper extended payload? */
|
||||
if (payload == 127) {
|
||||
- len = 8;
|
||||
- if (plaintext) {
|
||||
- rv = apr_socket_recv(sock, (char*) &payload_long, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection,
|
||||
- (char*) &payload_long, 8);
|
||||
- }
|
||||
- if (rv == APR_SUCCESS) {
|
||||
- plen = ap_ntoh64(&payload_long);
|
||||
- }
|
||||
- else {
|
||||
+ rv = lua_websocket_readbytes(c, brigade,
|
||||
+ (char*) &payload_long, 8);
|
||||
+
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+ plen = ap_ntoh64(&payload_long);
|
||||
}
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03210)
|
||||
"Websocket: Reading %" APR_SIZE_T_FMT " (%s) bytes, masking is %s. %s",
|
||||
@@ -2335,46 +2305,27 @@ static int lua_websocket_read(lua_State *L)
|
||||
mask ? "on" : "off",
|
||||
fin ? "This is a final frame" : "more to follow");
|
||||
if (mask) {
|
||||
- len = 4;
|
||||
- if (plaintext) {
|
||||
- rv = apr_socket_recv(sock, (char*) mask_bytes, &len);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection,
|
||||
- (char*) mask_bytes, 4);
|
||||
- }
|
||||
+ rv = lua_websocket_readbytes(c, brigade,
|
||||
+ (char*) mask_bytes, 4);
|
||||
+
|
||||
if (rv != APR_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (plen < (HUGE_STRING_LEN*1024) && plen > 0) {
|
||||
apr_size_t remaining = plen;
|
||||
- apr_size_t received;
|
||||
- apr_off_t at = 0;
|
||||
char *buffer = apr_palloc(r->pool, plen+1);
|
||||
buffer[plen] = 0;
|
||||
|
||||
- if (plaintext) {
|
||||
- while (remaining > 0) {
|
||||
- received = remaining;
|
||||
- rv = apr_socket_recv(sock, buffer+at, &received);
|
||||
- if (received > 0 ) {
|
||||
- remaining -= received;
|
||||
- at += received;
|
||||
- }
|
||||
- }
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
- "Websocket: Frame contained %" APR_OFF_T_FMT " bytes, pushed to Lua stack",
|
||||
- at);
|
||||
- }
|
||||
- else {
|
||||
- rv = lua_websocket_readbytes(r->connection, buffer,
|
||||
- remaining);
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
- "Websocket: SSL Frame contained %" APR_SIZE_T_FMT " bytes, "\
|
||||
- "pushed to Lua stack",
|
||||
- remaining);
|
||||
+ rv = lua_websocket_readbytes(c, brigade, buffer, remaining);
|
||||
+
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return 0;
|
||||
}
|
||||
+
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
+ "Websocket: Frame contained %" APR_SIZE_T_FMT \
|
||||
+ " bytes, pushed to Lua stack", remaining);
|
||||
if (mask) {
|
||||
for (n = 0; n < plen; n++) {
|
||||
buffer[n] ^= mask_bytes[n%4];
|
||||
@@ -2386,14 +2337,25 @@ static int lua_websocket_read(lua_State *L)
|
||||
return 2;
|
||||
}
|
||||
|
||||
-
|
||||
/* Decide if we need to react to the opcode or not */
|
||||
if (opcode == 0x09) { /* ping */
|
||||
char frame[2];
|
||||
- plen = 2;
|
||||
+ apr_bucket *b;
|
||||
+
|
||||
frame[0] = 0x8A;
|
||||
frame[1] = 0;
|
||||
- apr_socket_send(sock, frame, &plen); /* Pong! */
|
||||
+
|
||||
+ /* Pong! */
|
||||
+ b = apr_bucket_transient_create(frame, 2, c->bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(brigade, b);
|
||||
+
|
||||
+ rv = ap_pass_brigade(c->output_filters, brigade);
|
||||
+ apr_brigade_cleanup(brigade);
|
||||
+
|
||||
+ if (rv != APR_SUCCESS) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
do_read = 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index efcc6ca..6626ea0 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -3631,12 +3631,14 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
char **old_cl_val,
|
||||
char **old_te_val)
|
||||
{
|
||||
+ int rc = OK;
|
||||
conn_rec *c = r->connection;
|
||||
int counter;
|
||||
char *buf;
|
||||
+ apr_table_t *saved_headers_in = r->headers_in;
|
||||
+ const char *saved_host = apr_table_get(saved_headers_in, "Host");
|
||||
const apr_array_header_t *headers_in_array;
|
||||
const apr_table_entry_t *headers_in;
|
||||
- apr_table_t *saved_headers_in;
|
||||
apr_bucket *e;
|
||||
int do_100_continue;
|
||||
conn_rec *origin = p_conn->connection;
|
||||
@@ -3672,6 +3674,52 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
ap_xlate_proto_to_ascii(buf, strlen(buf));
|
||||
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
|
||||
+
|
||||
+ /*
|
||||
+ * Make a copy on r->headers_in for the request we make to the backend,
|
||||
+ * modify the copy in place according to our configuration and connection
|
||||
+ * handling, use it to fill in the forwarded headers' brigade, and finally
|
||||
+ * restore the saved/original ones in r->headers_in.
|
||||
+ *
|
||||
+ * Note: We need to take r->pool for apr_table_copy as the key / value
|
||||
+ * pairs in r->headers_in have been created out of r->pool and
|
||||
+ * p might be (and actually is) a longer living pool.
|
||||
+ * This would trigger the bad pool ancestry abort in apr_table_copy if
|
||||
+ * apr is compiled with APR_POOL_DEBUG.
|
||||
+ *
|
||||
+ * icing: if p indeed lives longer than r->pool, we should allocate
|
||||
+ * all new header values from r->pool as well and avoid leakage.
|
||||
+ */
|
||||
+ r->headers_in = apr_table_copy(r->pool, saved_headers_in);
|
||||
+
|
||||
+ /* Return the original Transfer-Encoding and/or Content-Length values
|
||||
+ * then drop the headers, they must be set by the proxy handler based
|
||||
+ * on the actual body being forwarded.
|
||||
+ */
|
||||
+ if ((*old_te_val = (char *)apr_table_get(r->headers_in,
|
||||
+ "Transfer-Encoding"))) {
|
||||
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
|
||||
+ }
|
||||
+ if ((*old_cl_val = (char *)apr_table_get(r->headers_in,
|
||||
+ "Content-Length"))) {
|
||||
+ apr_table_unset(r->headers_in, "Content-Length");
|
||||
+ }
|
||||
+
|
||||
+ /* Clear out hop-by-hop request headers not to forward */
|
||||
+ if (ap_proxy_clear_connection(r, r->headers_in) < 0) {
|
||||
+ rc = HTTP_BAD_REQUEST;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* RFC2616 13.5.1 says we should strip these */
|
||||
+ apr_table_unset(r->headers_in, "Keep-Alive");
|
||||
+ apr_table_unset(r->headers_in, "Upgrade");
|
||||
+ apr_table_unset(r->headers_in, "Trailer");
|
||||
+ apr_table_unset(r->headers_in, "TE");
|
||||
+
|
||||
+ /* We used to send `Host: ` always first, so let's keep it that
|
||||
+ * way. No telling which legacy backend is relying no this.
|
||||
+ */
|
||||
if (dconf->preserve_host == 0) {
|
||||
if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */
|
||||
if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
|
||||
@@ -3693,7 +3741,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
/* don't want to use r->hostname, as the incoming header might have a
|
||||
* port attached
|
||||
*/
|
||||
- const char* hostname = apr_table_get(r->headers_in,"Host");
|
||||
+ const char* hostname = saved_host;
|
||||
if (!hostname) {
|
||||
hostname = r->server->server_hostname;
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01092)
|
||||
@@ -3707,21 +3755,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
ap_xlate_proto_to_ascii(buf, strlen(buf));
|
||||
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
|
||||
-
|
||||
- /*
|
||||
- * Save the original headers in here and restore them when leaving, since
|
||||
- * we will apply proxy purpose only modifications (eg. clearing hop-by-hop
|
||||
- * headers, add Via or X-Forwarded-* or Expect...), whereas the originals
|
||||
- * will be needed later to prepare the correct response and logging.
|
||||
- *
|
||||
- * Note: We need to take r->pool for apr_table_copy as the key / value
|
||||
- * pairs in r->headers_in have been created out of r->pool and
|
||||
- * p might be (and actually is) a longer living pool.
|
||||
- * This would trigger the bad pool ancestry abort in apr_table_copy if
|
||||
- * apr is compiled with APR_POOL_DEBUG.
|
||||
- */
|
||||
- saved_headers_in = r->headers_in;
|
||||
- r->headers_in = apr_table_copy(r->pool, saved_headers_in);
|
||||
+ apr_table_unset(r->headers_in, "Host");
|
||||
|
||||
/* handle Via */
|
||||
if (conf->viaopt == via_block) {
|
||||
@@ -3788,8 +3822,6 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
*/
|
||||
if (dconf->add_forwarded_headers) {
|
||||
if (PROXYREQ_REVERSE == r->proxyreq) {
|
||||
- const char *buf;
|
||||
-
|
||||
/* Add X-Forwarded-For: so that the upstream has a chance to
|
||||
* determine, where the original request came from.
|
||||
*/
|
||||
@@ -3799,8 +3831,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
/* Add X-Forwarded-Host: so that upstream knows what the
|
||||
* original request hostname was.
|
||||
*/
|
||||
- if ((buf = apr_table_get(r->headers_in, "Host"))) {
|
||||
- apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf);
|
||||
+ if (saved_host) {
|
||||
+ apr_table_mergen(r->headers_in, "X-Forwarded-Host",
|
||||
+ saved_host);
|
||||
}
|
||||
|
||||
/* Add X-Forwarded-Server: so that upstream knows what the
|
||||
@@ -3812,10 +3845,27 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Do we want to strip Proxy-Authorization ?
|
||||
+ * If we haven't used it, then NO
|
||||
+ * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
|
||||
+ * So let's make it configurable by env.
|
||||
+ */
|
||||
+ if (r->user != NULL /* we've authenticated */
|
||||
+ && !apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
|
||||
+ apr_table_unset(r->headers_in, "Proxy-Authorization");
|
||||
+ }
|
||||
+
|
||||
+ /* for sub-requests, ignore freshness/expiry headers */
|
||||
+ if (r->main) {
|
||||
+ apr_table_unset(r->headers_in, "If-Match");
|
||||
+ apr_table_unset(r->headers_in, "If-Modified-Since");
|
||||
+ apr_table_unset(r->headers_in, "If-Range");
|
||||
+ apr_table_unset(r->headers_in, "If-Unmodified-Since");
|
||||
+ apr_table_unset(r->headers_in, "If-None-Match");
|
||||
+ }
|
||||
+
|
||||
+ /* run hook to fixup the request we are about to send */
|
||||
proxy_run_fixups(r);
|
||||
- if (ap_proxy_clear_connection(r, r->headers_in) < 0) {
|
||||
- return HTTP_BAD_REQUEST;
|
||||
- }
|
||||
|
||||
creds = apr_table_get(r->notes, "proxy-basic-creds");
|
||||
if (creds) {
|
||||
@@ -3827,55 +3877,8 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
headers_in = (const apr_table_entry_t *) headers_in_array->elts;
|
||||
for (counter = 0; counter < headers_in_array->nelts; counter++) {
|
||||
if (headers_in[counter].key == NULL
|
||||
- || headers_in[counter].val == NULL
|
||||
-
|
||||
- /* Already sent */
|
||||
- || !strcasecmp(headers_in[counter].key, "Host")
|
||||
-
|
||||
- /* Clear out hop-by-hop request headers not to send
|
||||
- * RFC2616 13.5.1 says we should strip these headers
|
||||
- */
|
||||
- || !strcasecmp(headers_in[counter].key, "Keep-Alive")
|
||||
- || !strcasecmp(headers_in[counter].key, "TE")
|
||||
- || !strcasecmp(headers_in[counter].key, "Trailer")
|
||||
- || !strcasecmp(headers_in[counter].key, "Upgrade")
|
||||
-
|
||||
- ) {
|
||||
- continue;
|
||||
- }
|
||||
- /* Do we want to strip Proxy-Authorization ?
|
||||
- * If we haven't used it, then NO
|
||||
- * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
|
||||
- * So let's make it configurable by env.
|
||||
- */
|
||||
- if (!strcasecmp(headers_in[counter].key,"Proxy-Authorization")) {
|
||||
- if (r->user != NULL) { /* we've authenticated */
|
||||
- if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
|
||||
- continue;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /* Skip Transfer-Encoding and Content-Length for now.
|
||||
- */
|
||||
- if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) {
|
||||
- *old_te_val = headers_in[counter].val;
|
||||
- continue;
|
||||
- }
|
||||
- if (!strcasecmp(headers_in[counter].key, "Content-Length")) {
|
||||
- *old_cl_val = headers_in[counter].val;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- /* for sub-requests, ignore freshness/expiry headers */
|
||||
- if (r->main) {
|
||||
- if ( !strcasecmp(headers_in[counter].key, "If-Match")
|
||||
- || !strcasecmp(headers_in[counter].key, "If-Modified-Since")
|
||||
- || !strcasecmp(headers_in[counter].key, "If-Range")
|
||||
- || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since")
|
||||
- || !strcasecmp(headers_in[counter].key, "If-None-Match")) {
|
||||
- continue;
|
||||
- }
|
||||
+ || headers_in[counter].val == NULL) {
|
||||
+ continue;
|
||||
}
|
||||
|
||||
buf = apr_pstrcat(p, headers_in[counter].key, ": ",
|
||||
@@ -3886,11 +3889,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
|
||||
}
|
||||
|
||||
- /* Restore the original headers in (see comment above),
|
||||
- * we won't modify them anymore.
|
||||
- */
|
||||
+cleanup:
|
||||
r->headers_in = saved_headers_in;
|
||||
- return OK;
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
PROXY_DECLARE(int) ap_proxy_prefetch_input(request_rec *r,
|
|
@ -0,0 +1,23 @@
|
|||
From 5efc9507c487c37dfe2a279a4a0335cad701cd5f Mon Sep 17 00:00:00 2001
|
||||
From: Eric Covener <covener@apache.org>
|
||||
Date: Tue, 10 Jan 2023 13:19:07 +0000
|
||||
Subject: [PATCH] cleanup on error
|
||||
|
||||
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1906540 13f79535-47bb-0310-9956-ffa450edef68
|
||||
---
|
||||
modules/proxy/mod_proxy_ajp.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
|
||||
index 9cd7adbcbbf..07f37392d88 100644
|
||||
--- a/modules/proxy/mod_proxy_ajp.c
|
||||
+++ b/modules/proxy/mod_proxy_ajp.c
|
||||
@@ -255,6 +255,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10396)
|
||||
"%s Transfer-Encoding is not supported",
|
||||
tenc);
|
||||
+ /* We had a failure: Close connection to backend */
|
||||
+ conn->close = 1;
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
} else {
|
|
@ -0,0 +1,129 @@
|
|||
From 8b6d55f6a047acf62675e32606b037f5eea8ccc7 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Covener <covener@apache.org>
|
||||
Date: Tue, 10 Jan 2023 13:20:09 +0000
|
||||
Subject: [PATCH] Merge r1906539 from trunk:
|
||||
|
||||
fail on bad header
|
||||
|
||||
Submitted By: covener
|
||||
Reviewed By: covener, rpluem, gbechis
|
||||
|
||||
|
||||
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1906541 13f79535-47bb-0310-9956-ffa450edef68
|
||||
---
|
||||
modules/proxy/mod_proxy_http.c | 46 ++++++++++++++++++++--------------
|
||||
server/protocol.c | 2 ++
|
||||
2 files changed, 29 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index d74ae054ac9..ec4e7fb06b5 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -788,7 +788,7 @@ static void process_proxy_header(request_rec *r, proxy_dir_conf *c,
|
||||
* any sense at all, since we depend on buffer still containing
|
||||
* what was read by ap_getline() upon return.
|
||||
*/
|
||||
-static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
+static apr_status_t ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
char *buffer, int size,
|
||||
conn_rec *c, int *pread_len)
|
||||
{
|
||||
@@ -820,19 +820,26 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
rc = ap_proxygetline(tmp_bb, buffer, size, rr,
|
||||
AP_GETLINE_FOLD | AP_GETLINE_NOSPC_EOL, &len);
|
||||
|
||||
- if (len <= 0)
|
||||
- break;
|
||||
|
||||
- if (APR_STATUS_IS_ENOSPC(rc)) {
|
||||
- /* The header could not fit in the provided buffer, warn.
|
||||
- * XXX: falls through with the truncated header, 5xx instead?
|
||||
- */
|
||||
- int trunc = (len > 128 ? 128 : len) / 2;
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10124)
|
||||
- "header size is over the limit allowed by "
|
||||
- "ResponseFieldSize (%d bytes). "
|
||||
- "Bad response header: '%.*s[...]%s'",
|
||||
- size, trunc, buffer, buffer + len - trunc);
|
||||
+ if (rc != APR_SUCCESS) {
|
||||
+ if (APR_STATUS_IS_ENOSPC(rc)) {
|
||||
+ int trunc = (len > 128 ? 128 : len) / 2;
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10124)
|
||||
+ "header size is over the limit allowed by "
|
||||
+ "ResponseFieldSize (%d bytes). "
|
||||
+ "Bad response header: '%.*s[...]%s'",
|
||||
+ size, trunc, buffer, buffer + len - trunc);
|
||||
+ }
|
||||
+ else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10404)
|
||||
+ "Error reading headers from backend");
|
||||
+ }
|
||||
+ r->headers_out = NULL;
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
+ if (len <= 0) {
|
||||
+ break;
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "%s", buffer);
|
||||
@@ -855,7 +862,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
if (psc->badopt == bad_error) {
|
||||
/* Nope, it wasn't even an extra HTTP header. Give up. */
|
||||
r->headers_out = NULL;
|
||||
- return;
|
||||
+ return APR_EINVAL;
|
||||
}
|
||||
else if (psc->badopt == bad_body) {
|
||||
/* if we've already started loading headers_out, then
|
||||
@@ -869,13 +876,13 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
"in headers returned by %s (%s)",
|
||||
r->uri, r->method);
|
||||
*pread_len = len;
|
||||
- return;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01099)
|
||||
"No HTTP headers returned by %s (%s)",
|
||||
r->uri, r->method);
|
||||
- return;
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -905,6 +912,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
|
||||
process_proxy_header(r, dconf, buffer, value);
|
||||
saw_headers = 1;
|
||||
}
|
||||
+ return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1218,10 +1226,10 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
|
||||
"Set-Cookie", NULL);
|
||||
|
||||
/* shove the headers direct into r->headers_out */
|
||||
- ap_proxy_read_headers(r, backend->r, buffer, response_field_size,
|
||||
- origin, &pread_len);
|
||||
+ rc = ap_proxy_read_headers(r, backend->r, buffer, response_field_size,
|
||||
+ origin, &pread_len);
|
||||
|
||||
- if (r->headers_out == NULL) {
|
||||
+ if (rc != APR_SUCCESS || r->headers_out == NULL) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01106)
|
||||
"bad HTTP/%d.%d header returned by %s (%s)",
|
||||
major, minor, r->uri, r->method);
|
||||
diff --git a/server/protocol.c b/server/protocol.c
|
||||
index 7adc7f75c10..6f9540ad1de 100644
|
||||
--- a/server/protocol.c
|
||||
+++ b/server/protocol.c
|
||||
@@ -508,6 +508,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
||||
/* PR#43039: We shouldn't accept NULL bytes within the line */
|
||||
bytes_handled = strlen(*s);
|
||||
if (bytes_handled < *read) {
|
||||
+ ap_log_data(APLOG_MARK, APLOG_DEBUG, ap_server_conf,
|
||||
+ "NULL bytes in header", *s, *read, 0);
|
||||
*read = bytes_handled;
|
||||
if (rv == APR_SUCCESS) {
|
||||
rv = APR_EINVAL;
|
|
@ -0,0 +1,586 @@
|
|||
diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en
|
||||
index 815ec72..2b8ed35 100644
|
||||
--- a/docs/manual/mod/mod_rewrite.html.en
|
||||
+++ b/docs/manual/mod/mod_rewrite.html.en
|
||||
@@ -1265,7 +1265,17 @@ cannot use <code>$N</code> in the substitution string!
|
||||
<td>B</td>
|
||||
<td>Escape non-alphanumeric characters in backreferences <em>before</em>
|
||||
applying the transformation. <em><a href="../rewrite/flags.html#flag_b">details ...</a></em></td>
|
||||
- </tr>
|
||||
+ </tr>
|
||||
+<tr class="odd">
|
||||
+ <td>BCTLS</td>
|
||||
+ <td>Like [B], but only escape control characters and spaces.
|
||||
+ <em><a href="../rewrite/flags.html#flag_bctls">details ...</a></em></td>
|
||||
+</tr>
|
||||
+ <tr>
|
||||
+ <td>BNE</td>
|
||||
+ <td>Characters of [B] or [BCTLS] which should <strong>not</strong> be escaped.
|
||||
+ <em><a href="../rewrite/flags.html#flag_bne">details ...</a></em></td>
|
||||
+ </tr>
|
||||
<tr class="odd">
|
||||
<td>backrefnoplus|BNP</td>
|
||||
<td>If backreferences are being escaped, spaces should be escaped to
|
||||
diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en
|
||||
index 80d0759..734809a 100644
|
||||
--- a/docs/manual/rewrite/flags.html.en
|
||||
+++ b/docs/manual/rewrite/flags.html.en
|
||||
@@ -85,10 +85,6 @@ of how you might use them.</p>
|
||||
<h2><a name="flag_b" id="flag_b">B (escape backreferences)</a></h2>
|
||||
<p>The [B] flag instructs <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> to escape non-alphanumeric
|
||||
characters before applying the transformation.</p>
|
||||
-<p>In 2.4.26 and later, you can limit the escaping to specific characters
|
||||
-in backreferences by listing them: <code>[B=#?;]</code>. Note: The space
|
||||
-character can be used in the list of characters to escape, but it cannot be
|
||||
-the last character in the list.</p>
|
||||
|
||||
<p><code>mod_rewrite</code> has to unescape URLs before mapping them,
|
||||
so backreferences are unescaped at the time they are applied.
|
||||
@@ -120,6 +116,20 @@ when the backend may break if presented with an unescaped URL.</p>
|
||||
|
||||
<p>An alternative to this flag is using a <code class="directive"><a href="../mod/mod_rewrite.html#rewritecond">RewriteCond</a></code> to capture against %{THE_REQUEST} which will capture
|
||||
strings in the encoded form.</p>
|
||||
+
|
||||
+<p>In 2.4.26 and later, you can limit the escaping to specific characters
|
||||
+in backreferences by listing them: <code>[B=#?;]</code>. Note: The space
|
||||
+character can be used in the list of characters to escape, but you must quote
|
||||
+the entire third argument of <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code>
|
||||
+and the space must not be the last character in the list.</p>
|
||||
+
|
||||
+<pre class="prettyprint lang-config"># Escape spaces and question marks. The quotes around the final argument
|
||||
+# are required when a space is included.
|
||||
+RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B= ?]"</pre>
|
||||
+
|
||||
+<p>To limit the characters escaped this way, see <a href="#flag_bne">#flag_bne</a>
|
||||
+and <a href="#flag_bctls">#flag_bctls</a></p>
|
||||
+
|
||||
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
||||
<div class="section">
|
||||
<h2><a name="flag_bnp" id="flag_bnp">BNP|backrefnoplus (don't escape space to +)</a></h2>
|
||||
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
|
||||
index 38dbb24..b71c67c 100644
|
||||
--- a/modules/mappers/mod_rewrite.c
|
||||
+++ b/modules/mappers/mod_rewrite.c
|
||||
@@ -101,6 +101,8 @@
|
||||
#include "mod_rewrite.h"
|
||||
#include "ap_expr.h"
|
||||
|
||||
+#include "test_char.h"
|
||||
+
|
||||
static ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL;
|
||||
static void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL;
|
||||
static const char* really_last_key = "rewrite_really_last";
|
||||
@@ -168,6 +170,8 @@ static const char* really_last_key = "rewrite_really_last";
|
||||
#define RULEFLAG_END (1<<17)
|
||||
#define RULEFLAG_ESCAPENOPLUS (1<<18)
|
||||
#define RULEFLAG_QSLAST (1<<19)
|
||||
+#define RULEFLAG_QSNONE (1<<20) /* programattic only */
|
||||
+#define RULEFLAG_ESCAPECTLS (1<<21)
|
||||
|
||||
/* return code of the rewrite rule
|
||||
* the result may be escaped - or not
|
||||
@@ -321,7 +325,8 @@ typedef struct {
|
||||
data_item *cookie; /* added cookies */
|
||||
int skip; /* number of next rules to skip */
|
||||
int maxrounds; /* limit on number of loops with N flag */
|
||||
- char *escapes; /* specific backref escapes */
|
||||
+ const char *escapes; /* specific backref escapes */
|
||||
+ const char *noescapes; /* specific backref chars not to escape */
|
||||
} rewriterule_entry;
|
||||
|
||||
typedef struct {
|
||||
@@ -422,7 +427,9 @@ static const char *rewritemap_mutex_type = "rewrite-map";
|
||||
/* Optional functions imported from mod_ssl when loaded: */
|
||||
static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL;
|
||||
static APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL;
|
||||
-static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus);
|
||||
+static char *escape_backref(apr_pool_t *p, const char *path,
|
||||
+ const char *escapeme, const char *noescapeme,
|
||||
+ int flags);
|
||||
|
||||
/*
|
||||
* +-------------------------------------------------------+
|
||||
@@ -645,18 +652,26 @@ static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
|
||||
return where;
|
||||
}
|
||||
|
||||
+
|
||||
/*
|
||||
* Escapes a backreference in a similar way as php's urlencode does.
|
||||
* Based on ap_os_escape_path in server/util.c
|
||||
*/
|
||||
-static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus) {
|
||||
- char *copy = apr_palloc(p, 3 * strlen(path) + 3);
|
||||
+static char *escape_backref(apr_pool_t *p, const char *path,
|
||||
+ const char *escapeme, const char *noescapeme,
|
||||
+ int flags)
|
||||
+{
|
||||
+ char *copy = apr_palloc(p, 3 * strlen(path) + 1);
|
||||
const unsigned char *s = (const unsigned char *)path;
|
||||
unsigned char *d = (unsigned char *)copy;
|
||||
- unsigned c;
|
||||
+ int noplus = (flags & RULEFLAG_ESCAPENOPLUS) != 0;
|
||||
+ int ctls = (flags & RULEFLAG_ESCAPECTLS) != 0;
|
||||
+ unsigned char c;
|
||||
|
||||
while ((c = *s)) {
|
||||
- if (!escapeme) {
|
||||
+ if (((ctls ? !TEST_CHAR(c, T_VCHAR_OBSTEXT) : !escapeme)
|
||||
+ || (escapeme && ap_strchr_c(escapeme, c)))
|
||||
+ && (!noescapeme || !ap_strchr_c(noescapeme, c))) {
|
||||
if (apr_isalnum(c) || c == '_') {
|
||||
*d++ = c;
|
||||
}
|
||||
@@ -667,23 +682,8 @@ static char *escape_backref(apr_pool_t *p, const char *path, const char *escapem
|
||||
d = c2x(c, '%', d);
|
||||
}
|
||||
}
|
||||
- else {
|
||||
- const char *esc = escapeme;
|
||||
- while (*esc) {
|
||||
- if (c == *esc) {
|
||||
- if (c == ' ' && !noplus) {
|
||||
- *d++ = '+';
|
||||
- }
|
||||
- else {
|
||||
- d = c2x(c, '%', d);
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
- ++esc;
|
||||
- }
|
||||
- if (!*esc) {
|
||||
- *d++ = c;
|
||||
- }
|
||||
+ else {
|
||||
+ *d++ = c;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
@@ -761,15 +761,24 @@ static char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme)
|
||||
ap_escape_uri(p, cp), NULL);
|
||||
}
|
||||
|
||||
+
|
||||
/*
|
||||
* split out a QUERY_STRING part from
|
||||
* the current URI string
|
||||
*/
|
||||
-static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
|
||||
- int qslast)
|
||||
+static void splitout_queryargs(request_rec *r, int flags)
|
||||
{
|
||||
char *q;
|
||||
int split;
|
||||
+ int qsappend = flags & RULEFLAG_QSAPPEND;
|
||||
+ int qsdiscard = flags & RULEFLAG_QSDISCARD;
|
||||
+ int qslast = flags & RULEFLAG_QSLAST;
|
||||
+
|
||||
+ if (flags & RULEFLAG_QSNONE) {
|
||||
+ rewritelog((r, 2, NULL, "discarding query string, no parse from substitution"));
|
||||
+ r->args = NULL;
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
/* don't touch, unless it's a scheme for which a query string makes sense.
|
||||
* See RFC 1738 and RFC 2368.
|
||||
@@ -794,7 +803,7 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
|
||||
olduri = apr_pstrdup(r->pool, r->filename);
|
||||
*q++ = '\0';
|
||||
if (qsappend) {
|
||||
- if (*q) {
|
||||
+ if (*q) {
|
||||
r->args = apr_pstrcat(r->pool, q, "&" , r->args, NULL);
|
||||
}
|
||||
}
|
||||
@@ -802,9 +811,9 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
|
||||
r->args = apr_pstrdup(r->pool, q);
|
||||
}
|
||||
|
||||
- if (r->args) {
|
||||
+ if (r->args) {
|
||||
len = strlen(r->args);
|
||||
-
|
||||
+
|
||||
if (!len) {
|
||||
r->args = NULL;
|
||||
}
|
||||
@@ -2436,7 +2445,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
|
||||
/* escape the backreference */
|
||||
char *tmp2, *tmp;
|
||||
tmp = apr_pstrmemdup(pool, bri->source + bri->regmatch[n].rm_so, span);
|
||||
- tmp2 = escape_backref(pool, tmp, entry->escapes, entry->flags & RULEFLAG_ESCAPENOPLUS);
|
||||
+ tmp2 = escape_backref(pool, tmp, entry->escapes, entry->noescapes,
|
||||
+ entry->flags);
|
||||
rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'",
|
||||
tmp, tmp2));
|
||||
|
||||
@@ -2733,7 +2743,7 @@ static apr_status_t rewritelock_remove(void *data)
|
||||
* XXX: what an inclined parser. Seems we have to leave it so
|
||||
* for backwards compat. *sigh*
|
||||
*/
|
||||
-static int parseargline(char *str, char **a1, char **a2, char **a3)
|
||||
+static int parseargline(char *str, char **a1, char **a2, char **a2_end, char **a3)
|
||||
{
|
||||
char quote;
|
||||
|
||||
@@ -2784,8 +2794,10 @@ static int parseargline(char *str, char **a1, char **a2, char **a3)
|
||||
|
||||
if (!*str) {
|
||||
*a3 = NULL; /* 3rd argument is optional */
|
||||
+ *a2_end = str;
|
||||
return 0;
|
||||
}
|
||||
+ *a2_end = str;
|
||||
*str++ = '\0';
|
||||
|
||||
while (apr_isspace(*str)) {
|
||||
@@ -3323,7 +3335,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
|
||||
rewrite_server_conf *sconf;
|
||||
rewritecond_entry *newcond;
|
||||
ap_regex_t *regexp;
|
||||
- char *a1 = NULL, *a2 = NULL, *a3 = NULL;
|
||||
+ char *a1 = NULL, *a2 = NULL, *a2_end, *a3 = NULL;
|
||||
const char *err;
|
||||
|
||||
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
|
||||
@@ -3341,7 +3353,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
|
||||
* of the argument line. So we can use a1 .. a3 without
|
||||
* copying them again.
|
||||
*/
|
||||
- if (parseargline(str, &a1, &a2, &a3)) {
|
||||
+ if (parseargline(str, &a1, &a2, &a2_end, &a3)) {
|
||||
return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str,
|
||||
"'", NULL);
|
||||
}
|
||||
@@ -3500,13 +3512,24 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
|
||||
case 'B':
|
||||
if (!*key || !strcasecmp(key, "ackrefescaping")) {
|
||||
cfg->flags |= RULEFLAG_ESCAPEBACKREF;
|
||||
- if (val && *val) {
|
||||
+ if (val && *val) {
|
||||
cfg->escapes = val;
|
||||
}
|
||||
}
|
||||
+ else if (!strcasecmp(key, "NE")) {
|
||||
+ if (val && *val) {
|
||||
+ cfg->noescapes = val;
|
||||
+ }
|
||||
+ else {
|
||||
+ return "flag 'BNE' wants a list of characters (i.e. [BNE=...])";
|
||||
+ }
|
||||
+ }
|
||||
else if (!strcasecmp(key, "NP") || !strcasecmp(key, "ackrefernoplus")) {
|
||||
cfg->flags |= RULEFLAG_ESCAPENOPLUS;
|
||||
}
|
||||
+ else if (!strcasecmp(key, "CTLS")) {
|
||||
+ cfg->flags |= RULEFLAG_ESCAPECTLS|RULEFLAG_ESCAPEBACKREF;
|
||||
+ }
|
||||
else {
|
||||
++error;
|
||||
}
|
||||
@@ -3749,7 +3772,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
|
||||
rewrite_server_conf *sconf;
|
||||
rewriterule_entry *newrule;
|
||||
ap_regex_t *regexp;
|
||||
- char *a1 = NULL, *a2 = NULL, *a3 = NULL;
|
||||
+ char *a1 = NULL, *a2 = NULL, *a2_end, *a3 = NULL;
|
||||
const char *err;
|
||||
|
||||
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
|
||||
@@ -3763,12 +3786,11 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
|
||||
}
|
||||
|
||||
/* parse the argument line ourself */
|
||||
- if (parseargline(str, &a1, &a2, &a3)) {
|
||||
+ if (parseargline(str, &a1, &a2, &a2_end, &a3)) {
|
||||
return apr_pstrcat(cmd->pool, "RewriteRule: bad argument line '", str,
|
||||
"'", NULL);
|
||||
}
|
||||
|
||||
- /* arg3: optional flags field */
|
||||
newrule->forced_mimetype = NULL;
|
||||
newrule->forced_handler = NULL;
|
||||
newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY;
|
||||
@@ -3777,6 +3799,9 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
|
||||
newrule->cookie = NULL;
|
||||
newrule->skip = 0;
|
||||
newrule->maxrounds = REWRITE_MAX_ROUNDS;
|
||||
+ newrule->escapes = newrule->noescapes = NULL;
|
||||
+
|
||||
+ /* arg3: optional flags field */
|
||||
if (a3 != NULL) {
|
||||
if ((err = cmd_parseflagfield(cmd->pool, newrule, a3,
|
||||
cmd_rewriterule_setflag)) != NULL) {
|
||||
@@ -3810,6 +3835,17 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
|
||||
newrule->flags |= RULEFLAG_NOSUB;
|
||||
}
|
||||
|
||||
+ if (*(a2_end-1) == '?') {
|
||||
+ /* a literal ? at the end of the unsubstituted rewrite rule */
|
||||
+ newrule->flags |= RULEFLAG_QSNONE;
|
||||
+ *(a2_end-1) = '\0'; /* trailing ? has done its job */
|
||||
+ }
|
||||
+ else if (newrule->flags & RULEFLAG_QSDISCARD) {
|
||||
+ if (NULL == ap_strchr(newrule->output, '?')) {
|
||||
+ newrule->flags |= RULEFLAG_QSNONE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* now, if the server or per-dir config holds an
|
||||
* array of RewriteCond entries, we take it for us
|
||||
* and clear the array
|
||||
@@ -4215,9 +4251,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
|
||||
r->path_info = NULL;
|
||||
}
|
||||
|
||||
- splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND,
|
||||
- p->flags & RULEFLAG_QSDISCARD,
|
||||
- p->flags & RULEFLAG_QSLAST);
|
||||
+ splitout_queryargs(r, p->flags);
|
||||
|
||||
/* Add the previously stripped per-directory location prefix, unless
|
||||
* (1) it's an absolute URL path and
|
||||
@@ -4696,8 +4730,25 @@ static int hook_uri2file(request_rec *r)
|
||||
}
|
||||
|
||||
if (rulestatus) {
|
||||
- unsigned skip;
|
||||
- apr_size_t flen;
|
||||
+ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
|
||||
+ apr_size_t flen = r->filename ? strlen(r->filename) : 0;
|
||||
+ int to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0);
|
||||
+ int will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE);
|
||||
+
|
||||
+ if (r->args
|
||||
+ && !will_escape
|
||||
+ && *(ap_scan_vchar_obstext(r->args))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ * Correct encoding was missed and we're not going to escape
|
||||
+ * it before returning.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10410)
|
||||
+ "Rewritten query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
|
||||
if (ACTION_STATUS == rulestatus) {
|
||||
int n = r->status;
|
||||
@@ -4706,8 +4757,7 @@ static int hook_uri2file(request_rec *r)
|
||||
return n;
|
||||
}
|
||||
|
||||
- flen = r->filename ? strlen(r->filename) : 0;
|
||||
- if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
|
||||
+ if (to_proxyreq) {
|
||||
/* it should be go on as an internal proxy request */
|
||||
|
||||
/* check if the proxy module is enabled, so
|
||||
@@ -4749,7 +4799,7 @@ static int hook_uri2file(request_rec *r)
|
||||
r->filename));
|
||||
return OK;
|
||||
}
|
||||
- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) {
|
||||
+ else if (skip_absolute > 0) {
|
||||
int n;
|
||||
|
||||
/* it was finally rewritten to a remote URL */
|
||||
@@ -4757,7 +4807,7 @@ static int hook_uri2file(request_rec *r)
|
||||
if (rulestatus != ACTION_NOESCAPE) {
|
||||
rewritelog((r, 1, NULL, "escaping %s for redirect",
|
||||
r->filename));
|
||||
- r->filename = escape_absolute_uri(r->pool, r->filename, skip);
|
||||
+ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute);
|
||||
}
|
||||
|
||||
/* append the QUERY_STRING part */
|
||||
@@ -4981,7 +5031,26 @@ static int hook_fixup(request_rec *r)
|
||||
*/
|
||||
rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
|
||||
if (rulestatus) {
|
||||
- unsigned skip;
|
||||
+ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
|
||||
+ int to_proxyreq = 0;
|
||||
+ int will_escape = 0;
|
||||
+
|
||||
+ l = strlen(r->filename);
|
||||
+ to_proxyreq = l > 6 && strncmp(r->filename, "proxy:", 6) == 0;
|
||||
+ will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE);
|
||||
+
|
||||
+ if (r->args
|
||||
+ && !will_escape
|
||||
+ && *(ap_scan_vchar_obstext(r->args))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10411)
|
||||
+ "Rewritten query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
|
||||
if (ACTION_STATUS == rulestatus) {
|
||||
int n = r->status;
|
||||
@@ -4990,8 +5059,7 @@ static int hook_fixup(request_rec *r)
|
||||
return n;
|
||||
}
|
||||
|
||||
- l = strlen(r->filename);
|
||||
- if (l > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
|
||||
+ if (to_proxyreq) {
|
||||
/* it should go on as an internal proxy request */
|
||||
|
||||
/* make sure the QUERY_STRING and
|
||||
@@ -5015,7 +5083,7 @@ static int hook_fixup(request_rec *r)
|
||||
"%s [OK]", r->filename));
|
||||
return OK;
|
||||
}
|
||||
- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) {
|
||||
+ else if (skip_absolute > 0) {
|
||||
/* it was finally rewritten to a remote URL */
|
||||
|
||||
/* because we are in a per-dir context
|
||||
@@ -5024,7 +5092,7 @@ static int hook_fixup(request_rec *r)
|
||||
*/
|
||||
if (dconf->baseurl != NULL) {
|
||||
/* skip 'scheme://' */
|
||||
- cp = r->filename + skip;
|
||||
+ cp = r->filename + skip_absolute;
|
||||
|
||||
if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) {
|
||||
rewritelog((r, 2, dconf->directory,
|
||||
@@ -5069,7 +5137,7 @@ static int hook_fixup(request_rec *r)
|
||||
if (rulestatus != ACTION_NOESCAPE) {
|
||||
rewritelog((r, 1, dconf->directory, "escaping %s for redirect",
|
||||
r->filename));
|
||||
- r->filename = escape_absolute_uri(r->pool, r->filename, skip);
|
||||
+ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute);
|
||||
}
|
||||
|
||||
/* append the QUERY_STRING part */
|
||||
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
|
||||
index cbb0872..873ccf1 100644
|
||||
--- a/modules/proxy/mod_proxy_ajp.c
|
||||
+++ b/modules/proxy/mod_proxy_ajp.c
|
||||
@@ -69,6 +69,16 @@ static int proxy_ajp_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
|
||||
r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10406)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
if (path == NULL)
|
||||
return HTTP_BAD_REQUEST;
|
||||
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
|
||||
index 3a28038..c599e1a 100644
|
||||
--- a/modules/proxy/mod_proxy_balancer.c
|
||||
+++ b/modules/proxy/mod_proxy_balancer.c
|
||||
@@ -106,6 +106,16 @@ static int proxy_balancer_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
|
||||
r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10407)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
if (path == NULL)
|
||||
return HTTP_BAD_REQUEST;
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index 7573638..fe7b322 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -90,6 +90,16 @@ static int proxy_http_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url),
|
||||
enc_path, 0, r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10408)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
break;
|
||||
case PROXYREQ_PROXY:
|
||||
diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c
|
||||
index e005a94..f5e27d9 100644
|
||||
--- a/modules/proxy/mod_proxy_wstunnel.c
|
||||
+++ b/modules/proxy/mod_proxy_wstunnel.c
|
||||
@@ -77,6 +77,16 @@ static int proxy_wstunnel_canon(request_rec *r, char *url)
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
|
||||
r->proxyreq);
|
||||
search = r->args;
|
||||
+ if (search && *(ap_scan_vchar_obstext(search))) {
|
||||
+ /*
|
||||
+ * We have a raw control character or a ' ' in r->args.
|
||||
+ * Correct encoding was missed.
|
||||
+ */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10409)
|
||||
+ "To be forwarded query string contains control "
|
||||
+ "characters or spaces");
|
||||
+ return HTTP_FORBIDDEN;
|
||||
+ }
|
||||
}
|
||||
if (path == NULL)
|
||||
return HTTP_BAD_REQUEST;
|
||||
diff --git a/server/gen_test_char.c b/server/gen_test_char.c
|
||||
index 48ae6f4..6a153a3 100644
|
||||
--- a/server/gen_test_char.c
|
||||
+++ b/server/gen_test_char.c
|
||||
@@ -169,5 +169,15 @@ int main(int argc, char *argv[])
|
||||
|
||||
printf("\n};\n");
|
||||
|
||||
+
|
||||
+ printf(
|
||||
+ "/* we assume the folks using this ensure 0 <= c < 256... which means\n"
|
||||
+ " * you need a cast to (unsigned char) first, you can't just plug a\n"
|
||||
+ " * char in here and get it to work, because if char is signed then it\n"
|
||||
+ " * will first be sign extended.\n"
|
||||
+ " */\n"
|
||||
+ "#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))\n"
|
||||
+ );
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
diff --git a/server/util.c b/server/util.c
|
||||
index 45051b7..9d897d4 100644
|
||||
--- a/server/util.c
|
||||
+++ b/server/util.c
|
||||
@@ -74,13 +74,6 @@
|
||||
*/
|
||||
#include "test_char.h"
|
||||
|
||||
-/* we assume the folks using this ensure 0 <= c < 256... which means
|
||||
- * you need a cast to (unsigned char) first, you can't just plug a
|
||||
- * char in here and get it to work, because if char is signed then it
|
||||
- * will first be sign extended.
|
||||
- */
|
||||
-#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))
|
||||
-
|
||||
/* Win32/NetWare/OS2 need to check for both forward and back slashes
|
||||
* in ap_getparents() and ap_escape_url.
|
||||
*/
|
|
@ -0,0 +1,89 @@
|
|||
diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
|
||||
index 9dcbed1..a1b564d 100644
|
||||
--- a/modules/proxy/mod_proxy_uwsgi.c
|
||||
+++ b/modules/proxy/mod_proxy_uwsgi.c
|
||||
@@ -304,18 +304,16 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
|
||||
pass_bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
len = ap_getline(buffer, sizeof(buffer), rp, 1);
|
||||
-
|
||||
if (len <= 0) {
|
||||
- /* oops */
|
||||
+ /* invalid or empty */
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
-
|
||||
backend->worker->s->read += len;
|
||||
-
|
||||
- if (len >= sizeof(buffer) - 1) {
|
||||
- /* oops */
|
||||
+ if ((apr_size_t)len >= sizeof(buffer)) {
|
||||
+ /* too long */
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
+
|
||||
/* Position of http status code */
|
||||
if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
|
||||
status_start = 9;
|
||||
@@ -324,8 +322,8 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
|
||||
status_start = 7;
|
||||
}
|
||||
else {
|
||||
- /* oops */
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ /* not HTTP */
|
||||
+ return HTTP_BAD_GATEWAY;
|
||||
}
|
||||
status_end = status_start + 3;
|
||||
|
||||
@@ -345,21 +343,44 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
|
||||
}
|
||||
r->status_line = apr_pstrdup(r->pool, &buffer[status_start]);
|
||||
|
||||
- /* start parsing headers */
|
||||
+ /* parse headers */
|
||||
while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
|
||||
+ if ((apr_size_t)len >= sizeof(buffer)) {
|
||||
+ /* too long */
|
||||
+ len = -1;
|
||||
+ break;
|
||||
+ }
|
||||
value = strchr(buffer, ':');
|
||||
- /* invalid header skip */
|
||||
- if (!value)
|
||||
- continue;
|
||||
- *value = '\0';
|
||||
- ++value;
|
||||
+ if (!value) {
|
||||
+ /* invalid header */
|
||||
+ len = -1;
|
||||
+ break;
|
||||
+ }
|
||||
+ *value++ = '\0';
|
||||
+ if (*ap_scan_http_token(buffer)) {
|
||||
+ /* invalid name */
|
||||
+ len = -1;
|
||||
+ break;
|
||||
+ }
|
||||
while (apr_isspace(*value))
|
||||
++value;
|
||||
for (end = &value[strlen(value) - 1];
|
||||
end > value && apr_isspace(*end); --end)
|
||||
*end = '\0';
|
||||
+ if (*ap_scan_http_field_content(value)) {
|
||||
+ /* invalid value */
|
||||
+ len = -1;
|
||||
+ break;
|
||||
+ }
|
||||
apr_table_add(r->headers_out, buffer, value);
|
||||
}
|
||||
+ if (len < 0) {
|
||||
+ /* Reset headers, but not to NULL because things below the chain expect
|
||||
+ * this to be non NULL e.g. the ap_content_length_filter.
|
||||
+ */
|
||||
+ r->headers_out = apr_table_make(r->pool, 1);
|
||||
+ return HTTP_BAD_GATEWAY;
|
||||
+ }
|
||||
|
||||
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
|
||||
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
|
|
@ -0,0 +1,11 @@
|
|||
--- a/modules/core/mod_macro.c 2023/10/16 06:19:16 1912992
|
||||
+++ b/modules/core/mod_macro.c 2023/10/16 06:38:32 1912993
|
||||
@@ -483,7 +483,7 @@
|
||||
for (i = 0; i < contents->nelts; i++) {
|
||||
const char *errmsg;
|
||||
/* copy the line and substitute macro parameters */
|
||||
- strncpy(line, ((char **) contents->elts)[i], MAX_STRING_LEN - 1);
|
||||
+ apr_cpystrn(line, ((char **) contents->elts)[i], MAX_STRING_LEN);
|
||||
errmsg = substitute_macro_args(line, MAX_STRING_LEN,
|
||||
macro, replacements, used);
|
||||
if (errmsg) {
|
|
@ -0,0 +1,92 @@
|
|||
commit 4c0e27d7bfbf46f14dfbd5d888e56c64ad8c8de5
|
||||
Author: Tomas Korbar <tkorbar@redhat.com>
|
||||
Date: Mon Sep 19 13:22:27 2022 +0200
|
||||
|
||||
Backport refactor of SNI support to httpd-2.4.37
|
||||
|
||||
diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c
|
||||
index a7e0dcd..31ccd32 100644
|
||||
--- a/modules/http2/mod_proxy_http2.c
|
||||
+++ b/modules/http2/mod_proxy_http2.c
|
||||
@@ -591,16 +591,6 @@ run_connect:
|
||||
}
|
||||
|
||||
if (!ctx->p_conn->data) {
|
||||
- /* New conection: set a note on the connection what CN is
|
||||
- * requested and what protocol we want */
|
||||
- if (ctx->p_conn->ssl_hostname) {
|
||||
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner,
|
||||
- "set SNI to %s for (%s)",
|
||||
- ctx->p_conn->ssl_hostname,
|
||||
- ctx->p_conn->hostname);
|
||||
- apr_table_setn(ctx->p_conn->connection->notes,
|
||||
- "proxy-request-hostname", ctx->p_conn->ssl_hostname);
|
||||
- }
|
||||
if (ctx->is_ssl) {
|
||||
apr_table_setn(ctx->p_conn->connection->notes,
|
||||
"proxy-request-alpn-protos", "h2");
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index 1b7bb81..c1c591a 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -2111,19 +2111,6 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
|
||||
req->origin->keepalive = AP_CONN_CLOSE;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * On SSL connections set a note on the connection what CN is
|
||||
- * requested, such that mod_ssl can check if it is requested to do
|
||||
- * so.
|
||||
- *
|
||||
- * https://github.com/apache/httpd/commit/7d272e2628b4ae05f68cdc74b070707250896a34
|
||||
- */
|
||||
- if (backend->ssl_hostname) {
|
||||
- apr_table_setn(backend->connection->notes,
|
||||
- "proxy-request-hostname",
|
||||
- backend->ssl_hostname);
|
||||
- }
|
||||
-
|
||||
/* Step Four: Send the Request
|
||||
* On the off-chance that we forced a 100-Continue as a
|
||||
* kinda HTTP ping test, allow for retries
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index ec9a414..805820d 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -3261,6 +3261,16 @@ static int proxy_connection_create(const char *proxy_function,
|
||||
backend_addr, conn->hostname);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
+ if (conn->ssl_hostname) {
|
||||
+ /* Set a note on the connection about what CN is requested,
|
||||
+ * such that mod_ssl can check if it is requested to do so.
|
||||
+ */
|
||||
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, conn->connection,
|
||||
+ "%s: set SNI to %s for (%s)", proxy_function,
|
||||
+ conn->ssl_hostname, conn->hostname);
|
||||
+ apr_table_setn(conn->connection->notes, "proxy-request-hostname",
|
||||
+ conn->ssl_hostname);
|
||||
+ }
|
||||
}
|
||||
else {
|
||||
/* TODO: See if this will break FTP */
|
||||
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
|
||||
index 4e3875a..9b4280c 100644
|
||||
--- a/modules/ssl/ssl_engine_io.c
|
||||
+++ b/modules/ssl/ssl_engine_io.c
|
||||
@@ -1273,7 +1273,6 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
|
||||
((dc->proxy->ssl_check_peer_cn != FALSE) ||
|
||||
(dc->proxy->ssl_check_peer_name == TRUE)) &&
|
||||
hostname_note) {
|
||||
- apr_table_unset(c->notes, "proxy-request-hostname");
|
||||
if (!cert
|
||||
|| modssl_X509_match_name(c->pool, cert, hostname_note,
|
||||
TRUE, server) == FALSE) {
|
||||
@@ -1290,7 +1289,6 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
|
||||
|
||||
hostname = ssl_var_lookup(NULL, server, c, NULL,
|
||||
"SSL_CLIENT_S_DN_CN");
|
||||
- apr_table_unset(c->notes, "proxy-request-hostname");
|
||||
|
||||
/* Do string match or simplest wildcard match if that
|
||||
* fails. */
|
|
@ -0,0 +1,199 @@
|
|||
diff --git a/modules/proxy/mod_proxy_hcheck.c b/modules/proxy/mod_proxy_hcheck.c
|
||||
index bd89779..d7c0a68 100644
|
||||
--- a/modules/proxy/mod_proxy_hcheck.c
|
||||
+++ b/modules/proxy/mod_proxy_hcheck.c
|
||||
@@ -33,7 +33,6 @@ module AP_MODULE_DECLARE_DATA proxy_hcheck_module;
|
||||
#endif
|
||||
#else
|
||||
#define HC_USE_THREADS 0
|
||||
-typedef void apr_thread_pool_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
@@ -73,7 +72,7 @@ typedef struct {
|
||||
proxy_balancer *balancer;
|
||||
proxy_worker *worker;
|
||||
proxy_worker *hc;
|
||||
- apr_time_t now;
|
||||
+ apr_time_t *now;
|
||||
} baton_t;
|
||||
|
||||
static void *hc_create_config(apr_pool_t *p, server_rec *s)
|
||||
@@ -89,7 +88,10 @@ static void *hc_create_config(apr_pool_t *p, server_rec *s)
|
||||
}
|
||||
|
||||
static ap_watchdog_t *watchdog;
|
||||
-static int tpsize = HC_THREADPOOL_SIZE;
|
||||
+#if HC_USE_THREADS
|
||||
+static apr_thread_pool_t *hctp;
|
||||
+static int tpsize;
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* This serves double duty by not only validating (and creating)
|
||||
@@ -825,29 +827,28 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b)
|
||||
server_rec *s = baton->ctx->s;
|
||||
proxy_worker *worker = baton->worker;
|
||||
proxy_worker *hc = baton->hc;
|
||||
- apr_time_t now = baton->now;
|
||||
+ apr_time_t now;
|
||||
apr_status_t rv;
|
||||
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(03256)
|
||||
"%sHealth checking %s", (thread ? "Threaded " : ""),
|
||||
worker->s->name);
|
||||
|
||||
- worker->s->updated = now;
|
||||
if (hc->s->method == TCP) {
|
||||
rv = hc_check_tcp(baton);
|
||||
}
|
||||
else {
|
||||
rv = hc_check_http(baton);
|
||||
}
|
||||
+
|
||||
+ now = apr_time_now();
|
||||
if (rv == APR_ENOTIMPL) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(03257)
|
||||
"Somehow tried to use unimplemented hcheck method: %d",
|
||||
(int)hc->s->method);
|
||||
- apr_pool_destroy(baton->ptemp);
|
||||
- return NULL;
|
||||
}
|
||||
/* what state are we in ? */
|
||||
- if (PROXY_WORKER_IS_HCFAILED(worker)) {
|
||||
+ else if (PROXY_WORKER_IS_HCFAILED(worker)) {
|
||||
if (rv == APR_SUCCESS) {
|
||||
worker->s->pcount += 1;
|
||||
if (worker->s->pcount >= worker->s->passes) {
|
||||
@@ -860,7 +861,8 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b)
|
||||
|
||||
}
|
||||
}
|
||||
- } else {
|
||||
+ }
|
||||
+ else {
|
||||
if (rv != APR_SUCCESS) {
|
||||
worker->s->error_time = now;
|
||||
worker->s->fcount += 1;
|
||||
@@ -873,7 +875,12 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b)
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (baton->now) {
|
||||
+ *baton->now = now;
|
||||
+ }
|
||||
apr_pool_destroy(baton->ptemp);
|
||||
+ worker->s->updated = now;
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -881,12 +888,10 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
- apr_time_t now = apr_time_now();
|
||||
proxy_balancer *balancer;
|
||||
sctx_t *ctx = (sctx_t *)data;
|
||||
server_rec *s = ctx->s;
|
||||
proxy_server_conf *conf;
|
||||
- static apr_thread_pool_t *hctp = NULL;
|
||||
|
||||
switch (state) {
|
||||
case AP_WATCHDOG_STATE_STARTING:
|
||||
@@ -913,7 +918,6 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
"Skipping apr_thread_pool_create()");
|
||||
hctp = NULL;
|
||||
}
|
||||
-
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -929,45 +933,53 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
ctx->s = s;
|
||||
for (i = 0; i < conf->balancers->nelts; i++, balancer++) {
|
||||
int n;
|
||||
+ apr_time_t now;
|
||||
proxy_worker **workers;
|
||||
proxy_worker *worker;
|
||||
/* Have any new balancers or workers been added dynamically? */
|
||||
ap_proxy_sync_balancer(balancer, s, conf);
|
||||
workers = (proxy_worker **)balancer->workers->elts;
|
||||
+ now = apr_time_now();
|
||||
for (n = 0; n < balancer->workers->nelts; n++) {
|
||||
worker = *workers;
|
||||
if (!PROXY_WORKER_IS(worker, PROXY_WORKER_STOPPED) &&
|
||||
- (worker->s->method != NONE) &&
|
||||
- (now > worker->s->updated + worker->s->interval)) {
|
||||
+ (worker->s->method != NONE) &&
|
||||
+ (worker->s->updated != 0) &&
|
||||
+ (now > worker->s->updated + worker->s->interval)) {
|
||||
baton_t *baton;
|
||||
apr_pool_t *ptemp;
|
||||
+
|
||||
ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
|
||||
"Checking %s worker: %s [%d] (%pp)", balancer->s->name,
|
||||
worker->s->name, worker->s->method, worker);
|
||||
|
||||
if ((rv = hc_init_worker(ctx, worker)) != APR_SUCCESS) {
|
||||
+ worker->s->updated = now;
|
||||
return rv;
|
||||
}
|
||||
- /* This pool must last the lifetime of the (possible) thread */
|
||||
+ worker->s->updated = 0;
|
||||
+
|
||||
+ /* This pool has the lifetime of the check */
|
||||
apr_pool_create(&ptemp, ctx->p);
|
||||
apr_pool_tag(ptemp, "hc_request");
|
||||
- baton = apr_palloc(ptemp, sizeof(baton_t));
|
||||
+ baton = apr_pcalloc(ptemp, sizeof(baton_t));
|
||||
baton->ctx = ctx;
|
||||
- baton->now = now;
|
||||
baton->balancer = balancer;
|
||||
baton->worker = worker;
|
||||
baton->ptemp = ptemp;
|
||||
baton->hc = hc_get_hcworker(ctx, worker, ptemp);
|
||||
-
|
||||
- if (!hctp) {
|
||||
- hc_check(NULL, baton);
|
||||
- }
|
||||
#if HC_USE_THREADS
|
||||
- else {
|
||||
- rv = apr_thread_pool_push(hctp, hc_check, (void *)baton,
|
||||
- APR_THREAD_TASK_PRIORITY_NORMAL, NULL);
|
||||
+ if (hctp) {
|
||||
+ apr_thread_pool_push(hctp, hc_check, (void *)baton,
|
||||
+ APR_THREAD_TASK_PRIORITY_NORMAL,
|
||||
+ NULL);
|
||||
}
|
||||
+ else
|
||||
#endif
|
||||
+ {
|
||||
+ baton->now = &now;
|
||||
+ hc_check(NULL, baton);
|
||||
+ }
|
||||
}
|
||||
workers++;
|
||||
}
|
||||
@@ -986,9 +998,9 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(03315)
|
||||
"apr_thread_pool_destroy() failed");
|
||||
}
|
||||
+ hctp = NULL;
|
||||
}
|
||||
#endif
|
||||
- hctp = NULL;
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
@@ -996,7 +1008,10 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
|
||||
static int hc_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
|
||||
apr_pool_t *ptemp)
|
||||
{
|
||||
+#if HC_USE_THREADS
|
||||
+ hctp = NULL;
|
||||
tpsize = HC_THREADPOOL_SIZE;
|
||||
+#endif
|
||||
return OK;
|
||||
}
|
||||
static int hc_post_config(apr_pool_t *p, apr_pool_t *plog,
|
|
@ -0,0 +1,170 @@
|
|||
commit 84e6f25f67de9a9bddefdcdbfee3f251fead647e
|
||||
Author: Tomas Korbar <tkorbar@redhat.com>
|
||||
Date: Thu Jul 20 14:41:33 2023 +0200
|
||||
|
||||
Fix duplicate presence of keys printed by mod_status
|
||||
|
||||
diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c
|
||||
index 5917953..5bada07 100644
|
||||
--- a/modules/generators/mod_status.c
|
||||
+++ b/modules/generators/mod_status.c
|
||||
@@ -186,7 +186,8 @@ static int status_handler(request_rec *r)
|
||||
apr_uint32_t up_time;
|
||||
ap_loadavg_t t;
|
||||
int j, i, res, written;
|
||||
- int ready;
|
||||
+ int idle;
|
||||
+ int graceful;
|
||||
int busy;
|
||||
unsigned long count;
|
||||
unsigned long lres, my_lres, conn_lres;
|
||||
@@ -203,6 +204,7 @@ static int status_handler(request_rec *r)
|
||||
char *stat_buffer;
|
||||
pid_t *pid_buffer, worker_pid;
|
||||
int *thread_idle_buffer = NULL;
|
||||
+ int *thread_graceful_buffer = NULL;
|
||||
int *thread_busy_buffer = NULL;
|
||||
clock_t tu, ts, tcu, tcs;
|
||||
clock_t gu, gs, gcu, gcs;
|
||||
@@ -231,7 +233,8 @@ static int status_handler(request_rec *r)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
- ready = 0;
|
||||
+ idle = 0;
|
||||
+ graceful = 0;
|
||||
busy = 0;
|
||||
count = 0;
|
||||
bcount = 0;
|
||||
@@ -250,6 +253,7 @@ static int status_handler(request_rec *r)
|
||||
stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
|
||||
if (is_async) {
|
||||
thread_idle_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
|
||||
+ thread_graceful_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
|
||||
thread_busy_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
|
||||
}
|
||||
|
||||
@@ -318,6 +322,7 @@ static int status_handler(request_rec *r)
|
||||
ps_record = ap_get_scoreboard_process(i);
|
||||
if (is_async) {
|
||||
thread_idle_buffer[i] = 0;
|
||||
+ thread_graceful_buffer[i] = 0;
|
||||
thread_busy_buffer[i] = 0;
|
||||
}
|
||||
for (j = 0; j < thread_limit; ++j) {
|
||||
@@ -336,18 +341,20 @@ static int status_handler(request_rec *r)
|
||||
&& ps_record->pid) {
|
||||
if (res == SERVER_READY) {
|
||||
if (ps_record->generation == mpm_generation)
|
||||
- ready++;
|
||||
+ idle++;
|
||||
if (is_async)
|
||||
thread_idle_buffer[i]++;
|
||||
}
|
||||
else if (res != SERVER_DEAD &&
|
||||
res != SERVER_STARTING &&
|
||||
res != SERVER_IDLE_KILL) {
|
||||
- busy++;
|
||||
- if (is_async) {
|
||||
- if (res == SERVER_GRACEFUL)
|
||||
- thread_idle_buffer[i]++;
|
||||
- else
|
||||
+ if (res == SERVER_GRACEFUL) {
|
||||
+ graceful++;
|
||||
+ if (is_async)
|
||||
+ thread_graceful_buffer[i]++;
|
||||
+ } else {
|
||||
+ busy++;
|
||||
+ if (is_async)
|
||||
thread_busy_buffer[i]++;
|
||||
}
|
||||
}
|
||||
@@ -548,10 +555,10 @@ static int status_handler(request_rec *r)
|
||||
} /* ap_extended_status */
|
||||
|
||||
if (!short_report)
|
||||
- ap_rprintf(r, "<dt>%d requests currently being processed, "
|
||||
- "%d idle workers</dt>\n", busy, ready);
|
||||
+ ap_rprintf(r, "<dt>%d requests currently being processed, %d workers gracefully restarting, "
|
||||
+ "%d idle workers</dt>\n", busy, graceful, idle);
|
||||
else
|
||||
- ap_rprintf(r, "BusyWorkers: %d\nIdleWorkers: %d\n", busy, ready);
|
||||
+ ap_rprintf(r, "BusyWorkers: %d\nGracefulWorkers: %d\nIdleWorkers: %d\n", busy, graceful, idle);
|
||||
|
||||
if (!short_report)
|
||||
ap_rputs("</dl>", r);
|
||||
@@ -559,11 +566,6 @@ static int status_handler(request_rec *r)
|
||||
if (is_async) {
|
||||
int write_completion = 0, lingering_close = 0, keep_alive = 0,
|
||||
connections = 0, stopping = 0, procs = 0;
|
||||
- /*
|
||||
- * These differ from 'busy' and 'ready' in how gracefully finishing
|
||||
- * threads are counted. XXX: How to make this clear in the html?
|
||||
- */
|
||||
- int busy_workers = 0, idle_workers = 0;
|
||||
if (!short_report)
|
||||
ap_rputs("\n\n<table rules=\"all\" cellpadding=\"1%\">\n"
|
||||
"<tr><th rowspan=\"2\">Slot</th>"
|
||||
@@ -573,7 +575,7 @@ static int status_handler(request_rec *r)
|
||||
"<th colspan=\"2\">Threads</th>"
|
||||
"<th colspan=\"3\">Async connections</th></tr>\n"
|
||||
"<tr><th>total</th><th>accepting</th>"
|
||||
- "<th>busy</th><th>idle</th>"
|
||||
+ "<th>busy</th><th>graceful</th><th>idle</th>"
|
||||
"<th>writing</th><th>keep-alive</th><th>closing</th></tr>\n", r);
|
||||
for (i = 0; i < server_limit; ++i) {
|
||||
ps_record = ap_get_scoreboard_process(i);
|
||||
@@ -582,8 +584,6 @@ static int status_handler(request_rec *r)
|
||||
write_completion += ps_record->write_completion;
|
||||
keep_alive += ps_record->keep_alive;
|
||||
lingering_close += ps_record->lingering_close;
|
||||
- busy_workers += thread_busy_buffer[i];
|
||||
- idle_workers += thread_idle_buffer[i];
|
||||
procs++;
|
||||
if (ps_record->quiescing) {
|
||||
stopping++;
|
||||
@@ -599,7 +599,7 @@ static int status_handler(request_rec *r)
|
||||
ap_rprintf(r, "<tr><td>%u</td><td>%" APR_PID_T_FMT "</td>"
|
||||
"<td>%s%s</td>"
|
||||
"<td>%u</td><td>%s</td>"
|
||||
- "<td>%u</td><td>%u</td>"
|
||||
+ "<td>%u</td><td>%u</td><td>%u</td>"
|
||||
"<td>%u</td><td>%u</td><td>%u</td>"
|
||||
"</tr>\n",
|
||||
i, ps_record->pid,
|
||||
@@ -607,6 +607,7 @@ static int status_handler(request_rec *r)
|
||||
ps_record->connections,
|
||||
ps_record->not_accepting ? "no" : "yes",
|
||||
thread_busy_buffer[i],
|
||||
+ thread_graceful_buffer[i],
|
||||
thread_idle_buffer[i],
|
||||
ps_record->write_completion,
|
||||
ps_record->keep_alive,
|
||||
@@ -618,25 +619,22 @@ static int status_handler(request_rec *r)
|
||||
ap_rprintf(r, "<tr><td>Sum</td>"
|
||||
"<td>%d</td><td>%d</td>"
|
||||
"<td>%d</td><td> </td>"
|
||||
- "<td>%d</td><td>%d</td>"
|
||||
+ "<td>%d</td><td>%d</td><td>%d</td>"
|
||||
"<td>%d</td><td>%d</td><td>%d</td>"
|
||||
"</tr>\n</table>\n",
|
||||
procs, stopping,
|
||||
connections,
|
||||
- busy_workers, idle_workers,
|
||||
+ busy, graceful, idle,
|
||||
write_completion, keep_alive, lingering_close);
|
||||
}
|
||||
else {
|
||||
ap_rprintf(r, "Processes: %d\n"
|
||||
"Stopping: %d\n"
|
||||
- "BusyWorkers: %d\n"
|
||||
- "IdleWorkers: %d\n"
|
||||
"ConnsTotal: %d\n"
|
||||
"ConnsAsyncWriting: %d\n"
|
||||
"ConnsAsyncKeepAlive: %d\n"
|
||||
"ConnsAsyncClosing: %d\n",
|
||||
procs, stopping,
|
||||
- busy_workers, idle_workers,
|
||||
connections,
|
||||
write_completion, keep_alive, lingering_close);
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
--- a/modules/dav/main/mod_dav.c
|
||||
+++ b/modules/dav/main/mod_dav.c
|
||||
@@ -557,6 +557,7 @@
|
||||
dav_begin_multistatus(bb, r, status, namespaces);
|
||||
|
||||
apr_pool_create(&subpool, r->pool);
|
||||
+ apr_pool_tag(subpool, "mod_dav-multistatus");
|
||||
|
||||
for (; first != NULL; first = first->next) {
|
||||
apr_pool_clear(subpool);
|
||||
@@ -1980,8 +1981,9 @@
|
||||
** Note: we cast to lose the "const". The propdb won't try to change
|
||||
** the resource, however, since we are opening readonly.
|
||||
*/
|
||||
- err = dav_open_propdb(ctx->r, ctx->w.lockdb, wres->resource, 1,
|
||||
- ctx->doc ? ctx->doc->namespaces : NULL, &propdb);
|
||||
+ err = dav_popen_propdb(ctx->scratchpool,
|
||||
+ ctx->r, ctx->w.lockdb, wres->resource, 1,
|
||||
+ ctx->doc ? ctx->doc->namespaces : NULL, &propdb);
|
||||
if (err != NULL) {
|
||||
/* ### do something with err! */
|
||||
|
||||
--- a/modules/dav/main/mod_dav.h
|
||||
+++ b/modules/dav/main/mod_dav.h
|
||||
@@ -1590,6 +1590,16 @@
|
||||
apr_array_header_t *ns_xlate,
|
||||
dav_propdb **propdb);
|
||||
|
||||
+DAV_DECLARE(dav_error *) dav_popen_propdb(
|
||||
+ apr_pool_t *p,
|
||||
+ request_rec *r,
|
||||
+ dav_lockdb *lockdb,
|
||||
+ const dav_resource *resource,
|
||||
+ int ro,
|
||||
+ apr_array_header_t *ns_xlate,
|
||||
+ dav_propdb **propdb);
|
||||
+
|
||||
+
|
||||
DAV_DECLARE(void) dav_close_propdb(dav_propdb *db);
|
||||
|
||||
DAV_DECLARE(dav_get_props_result) dav_get_props(
|
||||
--- a/modules/dav/main/props.c
|
||||
+++ b/modules/dav/main/props.c
|
||||
@@ -323,7 +323,7 @@
|
||||
{
|
||||
/* need to escape the uri that's in the resource struct because during
|
||||
* the property walker it's not encoded. */
|
||||
- const char *e_uri = ap_escape_uri(propdb->resource->pool,
|
||||
+ const char *e_uri = ap_escape_uri(propdb->p,
|
||||
propdb->resource->uri);
|
||||
|
||||
/* perform a "GET" on the resource's URI (note that the resource
|
||||
@@ -524,8 +524,21 @@
|
||||
apr_array_header_t * ns_xlate,
|
||||
dav_propdb **p_propdb)
|
||||
{
|
||||
- dav_propdb *propdb = apr_pcalloc(r->pool, sizeof(*propdb));
|
||||
+ return dav_popen_propdb(r->pool, r, lockdb, resource, ro, ns_xlate, p_propdb);
|
||||
+}
|
||||
|
||||
+DAV_DECLARE(dav_error *)dav_popen_propdb(apr_pool_t *p,
|
||||
+ request_rec *r, dav_lockdb *lockdb,
|
||||
+ const dav_resource *resource,
|
||||
+ int ro,
|
||||
+ apr_array_header_t * ns_xlate,
|
||||
+ dav_propdb **p_propdb)
|
||||
+{
|
||||
+ dav_propdb *propdb = NULL;
|
||||
+
|
||||
+ propdb = apr_pcalloc(p, sizeof(*propdb));
|
||||
+ propdb->p = p;
|
||||
+
|
||||
*p_propdb = NULL;
|
||||
|
||||
#if DAV_DEBUG
|
||||
@@ -537,7 +550,6 @@
|
||||
#endif
|
||||
|
||||
propdb->r = r;
|
||||
- apr_pool_create(&propdb->p, r->pool);
|
||||
propdb->resource = resource;
|
||||
propdb->ns_xlate = ns_xlate;
|
||||
|
||||
@@ -562,10 +574,10 @@
|
||||
(*propdb->db_hooks->close)(propdb->db);
|
||||
}
|
||||
|
||||
- /* Currently, mod_dav's pool usage doesn't allow clearing this pool. */
|
||||
-#if 0
|
||||
- apr_pool_destroy(propdb->p);
|
||||
-#endif
|
||||
+ if (propdb->subreq) {
|
||||
+ ap_destroy_sub_req(propdb->subreq);
|
||||
+ propdb->subreq = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb,
|
||||
@@ -739,7 +751,8 @@
|
||||
*/
|
||||
|
||||
if (elem->priv == NULL) {
|
||||
- elem->priv = apr_pcalloc(propdb->p, sizeof(*priv));
|
||||
+ /* elem->priv outlives propdb->p. Hence use the request pool */
|
||||
+ elem->priv = apr_pcalloc(propdb->r->pool, sizeof(*priv));
|
||||
}
|
||||
priv = elem->priv;
|
||||
|
|
@ -0,0 +1,849 @@
|
|||
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
|
||||
index fbbd508..8fcd26d 100644
|
||||
--- a/modules/proxy/mod_proxy.h
|
||||
+++ b/modules/proxy/mod_proxy.h
|
||||
@@ -1168,6 +1168,55 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
char **old_cl_val,
|
||||
char **old_te_val);
|
||||
|
||||
+/**
|
||||
+ * Prefetch the client request body (in memory), up to a limit.
|
||||
+ * Read what's in the client pipe. If nonblocking is set and read is EAGAIN,
|
||||
+ * pass a FLUSH bucket to the backend and read again in blocking mode.
|
||||
+ * @param r client request
|
||||
+ * @param backend backend connection
|
||||
+ * @param input_brigade input brigade to use/fill
|
||||
+ * @param block blocking or non-blocking mode
|
||||
+ * @param bytes_read number of bytes read
|
||||
+ * @param max_read maximum number of bytes to read
|
||||
+ * @return OK or HTTP_* error code
|
||||
+ * @note max_read is rounded up to APR_BUCKET_BUFF_SIZE
|
||||
+ */
|
||||
+PROXY_DECLARE(int) ap_proxy_prefetch_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_read_type_e block,
|
||||
+ apr_off_t *bytes_read,
|
||||
+ apr_off_t max_read);
|
||||
+
|
||||
+/**
|
||||
+ * Spool the client request body to memory, or disk above given limit.
|
||||
+ * @param r client request
|
||||
+ * @param backend backend connection
|
||||
+ * @param input_brigade input brigade to use/fill
|
||||
+ * @param bytes_spooled number of bytes spooled
|
||||
+ * @param max_mem_spool maximum number of in-memory bytes
|
||||
+ * @return OK or HTTP_* error code
|
||||
+ */
|
||||
+PROXY_DECLARE(int) ap_proxy_spool_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_off_t *bytes_spooled,
|
||||
+ apr_off_t max_mem_spool);
|
||||
+
|
||||
+/**
|
||||
+ * Read what's in the client pipe. If the read would block (EAGAIN),
|
||||
+ * pass a FLUSH bucket to the backend and read again in blocking mode.
|
||||
+ * @param r client request
|
||||
+ * @param backend backend connection
|
||||
+ * @param input_brigade brigade to use/fill
|
||||
+ * @param max_read maximum number of bytes to read
|
||||
+ * @return OK or HTTP_* error code
|
||||
+ */
|
||||
+PROXY_DECLARE(int) ap_proxy_read_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_off_t max_read);
|
||||
+
|
||||
/**
|
||||
* @param bucket_alloc bucket allocator
|
||||
* @param r request
|
||||
diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c
|
||||
index 2e97408..f9cf716 100644
|
||||
--- a/modules/proxy/mod_proxy_fcgi.c
|
||||
+++ b/modules/proxy/mod_proxy_fcgi.c
|
||||
@@ -521,7 +521,8 @@ static int handle_headers(request_rec *r, int *state,
|
||||
static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
|
||||
request_rec *r, apr_pool_t *setaside_pool,
|
||||
apr_uint16_t request_id, const char **err,
|
||||
- int *bad_request, int *has_responded)
|
||||
+ int *bad_request, int *has_responded,
|
||||
+ apr_bucket_brigade *input_brigade)
|
||||
{
|
||||
apr_bucket_brigade *ib, *ob;
|
||||
int seen_end_of_headers = 0, done = 0, ignore_body = 0;
|
||||
@@ -583,9 +584,26 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
|
||||
int last_stdin = 0;
|
||||
char *iobuf_cursor;
|
||||
|
||||
- rv = ap_get_brigade(r->input_filters, ib,
|
||||
- AP_MODE_READBYTES, APR_BLOCK_READ,
|
||||
- iobuf_size);
|
||||
+ if (APR_BRIGADE_EMPTY(input_brigade)) {
|
||||
+ rv = ap_get_brigade(r->input_filters, ib,
|
||||
+ AP_MODE_READBYTES, APR_BLOCK_READ,
|
||||
+ iobuf_size);
|
||||
+ }
|
||||
+ else {
|
||||
+ apr_bucket *e;
|
||||
+ APR_BRIGADE_CONCAT(ib, input_brigade);
|
||||
+ rv = apr_brigade_partition(ib, iobuf_size, &e);
|
||||
+ if (rv == APR_SUCCESS) {
|
||||
+ while (e != APR_BRIGADE_SENTINEL(ib)
|
||||
+ && APR_BUCKET_IS_METADATA(e)) {
|
||||
+ e = APR_BUCKET_NEXT(e);
|
||||
+ }
|
||||
+ apr_brigade_split_ex(ib, e, input_brigade);
|
||||
+ }
|
||||
+ else if (rv == APR_INCOMPLETE) {
|
||||
+ rv = APR_SUCCESS;
|
||||
+ }
|
||||
+ }
|
||||
if (rv != APR_SUCCESS) {
|
||||
*err = "reading input brigade";
|
||||
*bad_request = 1;
|
||||
@@ -924,7 +942,8 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r,
|
||||
conn_rec *origin,
|
||||
proxy_dir_conf *conf,
|
||||
apr_uri_t *uri,
|
||||
- char *url, char *server_portstr)
|
||||
+ char *url, char *server_portstr,
|
||||
+ apr_bucket_brigade *input_brigade)
|
||||
{
|
||||
/* Request IDs are arbitrary numbers that we assign to a
|
||||
* single request. This would allow multiplex/pipelining of
|
||||
@@ -960,7 +979,8 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r,
|
||||
|
||||
/* Step 3: Read records from the back end server and handle them. */
|
||||
rv = dispatch(conn, conf, r, temp_pool, request_id,
|
||||
- &err, &bad_request, &has_responded);
|
||||
+ &err, &bad_request, &has_responded,
|
||||
+ input_brigade);
|
||||
if (rv != APR_SUCCESS) {
|
||||
/* If the client aborted the connection during retrieval or (partially)
|
||||
* sending the response, don't return a HTTP_SERVICE_UNAVAILABLE, since
|
||||
@@ -996,6 +1016,8 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r,
|
||||
|
||||
#define FCGI_SCHEME "FCGI"
|
||||
|
||||
+#define MAX_MEM_SPOOL 16384
|
||||
+
|
||||
/*
|
||||
* This handles fcgi:(dest) URLs
|
||||
*/
|
||||
@@ -1008,6 +1030,8 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
|
||||
char server_portstr[32];
|
||||
conn_rec *origin = NULL;
|
||||
proxy_conn_rec *backend = NULL;
|
||||
+ apr_bucket_brigade *input_brigade;
|
||||
+ apr_off_t input_bytes = 0;
|
||||
apr_uri_t *uri;
|
||||
|
||||
proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
|
||||
@@ -1050,6 +1074,101 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
+ /* We possibly reuse input data prefetched in previous call(s), e.g. for a
|
||||
+ * balancer fallback scenario.
|
||||
+ */
|
||||
+ apr_pool_userdata_get((void **)&input_brigade, "proxy-fcgi-input", p);
|
||||
+ if (input_brigade == NULL) {
|
||||
+ const char *old_te = apr_table_get(r->headers_in, "Transfer-Encoding");
|
||||
+ const char *old_cl = NULL;
|
||||
+ if (old_te) {
|
||||
+ apr_table_unset(r->headers_in, "Content-Length");
|
||||
+ }
|
||||
+ else {
|
||||
+ old_cl = apr_table_get(r->headers_in, "Content-Length");
|
||||
+ }
|
||||
+
|
||||
+ input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
|
||||
+ apr_pool_userdata_setn(input_brigade, "proxy-fcgi-input", NULL, p);
|
||||
+
|
||||
+ /* Prefetch (nonlocking) the request body so to increase the chance
|
||||
+ * to get the whole (or enough) body and determine Content-Length vs
|
||||
+ * chunked or spooled. By doing this before connecting or reusing the
|
||||
+ * backend, we want to minimize the delay between this connection is
|
||||
+ * considered alive and the first bytes sent (should the client's link
|
||||
+ * be slow or some input filter retain the data). This is a best effort
|
||||
+ * to prevent the backend from closing (from under us) what it thinks is
|
||||
+ * an idle connection, hence to reduce to the minimum the unavoidable
|
||||
+ * local is_socket_connected() vs remote keepalive race condition.
|
||||
+ */
|
||||
+ status = ap_proxy_prefetch_input(r, backend, input_brigade,
|
||||
+ APR_NONBLOCK_READ, &input_bytes,
|
||||
+ MAX_MEM_SPOOL);
|
||||
+ if (status != OK) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * The request body is streamed by default, using either C-L or
|
||||
+ * chunked T-E, like this:
|
||||
+ *
|
||||
+ * The whole body (including no body) was received on prefetch, i.e.
|
||||
+ * the input brigade ends with EOS => C-L = input_bytes.
|
||||
+ *
|
||||
+ * C-L is known and reliable, i.e. only protocol filters in the input
|
||||
+ * chain thus none should change the body => use C-L from client.
|
||||
+ *
|
||||
+ * The administrator has not "proxy-sendcl" which prevents T-E => use
|
||||
+ * T-E and chunks.
|
||||
+ *
|
||||
+ * Otherwise we need to determine and set a content-length, so spool
|
||||
+ * the entire request body to memory/temporary file (MAX_MEM_SPOOL),
|
||||
+ * such that we finally know its length => C-L = input_bytes.
|
||||
+ */
|
||||
+ if (!APR_BRIGADE_EMPTY(input_brigade)
|
||||
+ && APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
|
||||
+ /* The whole thing fit, so our decision is trivial, use the input
|
||||
+ * bytes for the Content-Length. If we expected no body, and read
|
||||
+ * no body, do not set the Content-Length.
|
||||
+ */
|
||||
+ if (old_cl || old_te || input_bytes) {
|
||||
+ apr_table_setn(r->headers_in, "Content-Length",
|
||||
+ apr_off_t_toa(p, input_bytes));
|
||||
+ if (old_te) {
|
||||
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ else if (old_cl && r->input_filters == r->proto_input_filters) {
|
||||
+ /* Streaming is possible by preserving the existing C-L */
|
||||
+ }
|
||||
+ else if (!apr_table_get(r->subprocess_env, "proxy-sendcl")) {
|
||||
+ /* Streaming is possible using T-E: chunked */
|
||||
+ }
|
||||
+ else {
|
||||
+ /* No streaming, C-L is the only option so spool to memory/file */
|
||||
+ apr_bucket_brigade *tmp_bb;
|
||||
+ apr_off_t remaining_bytes = 0;
|
||||
+
|
||||
+ AP_DEBUG_ASSERT(MAX_MEM_SPOOL >= input_bytes);
|
||||
+ tmp_bb = apr_brigade_create(p, r->connection->bucket_alloc);
|
||||
+ status = ap_proxy_spool_input(r, backend, tmp_bb, &remaining_bytes,
|
||||
+ MAX_MEM_SPOOL - input_bytes);
|
||||
+ if (status != OK) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ APR_BRIGADE_CONCAT(input_brigade, tmp_bb);
|
||||
+ input_bytes += remaining_bytes;
|
||||
+
|
||||
+ apr_table_setn(r->headers_in, "Content-Length",
|
||||
+ apr_off_t_toa(p, input_bytes));
|
||||
+ if (old_te) {
|
||||
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* This scheme handler does not reuse connections by default, to
|
||||
* avoid tying up a fastcgi that isn't expecting to work on
|
||||
* parallel requests. But if the user went out of their way to
|
||||
@@ -1074,7 +1193,7 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
|
||||
|
||||
/* Step Three: Process the Request */
|
||||
status = fcgi_do_request(p, r, backend, origin, dconf, uri, url,
|
||||
- server_portstr);
|
||||
+ server_portstr, input_brigade);
|
||||
|
||||
cleanup:
|
||||
ap_proxy_release_connection(FCGI_SCHEME, backend, r->server);
|
||||
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
|
||||
index df10997..7f67f26 100644
|
||||
--- a/modules/proxy/mod_proxy_http.c
|
||||
+++ b/modules/proxy/mod_proxy_http.c
|
||||
@@ -266,50 +266,6 @@ typedef struct {
|
||||
prefetch_nonblocking:1;
|
||||
} proxy_http_req_t;
|
||||
|
||||
-/* Read what's in the client pipe. If nonblocking is set and read is EAGAIN,
|
||||
- * pass a FLUSH bucket to the backend and read again in blocking mode.
|
||||
- */
|
||||
-static int stream_reqbody_read(proxy_http_req_t *req, apr_bucket_brigade *bb,
|
||||
- int nonblocking)
|
||||
-{
|
||||
- request_rec *r = req->r;
|
||||
- proxy_conn_rec *p_conn = req->backend;
|
||||
- apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
|
||||
- apr_read_type_e block = nonblocking ? APR_NONBLOCK_READ : APR_BLOCK_READ;
|
||||
- apr_status_t status;
|
||||
- int rv;
|
||||
-
|
||||
- for (;;) {
|
||||
- status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
|
||||
- block, HUGE_STRING_LEN);
|
||||
- if (block == APR_BLOCK_READ
|
||||
- || (!APR_STATUS_IS_EAGAIN(status)
|
||||
- && (status != APR_SUCCESS || !APR_BRIGADE_EMPTY(bb)))) {
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- /* Flush and retry (blocking) */
|
||||
- apr_brigade_cleanup(bb);
|
||||
- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, bb, 1);
|
||||
- if (rv != OK) {
|
||||
- return rv;
|
||||
- }
|
||||
- block = APR_BLOCK_READ;
|
||||
- }
|
||||
-
|
||||
- if (status != APR_SUCCESS) {
|
||||
- conn_rec *c = r->connection;
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02608)
|
||||
- "read request body failed to %pI (%s)"
|
||||
- " from %s (%s)", p_conn->addr,
|
||||
- p_conn->hostname ? p_conn->hostname: "",
|
||||
- c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
- return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
|
||||
- }
|
||||
-
|
||||
- return OK;
|
||||
-}
|
||||
-
|
||||
static int stream_reqbody(proxy_http_req_t *req)
|
||||
{
|
||||
request_rec *r = req->r;
|
||||
@@ -328,7 +284,8 @@ static int stream_reqbody(proxy_http_req_t *req)
|
||||
do {
|
||||
if (APR_BRIGADE_EMPTY(input_brigade)
|
||||
&& APR_BRIGADE_EMPTY(header_brigade)) {
|
||||
- rv = stream_reqbody_read(req, input_brigade, 1);
|
||||
+ rv = ap_proxy_read_input(r, p_conn, input_brigade,
|
||||
+ HUGE_STRING_LEN);
|
||||
if (rv != OK) {
|
||||
return rv;
|
||||
}
|
||||
@@ -409,7 +366,7 @@ static int stream_reqbody(proxy_http_req_t *req)
|
||||
*/
|
||||
APR_BRIGADE_PREPEND(input_brigade, header_brigade);
|
||||
|
||||
- /* Flush here on EOS because we won't stream_reqbody_read() again */
|
||||
+ /* Flush here on EOS because we won't ap_proxy_read_input() again. */
|
||||
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin,
|
||||
input_brigade, seen_eos);
|
||||
if (rv != OK) {
|
||||
@@ -427,137 +384,6 @@ static int stream_reqbody(proxy_http_req_t *req)
|
||||
return OK;
|
||||
}
|
||||
|
||||
-static int spool_reqbody_cl(proxy_http_req_t *req, apr_off_t *bytes_spooled)
|
||||
-{
|
||||
- apr_pool_t *p = req->p;
|
||||
- request_rec *r = req->r;
|
||||
- int seen_eos = 0, rv = OK;
|
||||
- apr_status_t status = APR_SUCCESS;
|
||||
- apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
|
||||
- apr_bucket_brigade *input_brigade = req->input_brigade;
|
||||
- apr_bucket_brigade *body_brigade;
|
||||
- apr_bucket *e;
|
||||
- apr_off_t bytes, fsize = 0;
|
||||
- apr_file_t *tmpfile = NULL;
|
||||
- apr_off_t limit;
|
||||
-
|
||||
- body_brigade = apr_brigade_create(p, bucket_alloc);
|
||||
- *bytes_spooled = 0;
|
||||
-
|
||||
- limit = ap_get_limit_req_body(r);
|
||||
-
|
||||
- do {
|
||||
- if (APR_BRIGADE_EMPTY(input_brigade)) {
|
||||
- rv = stream_reqbody_read(req, input_brigade, 0);
|
||||
- if (rv != OK) {
|
||||
- return rv;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /* If this brigade contains EOS, either stop or remove it. */
|
||||
- if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
|
||||
- seen_eos = 1;
|
||||
- }
|
||||
-
|
||||
- apr_brigade_length(input_brigade, 1, &bytes);
|
||||
-
|
||||
- if (*bytes_spooled + bytes > MAX_MEM_SPOOL) {
|
||||
- /*
|
||||
- * LimitRequestBody does not affect Proxy requests (Should it?).
|
||||
- * Let it take effect if we decide to store the body in a
|
||||
- * temporary file on disk.
|
||||
- */
|
||||
- if (limit && (*bytes_spooled + bytes > limit)) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088)
|
||||
- "Request body is larger than the configured "
|
||||
- "limit of %" APR_OFF_T_FMT, limit);
|
||||
- return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
- }
|
||||
- /* can't spool any more in memory; write latest brigade to disk */
|
||||
- if (tmpfile == NULL) {
|
||||
- const char *temp_dir;
|
||||
- char *template;
|
||||
-
|
||||
- status = apr_temp_dir_get(&temp_dir, p);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01089)
|
||||
- "search for temporary directory failed");
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
- apr_filepath_merge(&template, temp_dir,
|
||||
- "modproxy.tmp.XXXXXX",
|
||||
- APR_FILEPATH_NATIVE, p);
|
||||
- status = apr_file_mktemp(&tmpfile, template, 0, p);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01090)
|
||||
- "creation of temporary file in directory "
|
||||
- "%s failed", temp_dir);
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
- }
|
||||
- for (e = APR_BRIGADE_FIRST(input_brigade);
|
||||
- e != APR_BRIGADE_SENTINEL(input_brigade);
|
||||
- e = APR_BUCKET_NEXT(e)) {
|
||||
- const char *data;
|
||||
- apr_size_t bytes_read, bytes_written;
|
||||
-
|
||||
- apr_bucket_read(e, &data, &bytes_read, APR_BLOCK_READ);
|
||||
- status = apr_file_write_full(tmpfile, data, bytes_read, &bytes_written);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- const char *tmpfile_name;
|
||||
-
|
||||
- if (apr_file_name_get(&tmpfile_name, tmpfile) != APR_SUCCESS) {
|
||||
- tmpfile_name = "(unknown)";
|
||||
- }
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01091)
|
||||
- "write to temporary file %s failed",
|
||||
- tmpfile_name);
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
- AP_DEBUG_ASSERT(bytes_read == bytes_written);
|
||||
- fsize += bytes_written;
|
||||
- }
|
||||
- apr_brigade_cleanup(input_brigade);
|
||||
- }
|
||||
- else {
|
||||
-
|
||||
- /*
|
||||
- * Save input_brigade in body_brigade. (At least) in the SSL case
|
||||
- * input_brigade contains transient buckets whose data would get
|
||||
- * overwritten during the next call of ap_get_brigade in the loop.
|
||||
- * ap_save_brigade ensures these buckets to be set aside.
|
||||
- * Calling ap_save_brigade with NULL as filter is OK, because
|
||||
- * body_brigade already has been created and does not need to get
|
||||
- * created by ap_save_brigade.
|
||||
- */
|
||||
- status = ap_save_brigade(NULL, &body_brigade, &input_brigade, p);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
-
|
||||
- }
|
||||
-
|
||||
- *bytes_spooled += bytes;
|
||||
- } while (!seen_eos);
|
||||
-
|
||||
- APR_BRIGADE_CONCAT(input_brigade, body_brigade);
|
||||
- if (tmpfile) {
|
||||
- apr_brigade_insert_file(input_brigade, tmpfile, 0, fsize, p);
|
||||
- }
|
||||
- if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) {
|
||||
- e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
|
||||
- APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
- }
|
||||
- if (tmpfile) {
|
||||
- /* We dropped metadata buckets when spooling to tmpfile,
|
||||
- * terminate with EOS for stream_reqbody() to flush the
|
||||
- * whole in one go.
|
||||
- */
|
||||
- e = apr_bucket_eos_create(bucket_alloc);
|
||||
- APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
- }
|
||||
- return OK;
|
||||
-}
|
||||
|
||||
static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
apr_uri_t *uri, char *url)
|
||||
@@ -569,14 +395,12 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
|
||||
apr_bucket_brigade *header_brigade = req->header_brigade;
|
||||
apr_bucket_brigade *input_brigade = req->input_brigade;
|
||||
- apr_bucket_brigade *temp_brigade;
|
||||
apr_bucket *e;
|
||||
- char *buf;
|
||||
apr_status_t status;
|
||||
+ char *buf;
|
||||
apr_off_t bytes_read = 0;
|
||||
apr_off_t bytes;
|
||||
int force10, rv;
|
||||
- apr_read_type_e block;
|
||||
conn_rec *origin = p_conn->connection;
|
||||
|
||||
if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
|
||||
@@ -641,69 +465,12 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
p_conn->close = 1;
|
||||
}
|
||||
|
||||
- /* Prefetch MAX_MEM_SPOOL bytes
|
||||
- *
|
||||
- * This helps us avoid any election of C-L v.s. T-E
|
||||
- * request bodies, since we are willing to keep in
|
||||
- * memory this much data, in any case. This gives
|
||||
- * us an instant C-L election if the body is of some
|
||||
- * reasonable size.
|
||||
- */
|
||||
- temp_brigade = apr_brigade_create(p, bucket_alloc);
|
||||
- block = req->prefetch_nonblocking ? APR_NONBLOCK_READ : APR_BLOCK_READ;
|
||||
-
|
||||
- /* Account for saved input, if any. */
|
||||
- apr_brigade_length(input_brigade, 0, &bytes_read);
|
||||
-
|
||||
- /* Ensure we don't hit a wall where we have a buffer too small
|
||||
- * for ap_get_brigade's filters to fetch us another bucket,
|
||||
- * surrender once we hit 80 bytes less than MAX_MEM_SPOOL
|
||||
- * (an arbitrary value).
|
||||
- */
|
||||
- while (bytes_read < MAX_MEM_SPOOL - 80
|
||||
- && (APR_BRIGADE_EMPTY(input_brigade)
|
||||
- || !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)))) {
|
||||
- status = ap_get_brigade(r->input_filters, temp_brigade,
|
||||
- AP_MODE_READBYTES, block,
|
||||
- MAX_MEM_SPOOL - bytes_read);
|
||||
- /* ap_get_brigade may return success with an empty brigade
|
||||
- * for a non-blocking read which would block
|
||||
- */
|
||||
- if (block == APR_NONBLOCK_READ
|
||||
- && ((status == APR_SUCCESS && APR_BRIGADE_EMPTY(temp_brigade))
|
||||
- || APR_STATUS_IS_EAGAIN(status))) {
|
||||
- break;
|
||||
- }
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095)
|
||||
- "prefetch request body failed to %pI (%s)"
|
||||
- " from %s (%s)",
|
||||
- p_conn->addr, p_conn->hostname ? p_conn->hostname: "",
|
||||
- c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
- return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
|
||||
- }
|
||||
-
|
||||
- apr_brigade_length(temp_brigade, 1, &bytes);
|
||||
- bytes_read += bytes;
|
||||
-
|
||||
- /*
|
||||
- * Save temp_brigade in input_brigade. (At least) in the SSL case
|
||||
- * temp_brigade contains transient buckets whose data would get
|
||||
- * overwritten during the next call of ap_get_brigade in the loop.
|
||||
- * ap_save_brigade ensures these buckets to be set aside.
|
||||
- * Calling ap_save_brigade with NULL as filter is OK, because
|
||||
- * input_brigade already has been created and does not need to get
|
||||
- * created by ap_save_brigade.
|
||||
- */
|
||||
- status = ap_save_brigade(NULL, &input_brigade, &temp_brigade, p);
|
||||
- if (status != APR_SUCCESS) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01096)
|
||||
- "processing prefetched request body failed"
|
||||
- " to %pI (%s) from %s (%s)",
|
||||
- p_conn->addr, p_conn->hostname ? p_conn->hostname: "",
|
||||
- c->client_ip, c->remote_host ? c->remote_host: "");
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
+ rv = ap_proxy_prefetch_input(r, req->backend, input_brigade,
|
||||
+ req->prefetch_nonblocking ? APR_NONBLOCK_READ
|
||||
+ : APR_BLOCK_READ,
|
||||
+ &bytes_read, MAX_MEM_SPOOL);
|
||||
+ if (rv != OK) {
|
||||
+ return rv;
|
||||
}
|
||||
|
||||
/* Use chunked request body encoding or send a content-length body?
|
||||
@@ -772,7 +539,7 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
char *endstr;
|
||||
status = apr_strtoff(&req->cl_val, req->old_cl_val, &endstr, 10);
|
||||
if (status != APR_SUCCESS || *endstr || req->cl_val < 0) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085)
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01085)
|
||||
"could not parse request Content-Length (%s)",
|
||||
req->old_cl_val);
|
||||
return HTTP_BAD_REQUEST;
|
||||
@@ -812,7 +579,8 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
|
||||
/* If we have to spool the body, do it now, before connecting or
|
||||
* reusing the backend connection.
|
||||
*/
|
||||
- rv = spool_reqbody_cl(req, &bytes);
|
||||
+ rv = ap_proxy_spool_input(r, p_conn, input_brigade,
|
||||
+ &bytes, MAX_MEM_SPOOL);
|
||||
if (rv != OK) {
|
||||
return rv;
|
||||
}
|
||||
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
||||
index ab88d8f..973aa83 100644
|
||||
--- a/modules/proxy/proxy_util.c
|
||||
+++ b/modules/proxy/proxy_util.c
|
||||
@@ -3866,6 +3866,268 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
return OK;
|
||||
}
|
||||
|
||||
+PROXY_DECLARE(int) ap_proxy_prefetch_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_read_type_e block,
|
||||
+ apr_off_t *bytes_read,
|
||||
+ apr_off_t max_read)
|
||||
+{
|
||||
+ apr_pool_t *p = r->pool;
|
||||
+ conn_rec *c = r->connection;
|
||||
+ apr_bucket_brigade *temp_brigade;
|
||||
+ apr_status_t status;
|
||||
+ apr_off_t bytes;
|
||||
+
|
||||
+ *bytes_read = 0;
|
||||
+ if (max_read < APR_BUCKET_BUFF_SIZE) {
|
||||
+ max_read = APR_BUCKET_BUFF_SIZE;
|
||||
+ }
|
||||
+
|
||||
+ /* Prefetch max_read bytes
|
||||
+ *
|
||||
+ * This helps us avoid any election of C-L v.s. T-E
|
||||
+ * request bodies, since we are willing to keep in
|
||||
+ * memory this much data, in any case. This gives
|
||||
+ * us an instant C-L election if the body is of some
|
||||
+ * reasonable size.
|
||||
+ */
|
||||
+ temp_brigade = apr_brigade_create(p, input_brigade->bucket_alloc);
|
||||
+
|
||||
+ /* Account for saved input, if any. */
|
||||
+ apr_brigade_length(input_brigade, 0, bytes_read);
|
||||
+
|
||||
+ /* Ensure we don't hit a wall where we have a buffer too small for
|
||||
+ * ap_get_brigade's filters to fetch us another bucket, surrender
|
||||
+ * once we hit 80 bytes (an arbitrary value) less than max_read.
|
||||
+ */
|
||||
+ while (*bytes_read < max_read - 80
|
||||
+ && (APR_BRIGADE_EMPTY(input_brigade)
|
||||
+ || !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)))) {
|
||||
+ status = ap_get_brigade(r->input_filters, temp_brigade,
|
||||
+ AP_MODE_READBYTES, block,
|
||||
+ max_read - *bytes_read);
|
||||
+ /* ap_get_brigade may return success with an empty brigade
|
||||
+ * for a non-blocking read which would block
|
||||
+ */
|
||||
+ if (block == APR_NONBLOCK_READ
|
||||
+ && ((status == APR_SUCCESS && APR_BRIGADE_EMPTY(temp_brigade))
|
||||
+ || APR_STATUS_IS_EAGAIN(status))) {
|
||||
+ break;
|
||||
+ }
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095)
|
||||
+ "prefetch request body failed to %pI (%s)"
|
||||
+ " from %s (%s)", backend->addr,
|
||||
+ backend->hostname ? backend->hostname : "",
|
||||
+ c->client_ip, c->remote_host ? c->remote_host : "");
|
||||
+ return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
|
||||
+ }
|
||||
+
|
||||
+ apr_brigade_length(temp_brigade, 1, &bytes);
|
||||
+ *bytes_read += bytes;
|
||||
+
|
||||
+ /*
|
||||
+ * Save temp_brigade in input_brigade. (At least) in the SSL case
|
||||
+ * temp_brigade contains transient buckets whose data would get
|
||||
+ * overwritten during the next call of ap_get_brigade in the loop.
|
||||
+ * ap_save_brigade ensures these buckets to be set aside.
|
||||
+ * Calling ap_save_brigade with NULL as filter is OK, because
|
||||
+ * input_brigade already has been created and does not need to get
|
||||
+ * created by ap_save_brigade.
|
||||
+ */
|
||||
+ status = ap_save_brigade(NULL, &input_brigade, &temp_brigade, p);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01096)
|
||||
+ "processing prefetched request body failed"
|
||||
+ " to %pI (%s) from %s (%s)", backend->addr,
|
||||
+ backend->hostname ? backend->hostname : "",
|
||||
+ c->client_ip, c->remote_host ? c->remote_host : "");
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
+PROXY_DECLARE(int) ap_proxy_read_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *bb,
|
||||
+ apr_off_t max_read)
|
||||
+{
|
||||
+ apr_bucket_alloc_t *bucket_alloc = bb->bucket_alloc;
|
||||
+ apr_read_type_e block = (backend->connection) ? APR_NONBLOCK_READ
|
||||
+ : APR_BLOCK_READ;
|
||||
+ apr_status_t status;
|
||||
+ int rv;
|
||||
+
|
||||
+ for (;;) {
|
||||
+ apr_brigade_cleanup(bb);
|
||||
+ status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
|
||||
+ block, max_read);
|
||||
+ if (block == APR_BLOCK_READ
|
||||
+ || (!(status == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))
|
||||
+ && !APR_STATUS_IS_EAGAIN(status))) {
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Flush and retry (blocking) */
|
||||
+ apr_brigade_cleanup(bb);
|
||||
+ rv = ap_proxy_pass_brigade(bucket_alloc, r, backend,
|
||||
+ backend->connection, bb, 1);
|
||||
+ if (rv != OK) {
|
||||
+ return rv;
|
||||
+ }
|
||||
+ block = APR_BLOCK_READ;
|
||||
+ }
|
||||
+
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ conn_rec *c = r->connection;
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02608)
|
||||
+ "read request body failed to %pI (%s)"
|
||||
+ " from %s (%s)", backend->addr,
|
||||
+ backend->hostname ? backend->hostname : "",
|
||||
+ c->client_ip, c->remote_host ? c->remote_host : "");
|
||||
+ return ap_map_http_request_error(status, HTTP_BAD_REQUEST);
|
||||
+ }
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
+PROXY_DECLARE(int) ap_proxy_spool_input(request_rec *r,
|
||||
+ proxy_conn_rec *backend,
|
||||
+ apr_bucket_brigade *input_brigade,
|
||||
+ apr_off_t *bytes_spooled,
|
||||
+ apr_off_t max_mem_spool)
|
||||
+{
|
||||
+ apr_pool_t *p = r->pool;
|
||||
+ int seen_eos = 0, rv = OK;
|
||||
+ apr_status_t status = APR_SUCCESS;
|
||||
+ apr_bucket_alloc_t *bucket_alloc = input_brigade->bucket_alloc;
|
||||
+ apr_bucket_brigade *body_brigade;
|
||||
+ apr_bucket *e;
|
||||
+ apr_off_t bytes, fsize = 0;
|
||||
+ apr_file_t *tmpfile = NULL;
|
||||
+ apr_off_t limit;
|
||||
+
|
||||
+ *bytes_spooled = 0;
|
||||
+ body_brigade = apr_brigade_create(p, bucket_alloc);
|
||||
+
|
||||
+ limit = ap_get_limit_req_body(r);
|
||||
+
|
||||
+ do {
|
||||
+ if (APR_BRIGADE_EMPTY(input_brigade)) {
|
||||
+ rv = ap_proxy_read_input(r, backend, input_brigade,
|
||||
+ HUGE_STRING_LEN);
|
||||
+ if (rv != OK) {
|
||||
+ return rv;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If this brigade contains EOS, either stop or remove it. */
|
||||
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
|
||||
+ seen_eos = 1;
|
||||
+ }
|
||||
+
|
||||
+ apr_brigade_length(input_brigade, 1, &bytes);
|
||||
+
|
||||
+ if (*bytes_spooled + bytes > max_mem_spool) {
|
||||
+ /*
|
||||
+ * LimitRequestBody does not affect Proxy requests (Should it?).
|
||||
+ * Let it take effect if we decide to store the body in a
|
||||
+ * temporary file on disk.
|
||||
+ */
|
||||
+ if (limit && (*bytes_spooled + bytes > limit)) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088)
|
||||
+ "Request body is larger than the configured "
|
||||
+ "limit of %" APR_OFF_T_FMT, limit);
|
||||
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
+ }
|
||||
+ /* can't spool any more in memory; write latest brigade to disk */
|
||||
+ if (tmpfile == NULL) {
|
||||
+ const char *temp_dir;
|
||||
+ char *template;
|
||||
+
|
||||
+ status = apr_temp_dir_get(&temp_dir, p);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01089)
|
||||
+ "search for temporary directory failed");
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ apr_filepath_merge(&template, temp_dir,
|
||||
+ "modproxy.tmp.XXXXXX",
|
||||
+ APR_FILEPATH_NATIVE, p);
|
||||
+ status = apr_file_mktemp(&tmpfile, template, 0, p);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01090)
|
||||
+ "creation of temporary file in directory "
|
||||
+ "%s failed", temp_dir);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+ for (e = APR_BRIGADE_FIRST(input_brigade);
|
||||
+ e != APR_BRIGADE_SENTINEL(input_brigade);
|
||||
+ e = APR_BUCKET_NEXT(e)) {
|
||||
+ const char *data;
|
||||
+ apr_size_t bytes_read, bytes_written;
|
||||
+
|
||||
+ apr_bucket_read(e, &data, &bytes_read, APR_BLOCK_READ);
|
||||
+ status = apr_file_write_full(tmpfile, data, bytes_read, &bytes_written);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ const char *tmpfile_name;
|
||||
+
|
||||
+ if (apr_file_name_get(&tmpfile_name, tmpfile) != APR_SUCCESS) {
|
||||
+ tmpfile_name = "(unknown)";
|
||||
+ }
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01091)
|
||||
+ "write to temporary file %s failed",
|
||||
+ tmpfile_name);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ AP_DEBUG_ASSERT(bytes_read == bytes_written);
|
||||
+ fsize += bytes_written;
|
||||
+ }
|
||||
+ apr_brigade_cleanup(input_brigade);
|
||||
+ }
|
||||
+ else {
|
||||
+
|
||||
+ /*
|
||||
+ * Save input_brigade in body_brigade. (At least) in the SSL case
|
||||
+ * input_brigade contains transient buckets whose data would get
|
||||
+ * overwritten during the next call of ap_get_brigade in the loop.
|
||||
+ * ap_save_brigade ensures these buckets to be set aside.
|
||||
+ * Calling ap_save_brigade with NULL as filter is OK, because
|
||||
+ * body_brigade already has been created and does not need to get
|
||||
+ * created by ap_save_brigade.
|
||||
+ */
|
||||
+ status = ap_save_brigade(NULL, &body_brigade, &input_brigade, p);
|
||||
+ if (status != APR_SUCCESS) {
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ *bytes_spooled += bytes;
|
||||
+ } while (!seen_eos);
|
||||
+
|
||||
+ APR_BRIGADE_CONCAT(input_brigade, body_brigade);
|
||||
+ if (tmpfile) {
|
||||
+ apr_brigade_insert_file(input_brigade, tmpfile, 0, fsize, p);
|
||||
+ }
|
||||
+ if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) {
|
||||
+ e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
+ }
|
||||
+ if (tmpfile) {
|
||||
+ /* We dropped metadata buckets when spooling to tmpfile,
|
||||
+ * terminate with EOS to allow for flushing in a one go.
|
||||
+ */
|
||||
+ e = apr_bucket_eos_create(bucket_alloc);
|
||||
+ APR_BRIGADE_INSERT_TAIL(input_brigade, e);
|
||||
+ }
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
|
||||
request_rec *r, proxy_conn_rec *p_conn,
|
||||
conn_rec *origin, apr_bucket_brigade *bb,
|
|
@ -0,0 +1,39 @@
|
|||
# ./pullrev.sh 1884505 1915625
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1884505
|
||||
http://svn.apache.org/viewvc?view=revision&revision=1915625
|
||||
|
||||
--- httpd-2.4.57/modules/filters/mod_xml2enc.c
|
||||
+++ httpd-2.4.57/modules/filters/mod_xml2enc.c
|
||||
@@ -329,7 +329,7 @@
|
||||
apr_bucket* bstart;
|
||||
apr_size_t insz = 0;
|
||||
int pending_meta = 0;
|
||||
- char *ctype;
|
||||
+ char *mtype;
|
||||
char *p;
|
||||
|
||||
if (!ctx || !f->r->content_type) {
|
||||
@@ -338,13 +338,17 @@
|
||||
return ap_pass_brigade(f->next, bb) ;
|
||||
}
|
||||
|
||||
- ctype = apr_pstrdup(f->r->pool, f->r->content_type);
|
||||
- for (p = ctype; *p; ++p)
|
||||
- if (isupper(*p))
|
||||
- *p = tolower(*p);
|
||||
+ /* Extract the media type, ignoring parameters in content-type. */
|
||||
+ mtype = apr_pstrdup(f->r->pool, f->r->content_type);
|
||||
+ if ((p = ap_strchr(mtype, ';')) != NULL) *p = '\0';
|
||||
+ ap_str_tolower(mtype);
|
||||
|
||||
- /* only act if starts-with "text/" or contains "xml" */
|
||||
- if (strncmp(ctype, "text/", 5) && !strstr(ctype, "xml")) {
|
||||
+ /* Accept text/ types, plus any XML media type per RFC 7303. */
|
||||
+ if (!(strncmp(mtype, "text/", 5) == 0
|
||||
+ || strcmp(mtype, "application/xml") == 0
|
||||
+ || (strlen(mtype) > 7 /* minimum 'a/b+xml' length */
|
||||
+ && (p = strstr(mtype, "+xml")) != NULL
|
||||
+ && strlen(p) == 4 /* ensures +xml is a suffix */))) {
|
||||
ap_remove_output_filter(f);
|
||||
return ap_pass_brigade(f->next, bb) ;
|
||||
}
|
|
@ -8,5 +8,6 @@ ConditionPathExists=|!/etc/pki/tls/private/localhost.key
|
|||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=no
|
||||
PrivateTmp=true
|
||||
|
||||
ExecStart=/usr/libexec/httpd-ssl-gencerts
|
||||
|
|
|
@ -33,6 +33,7 @@ sscg -q \
|
|||
--cert-file /etc/pki/tls/certs/localhost.crt \
|
||||
--cert-key-file /etc/pki/tls/private/localhost.key \
|
||||
--ca-file /etc/pki/tls/certs/localhost.crt \
|
||||
--dhparams-file /tmp/dhparams.pem \
|
||||
--lifetime 365 \
|
||||
--hostname $FQDN \
|
||||
--email root@$FQDN
|
||||
|
|
236
SPECS/httpd.spec
236
SPECS/httpd.spec
|
@ -3,7 +3,7 @@
|
|||
%define suexec_caller apache
|
||||
%define mmn 20120211
|
||||
%define mmnisa %{mmn}%{__isa_name}%{__isa_bits}
|
||||
%define vstring %(source /etc/os-release; echo ${REDHAT_SUPPORT_PRODUCT})
|
||||
%define vstring %(source /etc/os-release; echo ${NAME})
|
||||
%if 0%{?fedora} > 26 || 0%{?rhel} > 7
|
||||
%global mpm event
|
||||
%else
|
||||
|
@ -13,7 +13,7 @@
|
|||
Summary: Apache HTTP Server
|
||||
Name: httpd
|
||||
Version: 2.4.37
|
||||
Release: 41%{?dist}
|
||||
Release: 64%{?dist}
|
||||
URL: https://httpd.apache.org/
|
||||
Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2
|
||||
Source2: httpd.logrotate
|
||||
|
@ -159,6 +159,18 @@ Patch86: httpd-2.4.37-r1873907.patch
|
|||
Patch87: httpd-2.4.37-reply-two-tls-rec.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1905613
|
||||
Patch88: httpd-2.4.37-r1845768+.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2001046
|
||||
Patch89: httpd-2.4.37-r1862410.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1984828
|
||||
Patch90: httpd-2.4.37-hcheck-mem-issues.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2017543
|
||||
Patch91: httpd-2.4.37-add-SNI-support.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2159603
|
||||
Patch92: httpd-2.4.37-mod_status-duplicate-key.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2221083
|
||||
Patch93: httpd-2.4.37-r1885607.patch
|
||||
# https://issues.redhat.com/browse/RHEL-14321
|
||||
Patch94: httpd-2.4.57-r1884505+.patch
|
||||
|
||||
# Security fixes
|
||||
Patch200: httpd-2.4.37-r1851471.patch
|
||||
|
@ -192,6 +204,60 @@ Patch211: httpd-2.4.37-CVE-2020-11984.patch
|
|||
Patch212: httpd-2.4.37-CVE-2021-30641.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1968307
|
||||
Patch213: httpd-2.4.37-CVE-2021-26690.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2005117
|
||||
Patch214: httpd-2.4.37-CVE-2021-40438.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1966732
|
||||
Patch215: httpd-2.4.37-CVE-2021-26691.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1968278
|
||||
Patch216: httpd-2.4.37-CVE-2020-35452.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2005128
|
||||
Patch217: httpd-2.4.37-CVE-2021-34798.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2005119
|
||||
Patch218: httpd-2.4.37-CVE-2021-39275.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2005124
|
||||
Patch219: httpd-2.4.37-CVE-2021-36160.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1966728
|
||||
Patch220: httpd-2.4.37-CVE-2021-33193.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2034674
|
||||
Patch221: httpd-2.4.37-CVE-2021-44790.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2034672
|
||||
Patch222: httpd-2.4.37-CVE-2021-44224.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2064321
|
||||
Patch223: httpd-2.4.37-CVE-2022-22720.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1966738
|
||||
Patch224: httpd-2.4.37-CVE-2020-13950.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2064322
|
||||
Patch225: httpd-2.4.37-CVE-2022-22719.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2064320
|
||||
Patch226: httpd-2.4.37-CVE-2022-22721.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2065324
|
||||
Patch227: httpd-2.4.37-CVE-2022-23943.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2095002
|
||||
Patch228: httpd-2.4.37-CVE-2022-28614.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2095006
|
||||
Patch229: httpd-2.4.37-CVE-2022-28615.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2095015
|
||||
Patch230: httpd-2.4.37-CVE-2022-30522.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2095018
|
||||
Patch231: httpd-2.4.37-CVE-2022-30556.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2095020
|
||||
Patch232: httpd-2.4.37-CVE-2022-31813.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2095012
|
||||
Patch233: httpd-2.4.37-CVE-2022-29404.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2094997
|
||||
Patch234: httpd-2.4.37-CVE-2022-26377.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2161773
|
||||
Patch235: httpd-2.4.37-CVE-2022-37436.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2161774
|
||||
Patch236: httpd-2.4.37-CVE-2006-20001.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2161777
|
||||
Patch237: httpd-2.4.37-CVE-2022-36760.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2176209
|
||||
Patch238: httpd-2.4.37-CVE-2023-25690.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2176211
|
||||
Patch239: httpd-2.4.37-CVE-2023-27522.patch
|
||||
# https://issues.redhat.com/browse/RHEL-14448
|
||||
Patch240: httpd-2.4.37-CVE-2023-31122.patch
|
||||
|
||||
License: ASL 2.0
|
||||
Group: System Environment/Daemons
|
||||
|
@ -209,7 +275,7 @@ Provides: mod_dav = %{version}-%{release}, httpd-suexec = %{version}-%{release}
|
|||
Provides: httpd-mmn = %{mmn}, httpd-mmn = %{mmnisa}
|
||||
Requires: httpd-tools = %{version}-%{release}
|
||||
Requires: httpd-filesystem = %{version}-%{release}
|
||||
Requires: mod_http2
|
||||
Requires: mod_http2 >= 1.15.7-5
|
||||
Requires(pre): httpd-filesystem
|
||||
Requires(preun): systemd-units
|
||||
Requires(postun): systemd-units
|
||||
|
@ -273,7 +339,7 @@ Epoch: 1
|
|||
BuildRequires: openssl-devel
|
||||
Requires(pre): httpd-filesystem
|
||||
Requires: httpd = 0:%{version}-%{release}, httpd-mmn = %{mmnisa}
|
||||
Requires: sscg >= 2.2.0
|
||||
Requires: sscg >= 3.0.0-7, /usr/bin/hostname
|
||||
Obsoletes: stronghold-mod_ssl
|
||||
# Require an OpenSSL which supports PROFILE=SYSTEM
|
||||
Conflicts: openssl-libs < 1:1.0.1h-4
|
||||
|
@ -370,6 +436,12 @@ interface for storing and accessing per-user session data.
|
|||
%patch86 -p1 -b .r1873907
|
||||
%patch87 -p1 -b .reply-two-tls-rec
|
||||
%patch88 -p1 -b .r1845768+
|
||||
%patch89 -p1 -b .r1862410
|
||||
%patch90 -p1 -b .hcheck-mem-issues
|
||||
%patch91 -p1 -b .SNI
|
||||
%patch92 -p1 -b .mod_status-dupl
|
||||
%patch93 -p1 -b .r1885607
|
||||
%patch94 -p1 -b .r1884505+
|
||||
|
||||
%patch200 -p1 -b .r1851471
|
||||
%patch201 -p1 -b .CVE-2019-0211
|
||||
|
@ -385,6 +457,33 @@ interface for storing and accessing per-user session data.
|
|||
%patch211 -p1 -b .CVE-2020-11984
|
||||
%patch212 -p1 -b .CVE-2021-30641
|
||||
%patch213 -p1 -b .CVE-2021-26690
|
||||
%patch214 -p1 -b .CVE-2021-40438
|
||||
%patch215 -p1 -b .CVE-2021-26691
|
||||
%patch216 -p1 -b .CVE-2020-35452
|
||||
%patch217 -p1 -b .CVE-2021-34798
|
||||
%patch218 -p1 -b .CVE-2021-39275
|
||||
%patch219 -p1 -b .CVE-2021-36160
|
||||
%patch220 -p1 -b .CVE-2021-33193
|
||||
%patch221 -p1 -b .CVE-2021-44790
|
||||
%patch222 -p1 -b .CVE-2021-44224
|
||||
%patch223 -p1 -b .CVE-2022-22720
|
||||
%patch224 -p1 -b .CVE-2020-13950
|
||||
%patch225 -p1 -b .CVE-2022-22719
|
||||
%patch226 -p1 -b .CVE-2022-22721
|
||||
%patch227 -p1 -b .CVE-2022-23943
|
||||
%patch228 -p1 -b .CVE-2022-28614
|
||||
%patch229 -p1 -b .CVE-2022-28615
|
||||
%patch230 -p1 -b .CVE-2022-30522
|
||||
%patch231 -p1 -b .CVE-2022-30556
|
||||
%patch232 -p1 -b .CVE-2022-31813
|
||||
%patch233 -p1 -b .CVE-2022-29404
|
||||
%patch234 -p1 -b .CVE-2022-26377
|
||||
%patch235 -p1 -b .CVE-2022-37436
|
||||
%patch236 -p1 -b .CVE-2006-20001
|
||||
%patch237 -p1 -b .CVE-2022-36760
|
||||
%patch238 -p1 -b .CVE-2023-25690
|
||||
%patch239 -p1 -b .CVE-2023-27522
|
||||
%patch240 -p1 -b .CVE-2023-31122
|
||||
|
||||
# Patch in the vendor string
|
||||
sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h
|
||||
|
@ -890,6 +989,135 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%{_rpmconfigdir}/macros.d/macros.httpd
|
||||
|
||||
%changelog
|
||||
* Fri Feb 16 2024 Joe Orton <jorton@redhat.com> - 2.4.37-64
|
||||
- Resolves: RHEL-14448 - httpd: mod_macro: out-of-bounds read
|
||||
vulnerability (CVE-2023-31122)
|
||||
|
||||
* Wed Feb 14 2024 Joe Orton <jorton@redhat.com> - 2.4.37-63
|
||||
- mod_xml2enc: fix media type handling
|
||||
Resolves: RHEL-14321
|
||||
|
||||
* Thu Aug 17 2023 Johnny Hughes <jhughes@redhat.com> - 2.4.37-62
|
||||
- change for CentOS Stream Branding
|
||||
|
||||
* Thu Jul 27 2023 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-62
|
||||
- Resolves: #2221083 - Apache Bug 57087: mod_proxy_fcgi doesn't send cgi
|
||||
CONTENT_LENGTH variable when the client request used Transfer-Encoding:chunked
|
||||
|
||||
* Thu Jul 20 2023 Tomas Korbar <tkorbar@redhat.com> - 2.4.37-61
|
||||
- Fix issue found by covscan
|
||||
- Related: #2159603
|
||||
|
||||
* Mon Jul 17 2023 Tomas Korbar <tkorbar@redhat.com> - 2.4.37-60
|
||||
- Another rebuild because of mistake in workflow
|
||||
- Related: #2159603
|
||||
|
||||
* Mon Jul 17 2023 Tomas Korbar <tkorbar@redhat.com> - 2.4.37-59
|
||||
- Rebuild because of mistake in workflow
|
||||
- Related: #2159603
|
||||
|
||||
* Mon Jul 17 2023 Tomas Korbar <tkorbar@redhat.com> - 2.4.37-58
|
||||
- Resolves: #2159603 - mod_status lists BusyWorkers IdleWorkers keys twice
|
||||
|
||||
* Thu May 25 2023 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-57
|
||||
- Resolves: #2176723 - CVE-2023-27522 httpd:2.4/httpd: mod_proxy_uwsgi HTTP
|
||||
response splitting
|
||||
|
||||
* Thu Apr 27 2023 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-56.5
|
||||
- Resolves: #2190133 - mod_rewrite regression with CVE-2023-25690
|
||||
|
||||
* Sat Mar 18 2023 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-56.4
|
||||
- Resolves: #2177748 - CVE-2023-25690 httpd:2.4/httpd: HTTP request splitting
|
||||
with mod_rewrite and mod_proxy
|
||||
|
||||
* Tue Jan 31 2023 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-56
|
||||
- Resolves: #2162499 - CVE-2006-20001 httpd: mod_dav: out-of-bounds read/write
|
||||
of zero byte
|
||||
- Resolves: #2162485 - CVE-2022-37436 httpd: mod_proxy: HTTP response splitting
|
||||
- Resolves: #2162509 - CVE-2022-36760 httpd: mod_proxy_ajp: Possible request
|
||||
smuggling
|
||||
|
||||
* Thu Jan 26 2023 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-55
|
||||
- Resolves: #2155961 - prevent sscg creating /dhparams.pem
|
||||
|
||||
* Thu Dec 08 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-54
|
||||
- Resolves: #2095650 - Dependency from mod_http2 on httpd broken
|
||||
|
||||
* Wed Nov 09 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-53
|
||||
- Resolves: #2050888 - httpd with SSL fails to start unless hostname command
|
||||
was installed
|
||||
|
||||
* Mon Sep 19 2022 Tomas Korbar <tkorbar@redhat.com> - 2.4.37-52
|
||||
- Add the SNI support in mod_proxy_wstunnel module for Apache httpd
|
||||
- Resolves: rhbz#2017543
|
||||
|
||||
* Mon Jul 25 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-51
|
||||
- Resolves: #2097015 - CVE-2022-28614 httpd:2.4/httpd: out-of-bounds read via
|
||||
ap_rwrite()
|
||||
- Resolves: #2097031 - CVE-2022-28615 httpd:2.4/httpd: out-of-bounds read in
|
||||
ap_strcmp_match()
|
||||
- Resolves: #2097458 - CVE-2022-30522 httpd:2.4/httpd: mod_sed: DoS
|
||||
vulnerability
|
||||
- Resolves: #2097480 - CVE-2022-30556 httpd:2.4/httpd: mod_lua: Information
|
||||
disclosure with websockets
|
||||
- Resolves: #2098247 - CVE-2022-31813 httpd:2.4/httpd: mod_proxy:
|
||||
X-Forwarded-For dropped by hop-by-hop mechanism
|
||||
- Resolves: #2097451 - CVE-2022-29404 httpd:2.4/httpd: mod_lua: DoS in
|
||||
r:parsebody
|
||||
- Resolves: #2096997 - CVE-2022-26377 httpd:2.4/httpd: mod_proxy_ajp: Possible
|
||||
request smuggling
|
||||
|
||||
* Tue Jun 21 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-50
|
||||
- Resolves: #2065237 - CVE-2022-22719 httpd:2.4/httpd: mod_lua: Use of
|
||||
uninitialized value of in r:parsebody
|
||||
- Resolves: #2065267 - CVE-2022-22721 httpd:2.4/httpd: core: Possible buffer
|
||||
overflow with very large or unlimited LimitXMLRequestBody
|
||||
- Resolves: #2065324 - CVE-2022-23943 httpd:2.4/httpd: mod_sed: Read/write
|
||||
beyond bounds
|
||||
|
||||
* Fri Jun 10 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-49
|
||||
- Resolves: #2090848 - CVE-2020-13950 httpd:2.4/httpd: mod_proxy NULL pointer
|
||||
dereference
|
||||
|
||||
* Mon Mar 21 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-48
|
||||
- Resolves: #2065249 - CVE-2022-22720 httpd:2.4/httpd: HTTP request smuggling
|
||||
vulnerability in Apache HTTP Server 2.4.52 and earlier
|
||||
|
||||
* Thu Jan 20 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-47
|
||||
- Resolves: #2035030 - CVE-2021-44224 httpd:2.4/httpd: possible NULL dereference
|
||||
or SSRF in forward proxy configurations
|
||||
|
||||
* Mon Jan 10 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-46
|
||||
- Resolves: #2035063 - CVE-2021-44790 httpd:2.4/httpd: mod_lua: possible buffer
|
||||
overflow when parsing multipart content
|
||||
|
||||
* Thu Jan 06 2022 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-45
|
||||
- Resolves: #2007199 - CVE-2021-36160 httpd:2.4/httpd: mod_proxy_uwsgi:
|
||||
out-of-bounds read via a crafted request uri-path
|
||||
- Resolves: #1972491 - CVE-2021-33193 httpd:2.4/mod_http2: Request splitting via
|
||||
HTTP/2 method injection and mod_proxy
|
||||
|
||||
* Mon Nov 29 2021 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-44
|
||||
- Resolves: #1968278 - CVE-2020-35452 httpd:2.4/httpd: Single zero byte stack
|
||||
overflow in mod_auth_digest
|
||||
- Resolves: #2001046 - Apache httpd OOME with mod_dav in RHEL 8
|
||||
- Resolves: #2005128 (CVE-2021-34798) - CVE-2021-34798 httpd: NULL pointer
|
||||
dereference via malformed requests
|
||||
- Resolves: #1984828 - mod_proxy_hcheck piles up health checks leading to high
|
||||
memory consumption
|
||||
- Resolves: #2005119 - CVE-2021-39275 httpd: out-of-bounds write in
|
||||
ap_escape_quotes() via malicious input
|
||||
|
||||
* Tue Oct 26 2021 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-43
|
||||
- Related: #2007236 - CVE-2021-40438 httpd:2.4/httpd: mod_proxy: SSRF via
|
||||
a crafted request uri-path
|
||||
|
||||
* Thu Sep 30 2021 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-42
|
||||
- Resolves: #2007236 - CVE-2021-40438 httpd:2.4/httpd: mod_proxy: SSRF via
|
||||
a crafted request uri-path
|
||||
- Resolves: #1969229 - CVE-2021-26691 httpd:2.4/httpd: Heap overflow in
|
||||
mod_session
|
||||
|
||||
* Fri Jul 09 2021 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-41
|
||||
- Resolves: #1680111 - httpd sends reply to HTTPS GET using two TLS records
|
||||
- Resolves: #1905613 - mod_ssl does not like valid certificate chain
|
||||
|
|
Loading…
Reference in New Issue