]> granicus.if.org Git - apache/commitdiff
Add mod_proxy_ftp directives ProxyFtpListOnWildcard and ProxyFtpEscapeWildcards
authorEric Covener <covener@apache.org>
Thu, 26 Mar 2009 13:25:25 +0000 (13:25 +0000)
committerEric Covener <covener@apache.org>
Thu, 26 Mar 2009 13:25:25 +0000 (13:25 +0000)
to allow filenames with globbing characters to be retrieved instead of
presented in a directory listing.

Submitted by: Dan Poirier <poirier pobox.com>
Reviewed by: covener

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@758626 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/manual/mod/mod_proxy_ftp.xml
modules/proxy/mod_proxy_ftp.c

diff --git a/CHANGES b/CHANGES
index e8c8e8175399c367e6652cad288c1f678f954f8c..8b98652546ad623f2ee0373fbdd8210d00d92adf 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,10 @@
 
 Changes with Apache 2.3.3
 
+  *) mod_proxy_ftp: Add ProxyFtpListOnWildcard directive to allow files with
+     globbing characters to be retrieved instead of converted into a 
+     directory listing.  PR 46789 [Dan Poirier <poirier pobox.com>]
+
   *) Provide ap_set_retained_data()/ap_get_retained_data() for preservation
      of module state across unload/load.  [Jeff Trawick]
 
index 133407793b797ff2e3bd2f3f26178cbecaeeaa86..b9f7d95a23a9305fdecb33784c470126f9b352f7 100644 (file)
       </note>
     </section> <!-- /ftppass -->
 
+    <section id="wildcard"><title>Why do I get a file listing when I expected
+        a file to be downloaded?</title>
+      <p>In order to allow both browsing the directories on an FTP server and
+        downloading files, Apache looks at the request URL.  If it looks like
+        a directory, or contains wildcard characters ("*?[{~"), then it
+        guesses that a listing is wanted instead of a download.</p>
+      <p>You can disable the special handling of names with wildcard characters.
+        See the <directive>ProxyFtpListOnWildcard</directive> directive.
+      </p>
+    </section> <!-- /wildcard -->
+       
+<directivesynopsis>
+<name>ProxyFtpListOnWildcard</name>
+<description>Whether wildcards in requested filenames trigger a file listing</description>
+<syntax>ProxyFtpListOnWildcard [on|off]</syntax>
+<default>on</default>
+<contextlist><context>server config</context><context>virtual host</context>
+  <context>directory</context></contextlist>
+<compatibility>Available in Apache xxx and later</compatibility>
+
+<usage>
+  <p>The <directive>ProxyFtpListOnWildcard</directive> directive
+    controls whether wildcard characters ("*?[{~") in requested
+    filenames cause <module>mod_proxy_ftp</module> to return a listing
+    of files instead of downloading a file.  By default (value on),
+    they do.  Set to "off" to allow downloading files even if they
+    have wildcard characters in their names.</p>
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
+<name>ProxyFtpEscapeWildcards</name>
+<description>Whether wildcards in requested filenames are escaped when sent to the FTP server</description>
+<syntax>ProxyFtpEscapeWildcards [on|off]</syntax>
+<default>on</default>
+<contextlist><context>server config</context><context>virtual host</context>
+  <context>directory</context></contextlist>
+<compatibility>Available in Apache xxx and later</compatibility>
+
+<usage>
+  <p>The <directive>ProxyFtpEscapeWildcards</directive> directive
+    controls whether wildcard characters ("*?[{~") in requested
+    filenames are escaped with backslash before sending them to the
+    FTP server.  That is the default behavior, but many FTP servers
+    don't know about the escaping and try to serve the literal filenames
+    they were sent, including the backslashes in the names.  </p>
+    <p>Set to "off" to allow downloading files with wildcards
+    in their names from FTP servers that don't understand wildcard
+    escaping.</p>
+</usage>
+</directivesynopsis>
+
 
 </modulesynopsis>
index 028d766db2d6a70243469dda1bc34780d18cda6c..e0c1c07914413f41c30446efbd72ccbc368c3514 100644 (file)
 
 module AP_MODULE_DECLARE_DATA proxy_ftp_module;
 
