View | Details | Raw Unified | Return to bug 41676
Collapse All | Expand All

(-)mod_proxy_ftp.c (-140 / +124 lines)
Lines 37-42 Link Here
37
37
38
module AP_MODULE_DECLARE_DATA proxy_ftp_module;
38
module AP_MODULE_DECLARE_DATA proxy_ftp_module;
39
39
40
const char *proxy_function = "FTP";
41
40
/*
42
/*
41
 * Decodes a '%' escaped string, and returns the number of characters
43
 * Decodes a '%' escaped string, and returns the number of characters
42
 */
44
 */
Lines 744-776 Link Here
744
    proxy_ftp_cleanup(r, conn);
746
    proxy_ftp_cleanup(r, conn);
745
    return ap_proxyerror(r, statuscode, message);
747
    return ap_proxyerror(r, statuscode, message);
746
}
748
}
747
/*
749
748
 * Handles direct access of ftp:// URLs
750
static
749
 * Original (Non-PASV) version from
751
apr_status_t ap_proxy_ftp_cleanup(request_rec *r,
750
 * Troy Morrison <spiffnet@zoom.com>
752
                                   proxy_conn_rec *backend)
751
 * PASV added by Chuck
752
 * Filters by [Graham Leggett <minfrin@sharp.fm>]
753
 */
754
static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
755
                             proxy_server_conf *conf, char *url,
756
                             const char *proxyhost, apr_port_t proxyport)
757
{
753
{
758
    apr_pool_t *p = r->pool;
754
    ap_proxy_release_connection(proxy_function, backend, r->server);
759
    conn_rec *c = r->connection;
755
    return OK;
760
    proxy_conn_rec *backend;
756
}
757
758
static int ap_proxy_ftp_request(apr_pool_t* p, request_rec *r,
759
                                proxy_conn_rec *backend, conn_rec *c,
760
                                proxy_server_conf *conf,
761
                                apr_uri_t *uri,
762
                                char *url, char *server_portstr)
763
{
761
    apr_socket_t *sock, *local_sock, *data_sock = NULL;
764
    apr_socket_t *sock, *local_sock, *data_sock = NULL;
762
    apr_sockaddr_t *connect_addr = NULL;
765
    apr_sockaddr_t *connect_addr = backend->addr;
763
    apr_status_t rv;
766
    apr_status_t rv;
764
    conn_rec *origin, *data = NULL;
767
    conn_rec *origin, *data = NULL;
765
    apr_status_t err = APR_SUCCESS;
768
    apr_status_t err = APR_SUCCESS;
766
    apr_status_t uerr = APR_SUCCESS;
767
    apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
769
    apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
768
    char *buf, *connectname;
770
    char *buf;
769
    apr_port_t connectport;
770
    char buffer[MAX_STRING_LEN];
771
    char buffer[MAX_STRING_LEN];
771
    char *ftpmessage = NULL;
772
    char *ftpmessage = NULL;
772
    char *path, *strp, *type_suffix, *cwd = NULL;
773
    char *path, *strp, *type_suffix, *cwd = NULL;
773
    apr_uri_t uri;
774
    char *user = NULL;
774
    char *user = NULL;
775
/*    char *account = NULL; how to supply an account in a URL? */
775
/*    char *account = NULL; how to supply an account in a URL? */
776
    const char *password = NULL;
776
    const char *password = NULL;
Lines 787-839 Link Here
787
    int connect = 0, use_port = 0;
787
    int connect = 0, use_port = 0;
788
    char dates[APR_RFC822_DATE_LEN];
788
    char dates[APR_RFC822_DATE_LEN];
789
    int status;
789
    int status;
790
    apr_pool_t *address_pool;
791
790
792
    /* is this for us? */
791
    path = apr_pstrdup(p, uri->path);
793
    if (proxyhost) {
794
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
795
                     "proxy: FTP: declining URL %s - proxyhost %s specified:", url, proxyhost);
796
        return DECLINED;        /* proxy connections are via HTTP */
797
    }
798
    if (strncasecmp(url, "ftp:", 4)) {
799
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
800
                     "proxy: FTP: declining URL %s - not ftp:", url);
801
        return DECLINED;        /* only interested in FTP */
802
    }
803
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
804
                 "proxy: FTP: serving URL %s", url);
