]> granicus.if.org Git - apache/commitdiff
FTP directory filter works now.
authorGraham Leggett <minfrin@apache.org>
Thu, 12 Apr 2001 01:57:48 +0000 (01:57 +0000)
committerGraham Leggett <minfrin@apache.org>
Thu, 12 Apr 2001 01:57:48 +0000 (01:57 +0000)
Many FIXME notes added.
Much overhauling of proxy_ftp.c
PR:
Obtained from:
Reviewed by:

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

modules/proxy/mod_proxy.c
modules/proxy/mod_proxy.h
modules/proxy/proxy_ftp.c
modules/proxy/proxy_http.c
modules/proxy/proxy_util.c

index dd9153a77e3d58a16fd9afcc683401fb6e9954f7..5d2cf97009ebfd27da848f798b32c5d64e9569a9 100644 (file)
@@ -410,8 +410,6 @@ static void * create_proxy_config(apr_pool_t *p, server_rec *s)
     ps->noproxies = ap_make_array(p, 10, sizeof(struct noproxy_entry));
     ps->dirconn = ap_make_array(p, 10, sizeof(struct dirconn_entry));
     ps->allowed_connect_ports = ap_make_array(p, 10, sizeof(int));
-/*    ps->client_socket = NULL;*/
-    ps->connection = NULL;
     ps->domain = NULL;
     ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
     ps->viaopt_set = 0; /* 0 means default */
@@ -721,7 +719,7 @@ static void register_hooks(apr_pool_t *p)
     /* filename-to-URI translation */
     ap_hook_translate_name(proxy_trans, NULL, NULL, APR_HOOK_FIRST);
     /* filters */
-    ap_register_output_filter("PROXY_SEND_DIR", ap_proxy_send_dir_filter, AP_FTYPE_CONNECTION);
+    ap_register_output_filter("PROXY_SEND_DIR", ap_proxy_send_dir_filter, AP_FTYPE_CONTENT);
     /* fixups */
     ap_hook_fixups(proxy_fixup, NULL, NULL, APR_HOOK_FIRST);
     /* post read_request handling */
index 7a8f6eab3101de40949024cc9251723e6f01298a..9e32cda9e7e08de2e9dc9488849248324f0eaa3a 100644 (file)
@@ -167,11 +167,6 @@ typedef struct {
     apr_array_header_t *noproxies;
     apr_array_header_t *dirconn;
     apr_array_header_t *allowed_connect_ports;
-    long id;
-    const char *connectname;
-    apr_port_t connectport;
-/*    apr_socket_t *client_socket;*/
-    conn_rec *connection;
     const char *domain;                /* domain name to use in absence of a domain name in the request */
     int req;                   /* true if proxy requests are enabled */
     char req_set;
@@ -215,7 +210,8 @@ int ap_proxy_connect_handler(request_rec *r, char *url,
 
 int ap_proxy_ftp_canon(request_rec *r, char *url);
 int ap_proxy_ftp_handler(request_rec *r, char *url);
-apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *bb);
+apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f,
+                                     apr_bucket_brigade *bb);
 
 
 /* proxy_http.c */
@@ -248,7 +244,7 @@ int ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p);
 int ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p);
 int ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr);
 int ap_proxy_pre_http_connection(conn_rec *c, request_rec *r);
-apr_status_t ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen);
+apr_status_t ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen, int *eos);
 void ap_proxy_reset_output_filters(conn_rec *c);
 
 #endif /*MOD_PROXY_H*/