+typedef struct {
+    int ftp_list_on_wildcard;
+    int ftp_list_on_wildcard_set;
+    int ftp_escape_wildcards;
+    int ftp_escape_wildcards_set;
+} proxy_ftp_dir_conf;
+
+static void *create_proxy_ftp_dir_config(apr_pool_t *p, char *dummy)
+{
+    proxy_ftp_dir_conf *new =
+        (proxy_ftp_dir_conf *) apr_pcalloc(p, sizeof(proxy_ftp_dir_conf));
+
+    /* Put these in the dir config so they work inside <Location> */
+    new->ftp_list_on_wildcard = 1;
+    new->ftp_escape_wildcards = 1;
+
+    return (void *) new;
+}
+
+static void *merge_proxy_ftp_dir_config(apr_pool_t *p, void *basev, void *addv)
+{
+    proxy_ftp_dir_conf *new = (proxy_ftp_dir_conf *) apr_pcalloc(p, sizeof(proxy_ftp_dir_conf));
+    proxy_ftp_dir_conf *add = (proxy_ftp_dir_conf *) addv;
+    proxy_ftp_dir_conf *base = (proxy_ftp_dir_conf *) basev;
+
+    /* Put these in the dir config so they work inside <Location> */
+    new->ftp_list_on_wildcard = add->ftp_list_on_wildcard_set ?
+                                add->ftp_list_on_wildcard :
+                                base->ftp_list_on_wildcard;
+    new->ftp_list_on_wildcard_set = add->ftp_list_on_wildcard_set ?
+                                1 :
+                                base->ftp_list_on_wildcard_set;
+    new->ftp_escape_wildcards = add->ftp_escape_wildcards_set ?
+                                add->ftp_escape_wildcards :
+                                base->ftp_escape_wildcards;
+    new->ftp_escape_wildcards_set = add->ftp_escape_wildcards_set ?
+                                1 :
+                                base->ftp_escape_wildcards_set;
+
+    return new;
+}
+
+static const char *set_ftp_list_on_wildcard(cmd_parms *cmd, void *dconf,
+                                            int flag)
+{
+    proxy_ftp_dir_conf *conf = dconf;
+
+    conf->ftp_list_on_wildcard = flag;
+    conf->ftp_list_on_wildcard_set = 1;
+    return NULL;
+}
+
+static const char *set_ftp_escape_wildcards(cmd_parms *cmd, void *dconf,
+                                            int flag)
+{
+    proxy_ftp_dir_conf *conf = dconf;
+
+    conf->ftp_escape_wildcards = flag;
+    conf->ftp_escape_wildcards_set = 1;
+    return NULL;
+}
+
 /*
  * Decodes a '%' escaped string, and returns the number of characters
  */
@@ -63,13 +125,21 @@ static int decodeenc(char *x)
  * Escape the globbing characters in a path used as argument to
  * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
  * ftpd assumes '\\' as a quoting character to escape special characters.
+ * Just returns the original string if ProxyFtpEscapeWildcards has been
+ * configured "off".
  * Returns: escaped string
  */
 #define FTP_GLOBBING_CHARS "*?[{~"
-static char *ftp_escape_globbingchars(apr_pool_t *p, const char *path)
+static const char *ftp_escape_globbingchars(apr_pool_t *p, const char *path, proxy_ftp_dir_conf *dconf)
 {
-    char *ret = apr_palloc(p, 2*strlen(path)+sizeof(""));
+    char *ret;
     char *d;
+    
+    if (!dconf->ftp_escape_wildcards) {
+        return path;
+    }
+
+    ret = apr_palloc(p, 2*strlen(path)+sizeof(""));
     for (d = ret; *path; ++path) {
         if (strchr(FTP_GLOBBING_CHARS, *path) != NULL)
             *d++ = '\\';
@@ -809,6 +879,8 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
 #if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
     apr_time_t mtime = 0L;
 #endif
+    proxy_ftp_dir_conf *fdconf = ap_get_module_config(r->per_dir_config,
+                                                      &proxy_ftp_module);
 
     /* stuff for PASV mode */
     int connect = 0, use_port = 0;
@@ -1157,7 +1229,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
          * We could also have extended gen_test_char.c with a special T_ESCAPE_FTP_PATH
          */
         rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
-                           ftp_escape_globbingchars(p, path), CRLF, NULL),
+                           ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
                            r, origin, bb, &ftpmessage);
         *strp = '/';
         /* responses: 250, 421, 500, 501, 502, 530, 550 */