805
792
806
793
    if (uri->port == 0) {
807
    /*
794
        uri->port = apr_uri_port_of_scheme("ftp");
808
     * I: Who Do I Connect To? -----------------------
809
     *
810
     * Break up the URL to determine the host to connect to
811
     */
812
813
    /* we only support GET and HEAD */
814
    if (r->method_number != M_GET)
815
        return HTTP_NOT_IMPLEMENTED;
816
817
    /* We break the URL into host, port, path-search */
818
    if (r->parsed_uri.hostname == NULL) {
819
        if (APR_SUCCESS != apr_uri_parse(p, url, &uri)) {
820
            return ap_proxyerror(r, HTTP_BAD_REQUEST,
821
                apr_psprintf(p, "URI cannot be parsed: %s", url));
822
        }
823
        connectname = uri.hostname;
824
        connectport = uri.port;
825
        path = apr_pstrdup(p, uri.path);
826
    }
795
    }
827
    else {
828
        connectname = r->parsed_uri.hostname;
829
        connectport = r->parsed_uri.port;
830
        path = apr_pstrdup(p, r->parsed_uri.path);
831
    }
832
    if (connectport == 0) {
833
        connectport = apr_uri_port_of_scheme("ftp");
834
    }
835
    path = (path != NULL && path[0] != '\0') ? &path[1] : "";
796
    path = (path != NULL && path[0] != '\0') ? &path[1] : "";
836
837
    type_suffix = strchr(path, ';');
797
    type_suffix = strchr(path, ';');
838
    if (type_suffix != NULL)
798
    if (type_suffix != NULL)
839
        *(type_suffix++) = '\0';
799
        *(type_suffix++) = '\0';
Lines 893-983 Link Here
893
    }
853
    }
894
854
895
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
855
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
896
       "proxy: FTP: connecting %s to %s:%d", url, connectname, connectport);
856
       "proxy: FTP: connecting %s to %s:%d", url, uri->hostname, uri->port);
897
857
898
    if (worker->is_address_reusable) {
899
        if (!worker->cp->addr) {
900
            if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) {
901
                ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server,
902
                             "proxy: FTP: lock");
903
                return HTTP_INTERNAL_SERVER_ERROR;
904
            }
905
        }
906
        connect_addr = worker->cp->addr;
907
        address_pool = worker->cp->pool;
908
    }
909
    else
910
        address_pool = r->pool;
911
912
    /* do a DNS lookup for the destination host */
913
    if (!connect_addr)
914
        err = apr_sockaddr_info_get(&(connect_addr),
915
                                    connectname, APR_UNSPEC,
916
                                    connectport, 0,
917
                                    address_pool);
918
    if (worker->is_address_reusable && !worker->cp->addr) {
919
        worker->cp->addr = connect_addr;
920
        if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) {
921
            ap_log_error(APLOG_MARK, APLOG_ERR, uerr, r->server,
922
                         "proxy: FTP: unlock");
923
        }
924
    }
925
    /*
926
     * get all the possible IP addresses for the destname and loop through
927
     * them until we get a successful connection
928
     */
929
    if (APR_SUCCESS != err) {
858
    if (APR_SUCCESS != err) {
930
        return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
859
        return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
931
                                                 "DNS lookup failure for: ",
860
                                                 "DNS lookup failure for: ",
932
                                                        connectname, NULL));
861
                                                        uri->hostname, NULL));
933
    }
862
    }
934
863
935
    /* check if ProxyBlock directive on this host */
936
    if (OK != ap_proxy_checkproxyblock(r, conf, connect_addr)) {
937
        return ap_proxyerror(r, HTTP_FORBIDDEN,
938
                             "Connect to remote machine blocked");
939
    }
940
941
    /* create space for state information */
942
    backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_ftp_module);
943
    if (!backend) {
944
        status = ap_proxy_acquire_connection("FTP", &backend, worker, r->server);
945
        if (status != OK) {
946
            if (backend) {
947
                backend->close = 1;
948
                ap_proxy_release_connection("FTP", backend, r->server);
949
            }
950
            return status;
951
        }
952
        /* TODO: see if ftp could use determine_connection */
953
        backend->addr = connect_addr;
954
        ap_set_module_config(c->conn_config, &proxy_ftp_module, backend);
955
    }
956
957
958
    /*
959
     * II: Make the Connection -----------------------
960
     *
961
     * We have determined who to connect to. Now make the connection.
962
     */
963
964
965
    if (ap_proxy_connect_backend("FTP", backend, worker, r->server)) {
966
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
967
                     "proxy: FTP: an error occurred creating a new connection to %pI (%s)",
968
                     connect_addr, connectname);
969
        proxy_ftp_cleanup(r, backend);
970
        return HTTP_SERVICE_UNAVAILABLE;
971
    }