index 83c53ba7015e655d71fa5f1131b7d02ce46c75bb..5c089a19076a3047b61cda29863d8f2fc6e31e9d 100644 (file)
@@ -198,9 +198,9 @@ static int ftp_getrc_msg(conn_rec *c, apr_bucket_brigade *bb, char *msgbuf, int
     char *mb = msgbuf,
         *me = &msgbuf[msglen];
     apr_status_t rv;
+    int eos;
 
-
-    if (APR_SUCCESS != (rv = ap_proxy_string_read(c, bb, response, sizeof(response)))) {
+    if (APR_SUCCESS != (rv = ap_proxy_string_read(c, bb, response, sizeof(response), &eos))) {
        return -1;
     }
     if (!apr_isdigit(response[0]) || !apr_isdigit(response[1]) ||
@@ -215,7 +215,7 @@ static int ftp_getrc_msg(conn_rec *c, apr_bucket_brigade *bb, char *msgbuf, int
        memcpy(buff, response, 3);
        buff[3] = ' ';
        do {
-           if (APR_SUCCESS != (rv = ap_proxy_string_read(c, bb, response, sizeof(response)))) {
+           if (APR_SUCCESS != (rv = ap_proxy_string_read(c, bb, response, sizeof(response), &eos))) {
                return -1;
            }
            mb = apr_cpystrn(mb, response + (' ' == response[0] ? 1 : 4), me - mb);
@@ -234,81 +234,156 @@ static int ftp_getrc_msg(conn_rec *c, apr_bucket_brigade *bb, char *msgbuf, int
  * all in good time...! :)
  */
 
-apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *bb)
+typedef struct {
+    apr_bucket_brigade *in;
+    char buffer[MAX_STRING_LEN];
+    enum {HEADER, BODY, FOOTER} state;
+} proxy_dir_ctx_t;
+
+apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in)
 {
-    conn_rec *c = f->r->connection;
-    apr_pool_t *p = f->r->pool;
+    request_rec *r = f->r;
+    apr_pool_t *p = r->pool;
     apr_bucket *e;
-    char buf[MAX_STRING_LEN];
-    char buf2[MAX_STRING_LEN];
+    apr_bucket_brigade *out = apr_brigade_create(p);
+    apr_status_t rv;
 
-    char *filename;
-    int searchidx = 0;
-    char *searchptr = NULL;
-    int firstfile = 1;
     register int n;
-    char *dir, *path, *reldir, *site;
+    char *dir, *path, *reldir, *site, *str;
 
-    char *cwd = NULL;
+    const char *pwd = apr_table_get(r->notes, "Directory-PWD");
+    const char *readme = apr_table_get(r->notes, "Directory-README");
 
+    proxy_dir_ctx_t *ctx = f->ctx;
+    if (!ctx) {
+       f->ctx = ctx = apr_pcalloc(p, sizeof(*ctx));
+       ctx->in = apr_brigade_create(p);
+       ctx->buffer[0] = 0;
+       ctx->state = HEADER;
+    }
 
-    /* Save "scheme://site" prefix without password */
-    site = ap_unparse_uri_components(p, &f->r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO);
-    /* ... and path without query args */
-    path = ap_unparse_uri_components(p, &f->r->parsed_uri, UNP_OMITSITEPART|UNP_OMITQUERY);
-    (void)decodeenc(path);
+    /* combine the stored and the new */
+    APR_BRIGADE_CONCAT(ctx->in, in);
+
+    if (HEADER == ctx->state) {
+
+       /* Save "scheme://site" prefix without password */
+       site = ap_unparse_uri_components(p, &f->r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO);
+       /* ... and path without query args */
+       path = ap_unparse_uri_components(p, &f->r->parsed_uri, UNP_OMITSITEPART|UNP_OMITQUERY);
+       (void)decodeenc(path);
+
+       /* Copy path, strip (all except the last) trailing slashes */
+       path = dir = apr_pstrcat(p, path, "/", NULL);
+       while ((n = strlen(path)) > 1 && path[n-1] == '/' && path[n-2] == '/')
+           path[n-1] = '\0';
+
+       /* print "ftp://host/" */
+       str = apr_psprintf(p, DOCTYPE_HTML_3_2
+                       "\n\n<HTML>\n<HEAD>\n<TITLE>%s%s</TITLE>\n"
+                       "<BASE HREF=\"%s%s\">\n</HEAD>\n\n"
+                       "<BODY>\n\n<H2>Directory of "
+                       "<A HREF=\"/\">%s</A>/",
+                       site, path, site, path, site);
+
+       e = apr_bucket_pool_create(str, strlen(str), p);
+       APR_BRIGADE_INSERT_TAIL(out, e);
+
+       while ((dir = strchr(dir+1, '/')) != NULL)
+       {
+           *dir = '\0';
+           if ((reldir = strrchr(path+1, '/'))==NULL)
+               reldir = path+1;
+           else
+               ++reldir;
+           /* print "path/" component */
+           str = apr_psprintf(p, "<A HREF=\"/%s/\">%s</A>/", path+1, reldir);
+           e = apr_bucket_pool_create(str, strlen(str), p);
+           APR_BRIGADE_INSERT_TAIL(out, e);
+           *dir = '/';
+       }
+       /* If the caller has determined the current directory, and it differs */
+       /* from what the client requested, then show the real name */
+       if (pwd == NULL || strncmp (pwd, path, strlen(pwd)) == 0) {
+           str = apr_psprintf(p, "</H2>\n\n<HR></HR>\n\n<PRE>");
+       } else {
+           str = apr_psprintf(p, "</H2>\n\n(%s)\n\n<HR></HR>\n\n<PRE>", pwd);
+       }
+       e = apr_bucket_pool_create(str, strlen(str), p);
+       APR_BRIGADE_INSERT_TAIL(out, e);
 
-    /* Copy path, strip (all except the last) trailing slashes */
-    path = dir = apr_pstrcat(p, path, "/", NULL);
-    while ((n = strlen(path)) > 1 && path[n-1] == '/' && path[n-2] == '/')
-       path[n-1] = '\0';
+       /* print README */
+       if (readme) {
+           str = apr_psprintf(p, "%s\n</PRE>\n\n<HR></HR>\n\n<PRE>\n",
+                            readme);
 
-    /* print "ftp://host/" */
-    n = apr_snprintf(buf, sizeof(buf), DOCTYPE_HTML_3_2
-               "<HTML><HEAD><TITLE>%s%s</TITLE>\n"
-               "<BASE HREF=\"%s%s\"></HEAD>\n"
-               "<BODY><H2>Directory of "
-               "<A HREF=\"/\">%s</A>/",
-               site, path, site, path, site);
+           e = apr_bucket_pool_create(str, strlen(str), p);
+           APR_BRIGADE_INSERT_TAIL(out, e);
+       }
 
-    e = apr_bucket_pool_create(buf, n, p);
-    APR_BRIGADE_INSERT_TAIL(bb, e);
+       /* make sure page intro gets sent out */
+       e = apr_bucket_flush_create();
+       APR_BRIGADE_INSERT_TAIL(out, e);
+       if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+           return rv;
+       }
+       apr_brigade_cleanup(out);
 
-    while ((dir = strchr(dir+1, '/')) != NULL)
-    {
-       *dir = '\0';
-       if ((reldir = strrchr(path+1, '/'))==NULL)
-           reldir = path+1;
-       else
-           ++reldir;
-       /* print "path/" component */
-       n = apr_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, reldir);
-       e = apr_bucket_pool_create(buf, n, p);
-       APR_BRIGADE_INSERT_TAIL(bb, e);
-       *dir = '/';
-    }
-    /* If the caller has determined the current directory, and it differs */
-    /* from what the client requested, then show the real name */
-    if (cwd == NULL || strncmp (cwd, path, strlen(cwd)) == 0) {
-       n = apr_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>");
-    } else {
-       n = apr_snprintf(buf, sizeof(buf), "</H2>\n(%s)\n<HR><PRE>", cwd);
+       ctx->state = BODY;
     }
-    e = apr_bucket_pool_create(buf, n, p);
-    APR_BRIGADE_INSERT_TAIL(bb, e);
 
-    e = apr_bucket_flush_create();
-    APR_BRIGADE_INSERT_TAIL(bb, e);
+    /* loop through each line of directory */
+    while (BODY == ctx->state) {
+       char *filename;
+       int found = 0;
+       int eos = 0;
+       ctx->buffer[0] = 0;
+
+       /* get a complete line */
+       while (!found && !APR_BRIGADE_EMPTY(ctx->in)) {
+           char *pos, *response;
+           apr_size_t len, max;
+           e = APR_BRIGADE_FIRST(ctx->in);
+           if (APR_BUCKET_IS_EOS(e)) {
+               eos = 1;
+               break;
+           }
+           if (APR_SUCCESS != (rv = apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ))) {
+               return rv;
+           }
+           pos = memchr(response, APR_ASCII_LF, len);
+           if (pos != NULL) {
+               if ((pos - response + 1) != len) {
+                   apr_bucket_split(e, pos - response + 1);
+               }
+               found = 1;
+           }
+           max = sizeof(ctx->buffer)-strlen(ctx->buffer)-1;
+           if (len > max) {
+               len = max;
+           }
+           apr_cpystrn(ctx->buffer+strlen(ctx->buffer), response, len);
+           APR_BUCKET_REMOVE(e);
+           apr_bucket_destroy(e);
+       }
 
-    while (!c->aborted) {
-       n = ap_getline(buf, sizeof(buf), f->r, 0);
-       if (n == -1) {          /* input error */
+       /* EOS? jump to footer */
+       if (eos) {
+           ctx->state = FOOTER;
            break;
        }
-       if (n == 0) {
-           break;              /* EOF */
+
+       /* not complete? leave and try get some more */
+       if (!found) {
+           return APR_SUCCESS;
        }
-       if (buf[0] == 'l' && (filename=strstr(buf, " -> ")) != NULL) {
+
+ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                      "proxy: directory line: [%s]", ctx->buffer);
+
+
+       /* a symlink? */
+       if (ctx->buffer[0] == 'l' && (filename=strstr(ctx->buffer, " -> ")) != NULL) {
            char *link_ptr = filename;
 
            do {
@@ -318,65 +393,76 @@ apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *bb)
            *(link_ptr++) = '\0';
            if ((n = strlen(link_ptr)) > 1 && link_ptr[n - 1] == '\n')
              link_ptr[n - 1] = '\0';
-           apr_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s %s</A>\n", buf, filename, filename, link_ptr);
-           apr_cpystrn(buf, buf2, sizeof(buf));
-           n = strlen(buf);
+           str = apr_psprintf(p, "%s <A HREF=\"%s\">%s %s</A>\n", ctx->buffer, filename, filename, link_ptr);
        }
-       else if (buf[0] == 'd' || buf[0] == '-' || buf[0] == 'l' || apr_isdigit(buf[0])) {
-           if (apr_isdigit(buf[0])) {  /* handle DOS dir */
-               searchptr = strchr(buf, '<');
+
+       /* a directory/file? */
+       else if (ctx->buffer[0] == 'd' || ctx->buffer[0] == '-' || ctx->buffer[0] == 'l' || apr_isdigit(ctx->buffer[0])) {
+           int searchidx = 0;
+           char *searchptr = NULL;
+           int firstfile = 1;
+           if (apr_isdigit(ctx->buffer[0])) {  /* handle DOS dir */
+               searchptr = strchr(ctx->buffer, '<');
                if (searchptr != NULL)
                    *searchptr = '[';
-               searchptr = strchr(buf, '>');
+               searchptr = strchr(ctx->buffer, '>');
                if (searchptr != NULL)
                    *searchptr = ']';
            }
 
-           filename = strrchr(buf, ' ');
+           filename = strrchr(ctx->buffer, ' ');
            *(filename++) = 0;
            filename[strlen(filename) - 1] = 0;
 
            /* handle filenames with spaces in 'em */
            if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
                firstfile = 0;
-               searchidx = filename - buf;
+               searchidx = filename - ctx->buffer;
            }
-           else if (searchidx != 0 && buf[searchidx] != 0) {
+           else if (searchidx != 0 && ctx->buffer[searchidx] != 0) {
                *(--filename) = ' ';
-               buf[searchidx - 1] = 0;
-               filename = &buf[searchidx];
+               ctx->buffer[searchidx - 1] = 0;
+               filename = &ctx->buffer[searchidx];
            }
 
            /* Special handling for '.' and '..' */
-           if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') {
-               apr_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s/\">%s</A>\n",
-                   buf, filename, filename);
+           if (!strcmp(filename, ".") || !strcmp(filename, "..") || ctx->buffer[0] == 'd') {
+               str = apr_psprintf(p, "%s <A HREF=\"%s/\">%s</A>\n",
+                   ctx->buffer, filename, filename);
            }
            else {
-               apr_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\n", buf, filename, filename);
+               str = apr_psprintf(p, "%s <A HREF=\"%s\">%s</A>\n",
+                   ctx->buffer, filename, filename);
            }
-           apr_cpystrn(buf, buf2, sizeof(buf));
-           n = strlen(buf);
        }
 
-       e = apr_bucket_pool_create(buf, n, p);
-       APR_BRIGADE_INSERT_TAIL(bb, e);
+       e = apr_bucket_pool_create(str, strlen(str), p);
+       APR_BRIGADE_INSERT_TAIL(out, e);
        e = apr_bucket_flush_create();
-       APR_BRIGADE_INSERT_TAIL(bb, e);
+       APR_BRIGADE_INSERT_TAIL(out, e);
+       if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+           return rv;
+       }
+       apr_brigade_cleanup(out);
 
     }
 
-    n = apr_snprintf(buf, sizeof(buf), "</PRE><HR>\n%s</BODY></HTML>\n", ap_psignature("", f->r));
-    e = apr_bucket_pool_create(buf, n, p);
-    APR_BRIGADE_INSERT_TAIL(bb, e);
+    if (FOOTER == ctx->state) {
+       str = apr_psprintf(p, "</PRE>\n\n<HR></HR>\n\n%s\n\n</BODY>\n</HTML>\n", ap_psignature("", r));
+       e = apr_bucket_pool_create(str, strlen(str), p);
+       APR_BRIGADE_INSERT_TAIL(out, e);
 
-    e = apr_bucket_eos_create();
-    APR_BRIGADE_INSERT_TAIL(bb, e);
+       e = apr_bucket_flush_create();
+       APR_BRIGADE_INSERT_TAIL(out, e);
 
-/* probably not necessary */
-/*    e = apr_bucket_flush_create();
-    APR_BRIGADE_INSERT_TAIL(bb, e);
-*/
+       e = apr_bucket_eos_create();
+       APR_BRIGADE_INSERT_TAIL(out, e);
+
+       if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+           return rv;
+       }
+       apr_brigade_destroy(out);
+    }
 
     return APR_SUCCESS;
 }
@@ -420,6 +506,7 @@ static int ftp_unauthorized (request_rec *r, int log_it)
 int ap_proxy_ftp_handler(request_rec *r, char *url)
 {
     apr_pool_t *p = r->pool;
+    conn_rec *c = r->connection;
     apr_socket_t *sock, *local_sock, *remote_sock;
     apr_sockaddr_t *connect_addr;
     apr_status_t rv;
@@ -432,7 +519,6 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     apr_port_t connectport;
     char buffer[MAX_STRING_LEN];
     char *path, *strp, *parms;
-    char *cwd = NULL;
     char *user = NULL;
 /*    char *account = NULL; how to supply an account in a URL? */
     const char *password = NULL;
@@ -448,6 +534,16 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     proxy_server_conf *conf =
     (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
 
+    proxy_conn_rec *backend =
+    (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_module);
+    if (!backend) {
+       backend = ap_pcalloc(c->pool, sizeof(proxy_conn_rec));
+       backend->connection = NULL;
+       backend->hostname = NULL;
+       backend->port = 0;
+       ap_set_module_config(c->conn_config, &proxy_module, backend);
+    }
+
 
     /*
      * I: Who Do I Connect To?
@@ -616,15 +712,10 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
 
     /* if a keepalive connection is floating around, close it first! */
     /* we might support ftp keepalives later, but not now... */
-    if ((conf->id == r->connection->id) && conf->connection) {
-       apr_socket_close(conf->connection->client_socket);
-       conf->connection = NULL;
+    if (backend->connection) {
+       apr_socket_close(backend->connection->client_socket);
+       backend->connection = NULL;
     }
-    conf->id = r->connection->id;
-    /* allocate this out of the connection pool - the check on r->connection->id makes
-     * sure that this string does not get accessed past the connection lifetime */
-    conf->connectname = apr_pstrdup(r->connection->pool, connectname);
-    conf->connectport = connectport;
 
     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                 "proxy: connection complete");
@@ -647,7 +738,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /*   421 Service not available, closing control connection. */
     i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                "proxy: FTP: initial connect returned status %d", i);
+                "proxy: FTP: %d %s", i, buffer);
     if (i == -1) {
        return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
     }
@@ -695,7 +786,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /*   530 Not logged in. */
     i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                 "proxy: FTP: returned status %d", i);
+                "proxy: FTP: %d %s", i, buffer);
     if (i == -1) {
        return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
     }
@@ -728,8 +819,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        /*   503 Bad sequence of commands. */
        /*   530 Not logged in. */
        i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                     "proxy: FTP: returned status %d [%s]", i, buffer);
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                "proxy: FTP: %d %s", i, buffer);
        if (i == -1) {
            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                 "Error reading from remote server");