@@ -1480,9 +1552,10 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
     }
 
     /* If len == 0 then it must be a directory (you can't RETR nothing)
-     * Also, don't allow to RETR by wildcard. Instead, create a dirlisting
+     * Also, don't allow to RETR by wildcard. Instead, create a dirlisting,
+     * unless ProxyFtpListOnWildcard is off.
      */
-    if (len == 0 || ftp_check_globbingchars(path)) {
+    if (len == 0 || (ftp_check_globbingchars(path) && fdconf->ftp_list_on_wildcard)) {
         dirlisting = 1;
     }
     else {
@@ -1503,7 +1576,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
         /* Therefore: switch to binary if the user did not specify ";type=a" */
         ftp_set_TYPE(xfer_type, r, origin, bb, &ftpmessage);
         rc = proxy_ftp_command(apr_pstrcat(p, "SIZE ",
-                           ftp_escape_globbingchars(p, path), CRLF, NULL),
+                           ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
                            r, origin, bb, &ftpmessage);
         if (rc == -1 || rc == 421) {
             return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
@@ -1522,7 +1595,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
                              "proxy: FTP: SIZE shows this is a directory");
             dirlisting = 1;
             rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
-                           ftp_escape_globbingchars(p, path), CRLF, NULL),
+                           ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
                            r, origin, bb, &ftpmessage);
             /* possible results: 250, 421, 500, 501, 502, 530, 550 */
             /* 250 Requested file action okay, completed. */
@@ -1583,7 +1656,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
          *     The "." and subsequent digits ("sss") are optional. <..>
          *     Time values are always represented in UTC (GMT)
          */
-        rc = proxy_ftp_command(apr_pstrcat(p, "MDTM ", ftp_escape_globbingchars(p, path), CRLF, NULL),
+        rc = proxy_ftp_command(apr_pstrcat(p, "MDTM ", ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
                                r, origin, bb, &ftpmessage);
         /* then extract the Last-Modified time from it (YYYYMMDDhhmmss or YYYYMMDDhhmmss.xxx GMT). */
         if (rc == 213) {
@@ -1622,7 +1695,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
     }
 #endif /* USE_MDTM */
 /* FIXME: Handle range requests - send REST */
-        buf = apr_pstrcat(p, "RETR ", ftp_escape_globbingchars(p, path), CRLF, NULL);
+        buf = apr_pstrcat(p, "RETR ", ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL);
     }
     rc = proxy_ftp_command(buf, r, origin, bb, &ftpmessage);
     /* rc is an intermediate response for the LIST or RETR commands */
@@ -1659,7 +1732,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
         ftp_set_TYPE('A', r, origin, bb, NULL);
 
         rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
-                               ftp_escape_globbingchars(p, path), CRLF, NULL),
+                               ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
                                r, origin, bb, &ftpmessage);
         /* possible results: 250, 421, 500, 501, 502, 530, 550 */
         /* 250 Requested file action okay, completed. */
@@ -1929,12 +2002,22 @@ static void ap_proxy_ftp_register_hook(apr_pool_t *p)
                               NULL, AP_FTYPE_RESOURCE);
 }
 
+static const command_rec proxy_ftp_cmds[] =
+{
+    AP_INIT_FLAG("ProxyFtpListOnWildcard", set_ftp_list_on_wildcard, NULL,
+     RSRC_CONF|ACCESS_CONF, "Whether wildcard characters in a path cause mod_proxy_ftp to list the files instead of trying to get them. Defaults to on."),
+    AP_INIT_FLAG("ProxyFtpEscapeWildcards", set_ftp_escape_wildcards, NULL,
+     RSRC_CONF|ACCESS_CONF, "Whether the proxy should escape wildcards in paths before sending them to the FTP server.  Defaults to on, but most FTP servers will need it turned off if you need to manage paths that contain wildcard characters."),
+    {NULL}
+};
+
+
 module AP_MODULE_DECLARE_DATA proxy_ftp_module = {
     STANDARD20_MODULE_STUFF,
-    NULL,                       /* create per-directory config structure */
-    NULL,                       /* merge per-directory config structures */
+    create_proxy_ftp_dir_config,/* create per-directory config structure */
+    merge_proxy_ftp_dir_config, /* merge per-directory config structures */
     NULL,                       /* create per-server config structure */
     NULL,                       /* merge per-server config structures */
-    NULL,                       /* command apr_table_t */
+    proxy_ftp_cmds,             /* command apr_table_t */
     ap_proxy_ftp_register_hook  /* register hooks */
 };