I was thinking along the lines of the following patch. The mod_proxy_ftp developer should be able to do a much better job as I am not a coder. It seems to work alright for anonymous and authenticated ftp traversal and is a good proof of concept. I can supply a patch for 2.2.3 if required but I need to upgrade my test proxy first, plus I need sleep now.
Regards, Jon --- /dev/httpd-2.2.0/modules/proxy/mod_proxy_ftp.c.dist 2006-08-22 20:21:33.000000000 +1000 +++ /dev/httpd-2.2.0/modules/proxy/mod_proxy_ftp.c.new 2006-08-23 04:39:19.000000000 +1000 @@ -292,13 +292,15 @@ apr_status_t rv; register int n; - char *dir, *path, *reldir, *site, *str, *type; + char *dir, *path, *reldir, *site, *str, *type, *location_header; const char *pwd = apr_table_get(r->notes, "Directory-PWD"); const char *readme = apr_table_get(r->notes, "Directory-README"); + const char *location = apr_table_get(r->notes, "Redirect-REQ"); proxy_dir_ctx_t *ctx = f->ctx; + if (!ctx) { f->ctx = ctx = apr_pcalloc(p, sizeof(*ctx)); ctx->in = apr_brigade_create(p, c->bucket_alloc); @@ -398,24 +400,54 @@ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p, c->bucket_alloc)); - /* print README */ - if (readme) { + /* Do we need a location header ( redirect ) ? */ + if ( location ) + { + + /* Set a temporary redirect */ + r->status_line = "302 Found"; + + /* Concatenate the domain and url then set the Location header*/ + location_header = apr_pstrcat(p, site, path, NULL); + apr_table_setn(r->headers_out, "Location", ap_escape_uri(p, location_header)); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "FTP REDIRECT: %s", ap_escape_uri(p, ap_escape_uri(p, location_header))); + + /* Add the typical redirect content */ + str = apr_psprintf(p, "The document has moved <a.href=\"%s\">here\n</a></pre><pre>\n", ap_escape_uri(p, location_header)); + + APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, + strlen(str), p, + c->bucket_alloc)); + + /* No need to return a body although we did get a listing */ + ctx->state = FOOTER; + + } + else { + /* print README */ + if (readme) { str = apr_psprintf(p, "%s\n</pre>\n\n<hr />\n\n<pre>\n", ap_escape_html(p, readme)); APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p, c->bucket_alloc)); - } + } + + ctx->state = BODY; + + } /* make sure page intro gets sent out */ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc)); if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) { - return rv; - } - apr_brigade_cleanup(out); + return rv; - ctx->state = BODY; + + apr_brigade_cleanup(out); + } } /* loop through each line of directory */ @@ -1481,6 +1513,9 @@ rc = proxy_ftp_command(apr_pstrcat(p, "CWD ", ftp_escape_globbingchars(p, path), CRLF, NULL), r, origin, bb, &ftpmessage); + + apr_table_set(r->notes, "Redirect-REQ", "true"); + /* possible results: 250, 421, 500, 501, 502, 530, 550 */ /* 250 Requested file action okay, completed. */ /* 421 Service not available, closing control connection. */