@@ -776,8 +867,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        /*   530 Not logged in. */
        /*   550 Requested action not taken. */
        i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                     "proxy: FTP: returned status %d", i);
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                "proxy: FTP: %d %s", i, buffer);
        if (i == -1) {
            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                 "Error reading from remote server");
@@ -791,6 +882,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
 
        path = strp + 1;
     }
+    apr_table_set(r->notes, "Directory-README", buffer);
 
     if (parms != NULL && strncasecmp(parms, "type=a", 6) == 0) {
        parms = "A";
@@ -817,8 +909,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /*   504 Command not implemented for that parameter. */
     /*   530 Not logged in. */
     i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                "proxy: FTP: returned status %d", i);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                "proxy: FTP: %d %s", i, buffer);
     if (i == -1) {
        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Error reading from remote server");
@@ -838,16 +930,23 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
      *
      * Try PASV, if that fails try normally.
      */
+/* this temporarily switches off PASV */
 /*goto bypass;*/
 
     /* try to set up PASV data connection first */
+/* IPV6 FIXME:
+ * The EPSV command replaces PASV where both IPV4 and IPV6 is supported. Only
+ * the port is returned, the IP address is always the same as that on the
+ * control connection. Example:
+ *   Entering Extended Passive Mode (|||6446|)
+ */
     buf = apr_pstrcat(p, "PASV", CRLF, NULL);
     e = apr_bucket_pool_create(buf, strlen(buf), p);
     APR_BRIGADE_INSERT_TAIL(bb, e);
     e = apr_bucket_flush_create();
     APR_BRIGADE_INSERT_TAIL(bb, e);
     ap_pass_brigade(origin->output_filters, bb);
-    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                  "proxy: FTP: PASV");
     /* possible results: 227, 421, 500, 501, 502, 530 */
     /*   227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
@@ -857,8 +956,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /*   502 Command not implemented. */
     /*   530 Not logged in. */
     i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                "proxy: FTP: returned status %d", i);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                "proxy: FTP: %d %s", i, buffer);
     if (i == -1) {
        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Error reading from remote server");
@@ -870,6 +969,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        unsigned int h0, h1, h2, h3, p0, p1;
        char *pstr;
 
+/* FIXME: Check PASV against RFC1123 */
+
        pstr = apr_pstrdup(p, buffer);
        pstr = strtok(pstr, " ");       /* separate result code */
        if (pstr != NULL) {
@@ -883,7 +984,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
            }
        }
 