972
973
    if (!backend->connection) {
974
        status = ap_proxy_connection_create("FTP", backend, c, r->server);
975
        if (status != OK) {
976
            proxy_ftp_cleanup(r, backend);
977
            return status;
978
        }
979
    }
980
981
    /* Use old naming */
864
    /* Use old naming */
982
    origin = backend->connection;
865
    origin = backend->connection;
983
    sock = backend->sock;
866
    sock = backend->sock;
Lines 1886-1891 Link Here
1886
    return OK;
1769
    return OK;
1887
}
1770
}
1888
1771
1772
/*
1773
 * Handles direct access of ftp:// URLs
1774
 * Original (Non-PASV) version from
1775
 * Troy Morrison <spiffnet@zoom.com>
1776
 * PASV added by Chuck
1777
 * Filters by [Graham Leggett <minfrin@sharp.fm>]
1778
 */
1779
static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
1780
                             proxy_server_conf *conf,
1781
                             char *url, const char *proxyname,
1782
                             apr_port_t proxyport)
1783
{
1784
    int status;
1785
    char server_portstr[32];
1786
    char *scheme;
1787
    const char *u;
1788
    proxy_conn_rec *backend = NULL;
1789
1790
    /* Note: Memory pool allocation.
1791
     * A downstream keepalive connection is always connected to the existence
1792
     * (or not) of an upstream keepalive connection. If this is not done then
1793
     * load balancing against multiple backend servers breaks (one backend
1794
     * server ends up taking 100% of the load), and the risk is run of
1795
     * downstream keepalive connections being kept open unnecessarily. This
1796
     * keeps webservers busy and ties up resources.
1797
     *
1798
     * As a result, we allocate all sockets out of the upstream connection
1799
     * pool, and when we want to reuse a socket, we check first whether the
1800
     * connection ID of the current upstream connection is the same as that
1801
     * of the connection when the socket was opened.
1802
     */
1803
    apr_pool_t *p = r->connection->pool;
1804
    conn_rec *c = r->connection;
1805
    apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri));
1806
1807
    /* find the scheme */
1808
    u = strchr(url, ':');
1809
    if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0')
1810
        return DECLINED;
1811
    scheme = apr_pstrndup(c->pool, url, u - url);
1812
    /* scheme is lowercase */
1813
    ap_str_tolower(scheme);
1814
    /* is it for us? */
1815
    if (strcmp(scheme, "ftp") || proxyname) {
1816
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1817
                "proxy: FTP: declining URL %s", url);
1818
        return DECLINED; /* only interested in direct FTP */
1819
    }
1820
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1821
            "proxy: FTP: serving URL %s", url);
1822
1823
    /* we only support GET and HEAD -- this should go away.FTP has mappings
1824
     * for all HTTP methods. */
1825
    if (r->method_number != M_GET)
1826
        return HTTP_NOT_IMPLEMENTED;
1827
1828
    /* create space for state information */
1829
    if ((status = ap_proxy_acquire_connection(proxy_function, &backend,
1830
                    worker, r->server)) != OK)
1831
        goto cleanup;
1832
1833
1834
    /* Step One: Determine Who To Connect To */
1835
    if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend,
1836
                    uri, &url, 0,
1837
                    0, server_portstr,
1838
                    sizeof(server_portstr))) != OK)
1839
        goto cleanup;
1840
1841
    /* Step Two: Make the Connection */
1842
    if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
1843
        status = HTTP_SERVICE_UNAVAILABLE;
1844
        goto cleanup;
1845
    }
1846
1847
    /* Step Three: Create conn_rec */
1848
    if (!backend->connection) {
1849
        if ((status = ap_proxy_connection_create(proxy_function, backend,
1850
                        c, r->server)) != OK)
1851
            goto cleanup;
1852
    }
1853
1854
    /* Step Four: Initiate Ftp Request */
1855
    if ((status = ap_proxy_ftp_request(p, r, backend, backend->connection,
1856
                    conf, uri, url, server_portstr)) != OK)
1857
        goto cleanup;
1858
1859
    /* Step Five: Receive the Response -- is included in previous step */
1860
1861
    /* Step Six: Clean Up */
1862
1863
cleanup:
1864
    if (backend) {
1865
        if (status != OK)
1866
            backend->close = 1;
1867
        ap_proxy_ftp_cleanup(r, backend);
1868
    }
1869
    return status;
1870
1871
}
1872
1889
static void ap_proxy_ftp_register_hook(apr_pool_t *p)
1873
static void ap_proxy_ftp_register_hook(apr_pool_t *p)
1890
{
1874
{
1891
    /* hooks */
1875
    /* hooks */

Return to bug 41676