Changes with Apache 2.0.34-dev
+ *) Proxy HTTP and CONNECT: Keep trying other addresses from the DNS
+ when we can't get a socket in the specified address family. We may
+ have gotten back an IPv6 address first and yet our system is not
+ configured to allow IPv6 sockets. [Jeff Trawick]
+
*) Be more careful about recursively removing CVS directories. Make
sure that we aren't cd'ing to their home directory first.
[Aaron Bannert]
PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen, int *eos);
PROXY_DECLARE(void) ap_proxy_reset_output_filters(conn_rec *c);
PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key);
+PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, server_rec *, apr_pool_t *);
#endif /*MOD_PROXY_H*/
apr_size_t i, o, nbytes;
char buffer[HUGE_STRING_LEN];
apr_socket_t *client_socket = ap_get_module_config(r->connection->conn_config, &core_module);
-
+ int failed;
apr_pollfd_t *pollfd;
apr_int32_t pollcnt;
apr_int16_t pollevent;
connectport = uri.port;
connect_addr = uri_addr;
}
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
"proxy: CONNECT: connecting to remote proxy %s on port %d", connectname, connectport);
/* check if ProxyBlock directive on this host */
case APR_URI_SNEWS_DEFAULT_PORT:
break;
default:
+ /* XXX can we call ap_proxyerror() here to get a nice log message? */
return HTTP_FORBIDDEN;
}
- } else if(!allowed_port(conf, uri.port))
+ } else if(!allowed_port(conf, uri.port)) {
+ /* XXX can we call ap_proxyerror() here to get a nice log message? */
return HTTP_FORBIDDEN;
-
+ }
/*
* Step Two: Make the Connection
connectname, NULL));
}
- /*
- * At this point we have a list of one or more IP addresses of
- * the machine to connect to. If configured, reorder this
- * list so that the "best candidate" is first try. "best
- * candidate" could mean the least loaded server, the fastest
- * responding server, whatever.
- *
- * For now we do nothing, ie we get DNS round robin.
- * XXX FIXME
- *
- * We have to create a new socket each time through the loop because
- *
- * (1) On most stacks, connect() fails with EINVAL or similar if
- * we previously failed connect() on the socket in the past
- * (2) The address family of the socket needs to match that of the
- * address we're trying to connect to.
- */
-
- /* try each IP address until we connect successfully */
- {
- int failed = 1;
- while (connect_addr) {
-
- /* create a new socket */
- if ((rv = apr_socket_create(&sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "proxy: error creating socket");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
- /* Set a timeout on the socket */
- if (conf->timeout_set == 1 ) {
- apr_setsocketopt(sock,
- APR_SO_TIMEOUT,
- (int)(conf->timeout * APR_USEC_PER_SEC));
- }
- else {
- apr_setsocketopt(sock,
- APR_SO_TIMEOUT,
- (int)(r->server->timeout * APR_USEC_PER_SEC));
- }
-
- /* make the connection out of the socket */
- rv = apr_connect(sock, connect_addr);
-
- /* if an error occurred, loop round and try again */
- if (rv != APR_SUCCESS) {
- apr_socket_close(sock);
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
- "proxy: CONNECT: attempt to connect to %pI (%s) failed", connect_addr, connectname);
- connect_addr = connect_addr->next;
- continue;
- }
-
- /* if we get here, all is well */
- failed = 0;
- break;
- }
-
- /* handle a permanent error from the above loop */
- if (failed) {
- if (proxyname) {
- return DECLINED;
- }
- else {
- return HTTP_BAD_GATEWAY;
- }
- }
+ /*
+ * At this point we have a list of one or more IP addresses of
+ * the machine to connect to. If configured, reorder this
+ * list so that the "best candidate" is first try. "best
+ * candidate" could mean the least loaded server, the fastest
+ * responding server, whatever.
+ *
+ * For now we do nothing, ie we get DNS round robin.
+ * XXX FIXME
+ */
+ failed = ap_proxy_connect_to_backend(&sock, "CONNECT", connect_addr,
+ connectname, conf, r->server,
+ r->pool);
+
+ /* handle a permanent error from the above loop */
+ if (failed) {
+ if (proxyname) {
+ return DECLINED;
+ }
+ else {
+ return HTTP_BAD_GATEWAY;
+ }
}
-
/*
* Step Three: Send the Request
*
proxy_server_conf *conf,
const char *proxyname) {
int failed=0, new=0;
- apr_status_t rv;
apr_socket_t *client_socket = NULL;
/* We have determined who to connect to. Now make the connection, supporting
*
* For now we do nothing, ie we get DNS round robin.
* XXX FIXME
- *
- * We have to create a new socket each time through the loop because
- *
- * (1) On most stacks, connect() fails with EINVAL or similar if
- * we previously failed connect() on the socket in the past
- * (2) The address family of the socket needs to match that of the
- * address we're trying to connect to.
*/
+ failed = ap_proxy_connect_to_backend(&p_conn->sock, "HTTP",
+ p_conn->addr, p_conn->name,
+ conf, r->server, c->pool);
- /* try each IP address until we connect successfully */
- failed = 1;
- while (p_conn->addr) {
-
- /* see memory note above */
- if ((rv = apr_socket_create(&p_conn->sock, p_conn->addr->family,
- SOCK_STREAM, c->pool)) != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
- "proxy: error creating socket");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
-#if !defined(TPF) && !defined(BEOS)
- if (conf->recv_buffer_size > 0 &&
- (rv = apr_setsocketopt(p_conn->sock, APR_SO_RCVBUF,
- conf->recv_buffer_size))) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "setsockopt(SO_RCVBUF): Failed to set "
- "ProxyReceiveBufferSize, using default");
- }
-#endif
-
- /* Set a timeout on the socket */
- if (conf->timeout_set == 1) {
- apr_setsocketopt(p_conn->sock, APR_SO_TIMEOUT,
- (int)(conf->timeout * APR_USEC_PER_SEC));
- }
- else {
- apr_setsocketopt(p_conn->sock, APR_SO_TIMEOUT,
- (int)(r->server->timeout * APR_USEC_PER_SEC));
- }
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
- "proxy: socket has been created");
-
- /* make the connection out of the socket */
- rv = apr_connect(p_conn->sock, p_conn->addr);
-
- /* if an error occurred, loop round and try again */
- if (rv != APR_SUCCESS) {
- apr_socket_close(p_conn->sock);
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
- "proxy: attempt to connect to %pI (%s) failed",
- p_conn->addr, p_conn->name);
- p_conn->addr = p_conn->addr->next;
- continue;
- }
-
- /* if we get here, all is well */
- failed = 0;
- break;
- }
-
- /* handle a permanent error from the above loop */
+ /* handle a permanent error on the connect */
if (failed) {
if (proxyname) {
return DECLINED;
}
apr_table_add(t, key, value + offset);
}
+
+PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
+ const char *proxy_function,
+ apr_sockaddr_t *backend_addr,
+ const char *backend_name,
+ proxy_server_conf *conf,
+ server_rec *s,
+ apr_pool_t *p)
+{
+ apr_status_t rv;
+ int connected = 0;
+ int loglevel;
+
+ while (backend_addr && !connected) {
+ if ((rv = apr_socket_create(newsock, backend_addr->family,
+ SOCK_STREAM, p)) != APR_SUCCESS) {
+ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+ ap_log_error(APLOG_MARK, loglevel, rv, s,
+ "proxy: %s: error creating fam %d socket for target %s",
+ proxy_function,
+ backend_addr->family,
+ backend_name);
+ /* this could be an IPv6 address from the DNS but the
+ * local machine won't give us an IPv6 socket; hopefully the
+ * DNS returned an additional address to try
+ */
+ backend_addr = backend_addr->next;
+ continue;
+ }
+
+#if !defined(TPF) && !defined(BEOS)
+ if (conf->recv_buffer_size > 0 &&
+ (rv = apr_setsocketopt(*newsock, APR_SO_RCVBUF,
+ conf->recv_buffer_size))) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+ "setsockopt(SO_RCVBUF): Failed to set "
+ "ProxyReceiveBufferSize, using default");
+ }
+#endif
+
+ /* Set a timeout on the socket */
+ if (conf->timeout_set == 1) {
+ apr_setsocketopt(*newsock, APR_SO_TIMEOUT,
+ (int)(conf->timeout * APR_USEC_PER_SEC));
+ }
+ else {
+ apr_setsocketopt(*newsock, APR_SO_TIMEOUT,
+ (int)(s->timeout * APR_USEC_PER_SEC));
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, s,
+ "proxy: %s: fam %d socket created to connect to %s",
+ proxy_function, backend_addr->family, backend_name);
+
+ /* make the connection out of the socket */
+ rv = apr_connect(*newsock, backend_addr);
+
+ /* if an error occurred, loop round and try again */
+ if (rv != APR_SUCCESS) {
+ apr_socket_close(*newsock);
+ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+ ap_log_error(APLOG_MARK, loglevel, rv, s,
+ "proxy: %s: attempt to connect to %pI (%s) failed",
+ proxy_function,
+ backend_addr,
+ backend_name);
+ backend_addr = backend_addr->next;
+ continue;
+ }
+ connected = 1;
+ }
+ return connected ? 0 : 1;
+}
+