-/* FIXME: Only supports IPV4 */
+/* FIXME: Only supports IPV4 - fix in RFC2428 */
 
        if (pstr != NULL && (sscanf(pstr,
                 "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) {
@@ -932,13 +1033,14 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        apr_sockaddr_t *local_addr;
        char *local_ip;
        apr_port_t local_port;
+       unsigned int h0, h1, h2, h3, p0, p1;
 
        if ((apr_socket_create(&local_sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                         "proxy: FTP: error creating local socket");
            return HTTP_INTERNAL_SERVER_ERROR;
        }
-        apr_socket_addr_get(&local_addr, APR_LOCAL, local_sock);
+        apr_socket_addr_get(&local_addr, APR_LOCAL, sock);
         apr_sockaddr_port_get(&local_port, local_addr);
         apr_sockaddr_ip_get(&local_ip, local_addr);
 
@@ -950,7 +1052,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
 #endif /*_OSD_POSIX*/
        }
 
-        if (apr_sockaddr_info_get(&local_addr, local_ip, APR_INET,
+        if (apr_sockaddr_info_get(&local_addr, local_ip, APR_UNSPEC,
                                  local_port, 0, r->pool) != APR_SUCCESS) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                           "proxy: FTP: error creating local socket address");
@@ -965,6 +1067,49 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
 
        /* only need a short queue */
        apr_listen(local_sock, 2);
+
+/* FIXME: Sent PORT here */
+
+       if (local_ip && (sscanf(local_ip,
+                "%d.%d.%d.%d", &h3, &h2, &h1, &h0) == 4)) {
+           p1 = (local_port >> 8);
+           p0 = (local_port & 0xFF);
+
+           buf = apr_psprintf(p, "PORT %d,%d,%d,%d,%d,%d" CRLF, h3, h2, h1, h0, p1, p0);
+           e = apr_bucket_pool_create(buf, strlen(buf), p);
+           APR_BRIGADE_INSERT_TAIL(bb, e);
+           e = apr_bucket_flush_create();
+           APR_BRIGADE_INSERT_TAIL(bb, e);
+           ap_pass_brigade(origin->output_filters, bb);
+            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                         "proxy: FTP: PORT %d,%d,%d,%d,%d,%d", h3, h2, h1, h0, p1, p0);
+           /* possible results: 200, 421, 500, 501, 502, 530 */
+           /*   200 Command okay. */
+           /*   421 Service not available, closing control connection. */
+           /*   500 Syntax error, command unrecognized. */
+           /*   501 Syntax error in parameters or arguments. */
+           /*   502 Command not implemented. */
+           /*   530 Not logged in. */
+           rc = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
+           ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                "proxy: FTP: %d %s", rc, buffer);
+           if (rc == -1) {
+               return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                                    "Error reading from remote server");
+           }
+           if (rc != 200) {
+               return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer);
+           }
+       }
+       else {
+/* IPV6 FIXME:
+ * The EPRT command replaces PORT where both IPV4 and IPV6 is supported. The first
+ * number (1,2) indicates the protocol type. Examples:
+ *   EPRT |1|132.235.1.2|6275|
+ *   EPRT |2|1080::8:800:200C:417A|5282|
+ */
+           return ap_proxyerror(r, HTTP_NOT_IMPLEMENTED, "Connect to IPV6 ftp server not supported");
+       }
     }
 
 
