You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by rp...@apache.org on 2005/10/25 22:12:57 UTC
svn commit: r328467 - in /httpd/httpd/branches/2.2.x: CHANGES
modules/proxy/ajp.h modules/proxy/ajp_header.c modules/proxy/ajp_msg.c
modules/proxy/mod_proxy_ajp.c
Author: rpluem
Date: Tue Oct 25 13:12:48 2005
New Revision: 328467
URL: http://svn.apache.org/viewcvs?rev=328467&view=rev
Log:
Merge r327185 from trunk:
* Fix PR37100 (SEGV in mod_proxy_ajp), by sending the data up the filter
chain immediately instead of spooling it completely before passing it
to the filter chain. It contains a bandaid to handle intentional
flushes from Tomcat side. Further explanation in code and report.
ajp.h: Add ajp_msg_reuse prototype
mod_proxy_ajp.c: Adjust logic of ap_proxy_ajp_request
ajp_msg.c: Add ajp_msg_reuse
ajp_header.c: Adjusting logic of ajp_read_header
Modified:
httpd/httpd/branches/2.2.x/CHANGES
httpd/httpd/branches/2.2.x/modules/proxy/ajp.h
httpd/httpd/branches/2.2.x/modules/proxy/ajp_header.c
httpd/httpd/branches/2.2.x/modules/proxy/ajp_msg.c
httpd/httpd/branches/2.2.x/modules/proxy/mod_proxy_ajp.c
Modified: httpd/httpd/branches/2.2.x/CHANGES
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/CHANGES?rev=328467&r1=328466&r2=328467&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.2.x/CHANGES [utf-8] Tue Oct 25 13:12:48 2005
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache 2.1.9
+ *) mod_proxy_ajp: Do not spool the entire response from AJP backend before
+ sending it up the filter chain. PR37100. [Ruediger Pluem]
+
*) mod_cache: Create new filters CACHE_OUT_SUBREQ / CACHE_SAVE_SUBREQ which
only differ by the type from CACHE_OUT / CACHE_SAVE to ensure that
subrequests to non local resources work again. [Ruediger Pluem]
Modified: httpd/httpd/branches/2.2.x/modules/proxy/ajp.h
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/modules/proxy/ajp.h?rev=328467&r1=328466&r2=328467&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/proxy/ajp.h (original)
+++ httpd/httpd/branches/2.2.x/modules/proxy/ajp.h Tue Oct 25 13:12:48 2005
@@ -35,6 +35,7 @@
#include "apr_buckets.h"
#include "apr_md5.h"
#include "apr_network_io.h"
+#include "apr_poll.h"
#include "apr_pools.h"
#include "apr_strings.h"
#include "apr_uri.h"
@@ -185,6 +186,14 @@
* @return APR_SUCCESS or error
*/
apr_status_t ajp_msg_reset(ajp_msg_t *msg);
+
+/**
+ * Reuse an AJP Message
+ *
+ * @param msg AJP Message to reuse
+ * @return APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_reuse(ajp_msg_t *msg);
/**
* Mark the end of an AJP Message
Modified: httpd/httpd/branches/2.2.x/modules/proxy/ajp_header.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/modules/proxy/ajp_header.c?rev=328467&r1=328466&r2=328467&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/proxy/ajp_header.c (original)
+++ httpd/httpd/branches/2.2.x/modules/proxy/ajp_header.c Tue Oct 25 13:12:48 2005
@@ -615,12 +615,22 @@
{
apr_byte_t result;
apr_status_t rc;
-
- rc = ajp_msg_create(r->pool, msg);
- if (rc != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "ajp_read_header: ajp_msg_create failed");
- return rc;
+
+ if (*msg) {
+ rc = ajp_msg_reuse(*msg);
+ if (rc != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "ajp_read_header: ajp_msg_reuse failed");
+ return rc;
+ }
+ }
+ else {
+ rc = ajp_msg_create(r->pool, msg);
+ if (rc != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "ajp_read_header: ajp_msg_create failed");
+ return rc;
+ }
}
ajp_msg_reset(*msg);
rc = ajp_ilink_receive(sock, *msg);
Modified: httpd/httpd/branches/2.2.x/modules/proxy/ajp_msg.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/modules/proxy/ajp_msg.c?rev=328467&r1=328466&r2=328467&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/proxy/ajp_msg.c (original)
+++ httpd/httpd/branches/2.2.x/modules/proxy/ajp_msg.c Tue Oct 25 13:12:48 2005
@@ -139,6 +139,24 @@
}
/**
+ * Reuse an AJP Message
+ *
+ * @param msg AJP Message to reuse
+ * @return APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_reuse(ajp_msg_t *msg)
+{
+ apr_byte_t *buf;
+
+ buf = msg->buf;
+ memset(msg, 0, sizeof(ajp_msg_t));
+ msg->buf = buf;
+ msg->header_len = AJP_HEADER_LEN;
+ ajp_msg_reset(msg);
+ return APR_SUCCESS;
+}
+
+/**
* Mark the end of an AJP Message
*
* @param msg AJP Message to end
Modified: httpd/httpd/branches/2.2.x/modules/proxy/mod_proxy_ajp.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/modules/proxy/mod_proxy_ajp.c?rev=328467&r1=328466&r2=328467&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/proxy/mod_proxy_ajp.c (original)
+++ httpd/httpd/branches/2.2.x/modules/proxy/mod_proxy_ajp.c Tue Oct 25 13:12:48 2005
@@ -90,6 +90,32 @@
}
/*
+ * XXX: Flushing bandaid
+ *
+ * When processing CMD_AJP13_SEND_BODY_CHUNK AJP messages we will do a poll
+ * with FLUSH_WAIT miliseconds timeout to determine if more data is currently
+ * available at the backend. If there is no more data available, we flush
+ * the data to the client by adding a flush bucket to the brigade we pass
+ * up the filter chain.
+ * This is only a bandaid to fix the AJP/1.3 protocol shortcoming of not
+ * sending (actually not having defined) a flush message, when the data
+ * should be flushed to the client. As soon as this protocol shortcoming is
+ * fixed this code should be removed.
+ *
+ * For further discussion see PR37100.
+ * http://issues.apache.org/bugzilla/show_bug.cgi?id=37100
+ */
+#define FLUSHING_BANDAID 1
+
+#ifdef FLUSHING_BANDAID
+/*
+ * Wait 10000 microseconds to find out if more data is currently
+ * available at the backend. Just an arbitrary choose.
+ */
+#define FLUSH_WAIT 10000
+#endif
+
+/*
* process the request and write the response.
*/
static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
@@ -112,6 +138,10 @@
int havebody = 1;
int isok = 1;
apr_off_t bb_len;
+#ifdef FLUSHING_BANDAID
+ apr_int32_t conn_poll_fd;
+ apr_pollfd_t *conn_poll;
+#endif
/*
* Send the AJP request to the remote server
@@ -134,6 +164,8 @@
/* allocate an AJP message to store the data of the buckets */
status = ajp_alloc_data_msg(r->pool, &buff, &bufsiz, &msg);
if (status != APR_SUCCESS) {
+ /* We had a failure: Close connection to backend */
+ conn->close++;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: ajp_alloc_data_msg failed");
return HTTP_INTERNAL_SERVER_ERROR;
@@ -171,6 +203,8 @@
status = apr_brigade_flatten(input_brigade, buff, &bufsiz);
if (status != APR_SUCCESS) {
+ /* We had a failure: Close connection to backend */
+ conn->close++;
apr_brigade_destroy(input_brigade);
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: apr_brigade_flatten");
@@ -183,6 +217,8 @@
if (bufsiz > 0) {
status = ajp_send_data_msg(conn->sock, msg, bufsiz);
if (status != APR_SUCCESS) {
+ /* We had a failure: Close connection to backend */
+ conn->close++;
apr_brigade_destroy(input_brigade);
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: send failed to %pI (%s)",
@@ -195,9 +231,12 @@
}
/* read the response */
+ conn->data = NULL;
status = ajp_read_header(conn->sock, r,
(ajp_msg_t **)&(conn->data));
if (status != APR_SUCCESS) {
+ /* We had a failure: Close connection to backend */
+ conn->close++;
apr_brigade_destroy(input_brigade);
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: read response failed from %pI (%s)",
@@ -209,6 +248,18 @@
result = ajp_parse_type(r, conn->data);
output_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
+#ifdef FLUSHING_BANDAID
+ /*
+ * Prepare apr_pollfd_t struct for later check if there is currently
+ * data available from the backend (do not flush response to client)
+ * or not (flush response to client)
+ */
+ conn_poll = apr_pcalloc(p, sizeof(apr_pollfd_t));
+ conn_poll->reqevents = APR_POLLIN;
+ conn_poll->desc_type = APR_POLL_SOCKET;
+ conn_poll->desc.s = conn->sock;
+#endif
+
bufsiz = AJP13_MAX_SEND_BODY_SZ;
while (isok) {
switch (result) {
@@ -272,16 +323,42 @@
case CMD_AJP13_SEND_BODY_CHUNK:
/* AJP13_SEND_BODY_CHUNK: piece of data */
status = ajp_parse_data(r, conn->data, &size, &buff);
- e = apr_bucket_transient_create(buff, size,
- r->connection->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(output_brigade, e);
- if (status != APR_SUCCESS)
+ if (status == APR_SUCCESS) {
+ e = apr_bucket_transient_create(buff, size,
+ r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(output_brigade, e);
+
+#ifdef FLUSHING_BANDAID
+ /*
+ * If there is no more data available from backend side
+ * currently, flush response to client.
+ */
+ if (apr_poll(conn_poll, 1, &conn_poll_fd, FLUSH_WAIT)
+ == APR_TIMEUP) {
+ e = apr_bucket_flush_create(r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(output_brigade, e);
+ }
+#endif
+ apr_brigade_length(output_brigade, 0, &bb_len);
+ if (bb_len != -1)
+ conn->worker->s->read += bb_len;
+ if (ap_pass_brigade(r->output_filters,
+ output_brigade) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error processing body");
+ isok = 0;
+ }
+ apr_brigade_cleanup(output_brigade);
+ }
+ else {
isok = 0;
+ }
break;
case CMD_AJP13_END_RESPONSE:
e = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(output_brigade, e);
- if (ap_pass_brigade(r->output_filters, output_brigade) != APR_SUCCESS) {
+ if (ap_pass_brigade(r->output_filters,
+ output_brigade) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"proxy: error processing body");
isok = 0;
@@ -291,6 +368,19 @@
isok = 0;
break;
}
+
+ /*
+ * If connection has been aborted by client: Stop working.
+ * Nevertheless, we regard our operation so far as a success:
+ * So do not set isok to 0 and set result to CMD_AJP13_END_RESPONSE
+ * But: Close this connection to the backend.
+ */
+ if (r->connection->aborted) {
+ conn->close++;
+ result = CMD_AJP13_END_RESPONSE;
+ break;
+ }
+
if (!isok)
break;
@@ -310,14 +400,11 @@
}
apr_brigade_destroy(input_brigade);
- apr_brigade_length(output_brigade, 0, &bb_len);
- if (bb_len != -1)
- conn->worker->s->read += bb_len;
-
- if (!isok)
- apr_brigade_destroy(output_brigade);
+ apr_brigade_destroy(output_brigade);
if (status != APR_SUCCESS) {
+ /* We had a failure: Close connection to backend */
+ conn->close++;
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: send body failed to %pI (%s)",
conn->worker->cp->addr,
@@ -340,6 +427,8 @@
conn->worker->cp->addr,
conn->worker->hostname);
+ /* We had a failure: Close connection to backend */
+ conn->close++;
return HTTP_SERVICE_UNAVAILABLE;
}