@@ -993,7 +1138,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
         ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                      "proxy: FTP: SIZE %s", path);
        i = ftp_getrc_msg(origin, cbb, buffer, sizeof buffer);
-        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                      "proxy: FTP: returned status %d with response %s", i, buffer);
        if (i != 500) {         /* Size command not recognized */
            if (i == 550) {     /* Not a regular file */
@@ -1017,8 +1162,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
                /* 502 Command not implemented. */
                /* 530 Not logged in. */
                /* 550 Requested action not taken. */
-                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                             "proxy: FTP: returned status %d", i);
+                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                            "proxy: FTP: %d %s", i, buffer);
                if (i == -1) {
                    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                         "Error reading from remote server");
@@ -1060,8 +1205,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /*   502 Command not implemented. */
     /*   550 Requested action not taken. */
     i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                                "proxy: FTP: PWD returned status %d", i);
+       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                                "proxy: FTP: %d %s", i, buffer);
     if (i == -1 || i == 421) {
        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Error reading from remote server");
@@ -1071,7 +1216,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     }
     if (i == 257) {
        const char *dirp = buffer;
-       cwd = ap_getword_conf(r->pool, &dirp);
+       apr_table_set(r->notes, "Directory-PWD", ap_getword_conf(r->pool, &dirp));
     }
 #endif /*AUTODETECT_PWD*/
 
@@ -1084,6 +1229,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
                     "proxy: FTP: LIST %s", (len == 0 ? "-lag" : path));
     }
     else {
+/* FIXME: Handle range requests - send REST */
        buf = apr_pstrcat(p, "RETR ", path, CRLF, NULL);
        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                     "proxy: FTP: RETR %s", path);
@@ -1110,8 +1256,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /*   530 Not logged in. */
     /*   550 Requested action not taken. */
     rc = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                 "proxy: FTP: returned status %d", rc);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                "proxy: FTP: %d %s", rc, buffer);
     if (rc == -1) {
        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Error reading from remote server");
@@ -1137,8 +1283,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        /*   530 Not logged in. */
        /*   550 Requested action not taken. */
        rc = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                                "proxy: FTP: returned status %d", rc);
+       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                                "proxy: FTP: %d %s", rc, buffer);
        if (rc == -1) {
            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Error reading from remote server");
@@ -1167,8 +1313,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        /*   502 Command not implemented. */
        /*   550 Requested action not taken. */
        i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                                "proxy: FTP: PWD returned status %d", i);
+       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                                "proxy: FTP: %d %s", i, buffer);
        if (i == -1 || i == 421) {
            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Error reading from remote server");
@@ -1178,7 +1324,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        }
        if (i == 257) {
            const char *dirp = buffer;
-           cwd = ap_getword_conf(r->pool, &dirp);
+           apr_table_set(r->notes, "Directory-PWD", ap_getword_conf(r->pool, &dirp));
        }
 #endif /*AUTODETECT_PWD*/
 
@@ -1188,11 +1334,11 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        e = apr_bucket_flush_create();
        APR_BRIGADE_INSERT_TAIL(bb, e);
        ap_pass_brigade(origin->output_filters, bb);
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                                 "proxy: FTP: LIST -lag");
        rc = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                                "proxy: FTP: returned status %d", rc);
+       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                                "proxy: FTP: %d %s", rc, buffer);
        if (rc == -1)
            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Error reading from remote server");
@@ -1208,8 +1354,10 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     apr_table_setn(r->headers_out, "Date", dates);
     apr_table_setn(r->headers_out, "Server", ap_get_server_version());
 
-    if (parms[0] == 'd')
-               apr_table_setn(r->headers_out, "Content-Type", "text/plain");
+    if (parms[0] == 'd') {
+       r->content_type = "text/html";
+       apr_table_setn(r->headers_out, "Content-Type", r->content_type);
+    }
     else {
        if (r->content_type != NULL) {
            apr_table_setn(r->headers_out, "Content-Type", r->content_type);
@@ -1226,9 +1374,11 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
                 "proxy: FTP: Content-Length set to %s", size);
        }
     }
+ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                        "proxy: FTP: Content-Type set to %s", r->content_type);
     if (r->content_encoding != NULL && r->content_encoding[0] != '\0') {
-               ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                "proxy: FTP: Content-Encoding set to %s", r->content_encoding);
+               ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                            "proxy: FTP: Content-Encoding set to %s", r->content_encoding);
        apr_table_setn(r->headers_out, "Content-Encoding", r->content_encoding);
     }
 
@@ -1236,6 +1386,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     if (!pasvmode) {
         for(;;)
         {
+/* FIXME: this does not return, despite the incoming connection being accepted */
             switch(apr_accept(&remote_sock, local_sock, r->pool))
             {
             case APR_EINTR:
@@ -1250,6 +1401,9 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
         }
     }
 
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                  "proxy: FTP: ready to suck data");
+
     /* the transfer socket is now open, create a new connection */
     remote = ap_new_connection(p, r->server, remote_sock, r->connection->id);
     if (!remote) {
@@ -1263,8 +1417,6 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /* set up the connection filters */
     ap_proxy_pre_http_connection(remote, NULL);
 
-/* XXX temporary end here while testing */
-/*return HTTP_NOT_IMPLEMENTED;*/
 
     /*
      * VI: Receive the Response
@@ -1277,12 +1429,13 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /* send response */
     r->sent_bodyct = 1;
 
-#ifdef FTP_FILTER
-   if (parms[0] == 'd') {
+    /* read till EOF */
+    c->remain = -1;
+
+    if (parms[0] == 'd') {
        /* insert directory filter */
        ap_add_output_filter("PROXY_SEND_DIR", NULL, r, r->connection);
-   }
-#endif
+    }
 
     /* send body */
     if (!r->header_only) {
@@ -1293,6 +1446,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        /* read the body, pass it to the output filters */
        while (ap_get_brigade(remote->input_filters, bb, AP_MODE_BLOCKING) == APR_SUCCESS) {
            if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+               e = apr_bucket_flush_create();
+               APR_BRIGADE_INSERT_TAIL(bb, e);
                ap_pass_brigade(r->output_filters, bb);
                break;
            }
@@ -1301,8 +1456,7 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        }
        apr_brigade_cleanup(bb);
        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                    "proxy: FTP end body send");
-
+                    "proxy: FTP: end body send");
 
     }
     else {
@@ -1324,8 +1478,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
        /*   501 Syntax error in parameters or arguments. */
        /*   502 Command not implemented. */
        i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                    "proxy: FTP: returned status %d", i);
+       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                    "proxy: FTP: %d %s", i, buffer);
     }
 
 
@@ -1350,8 +1504,8 @@ int ap_proxy_ftp_handler(request_rec *r, char *url)
     /*   221 Service closing control connection. */
     /*   500 Syntax error, command unrecognized. */
     i = ftp_getrc_msg(origin, cbb, buffer, sizeof(buffer));
-    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-                 "proxy: FTP: QUIT: status %d", i);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                 "proxy: FTP: %d %s", i, buffer);
 
     apr_brigade_destroy(bb);
     return OK;
index c69acb69d6b8c1a99b398a2ff0ffd1e72feae937..27387c9985826192895845ec48eec07a0a752e92 100644 (file)
@@ -175,7 +175,7 @@ int ap_proxy_http_handler(request_rec *r, char *url,
     apr_sockaddr_t *connect_addr;
     char server_portstr[32];
     apr_socket_t *sock;
-    int i, len, backasswards, close=0, failed=0, new=0;
+    int i, len, backasswards, eos, close=0, failed=0, new=0;
     apr_status_t err, rv;
     apr_array_header_t *headers_in_array;
     apr_table_entry_t *headers_in;
@@ -587,7 +587,7 @@ int ap_proxy_http_handler(request_rec *r, char *url,
 
     apr_brigade_cleanup(bb);
 
-    if (APR_SUCCESS != (rv = ap_proxy_string_read(origin, bb, buffer, sizeof(buffer)))) {
+    if (APR_SUCCESS != (rv = ap_proxy_string_read(origin, bb, buffer, sizeof(buffer), &eos))) {
        apr_socket_close(sock);
        backend->connection = NULL;
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
@@ -733,6 +733,8 @@ int ap_proxy_http_handler(request_rec *r, char *url,
        /* read the body, pass it to the output filters */
        while (ap_get_brigade(rp->input_filters, bb, AP_MODE_BLOCKING) == APR_SUCCESS) {
            if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+               e = apr_bucket_flush_create();
+               APR_BRIGADE_INSERT_TAIL(bb, e);
                ap_pass_brigade(r->output_filters, bb);
                break;
            }
index 42c45648a339f43534c66440bace2253c96d081c..8a99573764bbc5e55217f2ccbf779cc6fa0d4870 100644 (file)
@@ -1082,7 +1082,8 @@ int ap_proxy_pre_http_connection(conn_rec *c, request_rec *r)
 }
 
 /* converts a series of buckets into a string */
-apr_status_t ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen)
+apr_status_t ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb,
+                                 char *buff, size_t bufflen, int *eos)
 {
     apr_bucket *e;
     apr_status_t rv;
@@ -1093,6 +1094,7 @@ apr_status_t ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buf
 
     /* start with an empty string */
     buff[0] = 0;
+    *eos = 0;
 
     /* get line-at-a-time */
     c->remain = 0;
@@ -1108,6 +1110,9 @@ apr_status_t ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buf
        /* loop through each bucket */
        while (!found && !APR_BRIGADE_EMPTY(bb)) {
            e = APR_BRIGADE_FIRST(bb);
+           if (APR_BUCKET_IS_EOS(e)) {
+               *eos = 1;
+           }
            if (APR_SUCCESS != apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ)) {
                return rv;
            }