mod_proxy.c

来自「apache服务器源代码(版本号:2.2.2)」· C语言 代码 · 共 1,862 行 · 第 1/5 页

C
1,862
字号
static int proxy_detect(request_rec *r){    void *sconf = r->server->module_config;    proxy_server_conf *conf =        (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);    /* Ick... msvc (perhaps others) promotes ternary short results to int */    if (conf->req && r->parsed_uri.scheme) {        /* but it might be something vhosted */        if (!(r->parsed_uri.hostname              && !strcasecmp(r->parsed_uri.scheme, ap_http_scheme(r))              && ap_matches_request_vhost(r, r->parsed_uri.hostname,                                          (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port                                                       : ap_default_port(r))))) {            r->proxyreq = PROXYREQ_PROXY;            r->uri = r->unparsed_uri;            r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);            r->handler = "proxy-server";        }    }    /* We need special treatment for CONNECT proxying: it has no scheme part */    else if (conf->req && r->method_number == M_CONNECT             && r->parsed_uri.hostname             && r->parsed_uri.port_str) {        r->proxyreq = PROXYREQ_PROXY;        r->uri = r->unparsed_uri;        r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);        r->handler = "proxy-server";    }    return DECLINED;}static int proxy_trans(request_rec *r){    void *sconf = r->server->module_config;    proxy_server_conf *conf =    (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);    int i, len;    struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;    if (r->proxyreq) {        /* someone has already set up the proxy, it was possibly ourselves         * in proxy_detect         */        return OK;    }    /* XXX: since r->uri has been manipulated already we're not really     * compliant with RFC1945 at this point.  But this probably isn't     * an issue because this is a hybrid proxy/origin server.     */    for (i = 0; i < conf->aliases->nelts; i++) {        len = alias_match(r->uri, ent[i].fake);       if (len > 0) {           if ((ent[i].real[0] == '!') && (ent[i].real[1] == 0)) {               return DECLINED;           }           r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,                                     r->uri + len, NULL);           r->handler = "proxy-server";           r->proxyreq = PROXYREQ_REVERSE;           return OK;       }    }    return DECLINED;}static int proxy_walk(request_rec *r){    proxy_server_conf *sconf = ap_get_module_config(r->server->module_config,                                                    &proxy_module);    ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults;    ap_conf_vector_t **sec_proxy = (ap_conf_vector_t **) sconf->sec_proxy->elts;    ap_conf_vector_t *entry_config;    proxy_dir_conf *entry_proxy;    int num_sec = sconf->sec_proxy->nelts;    /* XXX: shouldn't we use URI here?  Canonicalize it first?     * Pass over "proxy:" prefix     */    const char *proxyname = r->filename + 6;    int j;    for (j = 0; j < num_sec; ++j)    {        entry_config = sec_proxy[j];        entry_proxy = ap_get_module_config(entry_config, &proxy_module);        /* XXX: What about case insensitive matching ???         * Compare regex, fnmatch or string as appropriate         * If the entry doesn't relate, then continue         */        if (entry_proxy->r              ? ap_regexec(entry_proxy->r, proxyname, 0, NULL, 0)              : (entry_proxy->p_is_fnmatch                   ? apr_fnmatch(entry_proxy->p, proxyname, 0)                   : strncmp(proxyname, entry_proxy->p,                                        strlen(entry_proxy->p)))) {            continue;        }        per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults,                                                             entry_config);    }    r->per_dir_config = per_dir_defaults;    return OK;}static int proxy_map_location(request_rec *r){    int access_status;    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)        return DECLINED;    /* Don't let the core or mod_http map_to_storage hooks handle this,     * We don't need directory/file_walk, and we want to TRACE on our own.     */    if ((access_status = proxy_walk(r))) {        ap_die(access_status, r);        return access_status;    }    return OK;}/* -------------------------------------------------------------- *//* Fixup the filename *//* * Canonicalise the URL */static int proxy_fixup(request_rec *r){    char *url, *p;    int access_status;    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)        return DECLINED;    /* XXX: Shouldn't we try this before we run the proxy_walk? */    url = &r->filename[6];    /* canonicalise each specific scheme */    if ((access_status = proxy_run_canon_handler(r, url))) {        return access_status;    }    p = strchr(url, ':');    if (p == NULL || p == url)        return HTTP_BAD_REQUEST;    return OK;      /* otherwise; we've done the best we can */}/* Send a redirection if the request contains a hostname which is not *//* fully qualified, i.e. doesn't have a domain name appended. Some proxy *//* servers like Netscape's allow this and access hosts from the local *//* domain in this case. I think it is better to redirect to a FQDN, since *//* these will later be found in the bookmarks files. *//* The "ProxyDomain" directive determines what domain will be appended */static int proxy_needsdomain(request_rec *r, const char *url, const char *domain){    char *nuri;    const char *ref;    /* We only want to worry about GETs */    if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)        return DECLINED;    /* If host does contain a dot already, or it is "localhost", decline */    if (strchr(r->parsed_uri.hostname, '.') != NULL     || strcasecmp(r->parsed_uri.hostname, "localhost") == 0)        return DECLINED;    /* host name has a dot already */    ref = apr_table_get(r->headers_in, "Referer");    /* Reassemble the request, but insert the domain after the host name */    /* Note that the domain name always starts with a dot */    r->parsed_uri.hostname = apr_pstrcat(r->pool, r->parsed_uri.hostname,                                         domain, NULL);    nuri = apr_uri_unparse(r->pool,                           &r->parsed_uri,                           APR_URI_UNP_REVEALPASSWORD);    apr_table_set(r->headers_out, "Location", nuri);    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,                  "Domain missing: %s sent to %s%s%s", r->uri,                  apr_uri_unparse(r->pool, &r->parsed_uri,                                  APR_URI_UNP_OMITUSERINFO),                  ref ? " from " : "", ref ? ref : "");    return HTTP_MOVED_PERMANENTLY;}/* -------------------------------------------------------------- *//* Invoke handler */static int proxy_handler(request_rec *r){    char *uri, *scheme, *p;    const char *p2;    void *sconf = r->server->module_config;    proxy_server_conf *conf = (proxy_server_conf *)        ap_get_module_config(sconf, &proxy_module);    apr_array_header_t *proxies = conf->proxies;    struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;    int i, rc, access_status;    int direct_connect = 0;    const char *str;    long maxfwd;    proxy_balancer *balancer = NULL;    proxy_worker *worker = NULL;    int attempts = 0, max_attempts = 0;    struct dirconn_entry *list = (struct dirconn_entry *)conf->dirconn->elts;    /* is this for us? */    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)        return DECLINED;    /* handle max-forwards / OPTIONS / TRACE */    if ((str = apr_table_get(r->headers_in, "Max-Forwards"))) {        maxfwd = strtol(str, NULL, 10);        if (maxfwd < 1) {            switch (r->method_number) {            case M_TRACE: {                int access_status;                r->proxyreq = PROXYREQ_NONE;                if ((access_status = ap_send_http_trace(r)))                    ap_die(access_status, r);                else                    ap_finalize_request_protocol(r);                return OK;            }            case M_OPTIONS: {                int access_status;                r->proxyreq = PROXYREQ_NONE;                if ((access_status = ap_send_http_options(r)))                    ap_die(access_status, r);                else                    ap_finalize_request_protocol(r);                return OK;            }            default: {                return ap_proxyerror(r, HTTP_BAD_GATEWAY,                                     "Max-Forwards has reached zero - proxy loop?");            }            }        }        maxfwd = (maxfwd > 0) ? maxfwd - 1 : 0;    }    else {        /* set configured max-forwards */        maxfwd = conf->maxfwd;    }    apr_table_set(r->headers_in, "Max-Forwards",                  apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0));    if (r->method_number == M_TRACE) {        core_server_config *coreconf = (core_server_config *)                            ap_get_module_config(sconf, &core_module);        if (coreconf->trace_enable == AP_TRACE_DISABLE)        {            /* Allow "error-notes" string to be printed by ap_send_error_response()             * Note; this goes nowhere, canned error response need an overhaul.             */            apr_table_setn(r->notes, "error-notes",                           "TRACE forbidden by server configuration");            apr_table_setn(r->notes, "verbose-error-to", "*");            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                          "proxy: TRACE forbidden by server configuration");            return HTTP_FORBIDDEN;        }        /* Can't test ap_should_client_block, we aren't ready to send         * the client a 100 Continue response till the connection has         * been established         */        if (coreconf->trace_enable != AP_TRACE_EXTENDED            && (r->read_length || r->read_chunked || r->remaining))        {            /* Allow "error-notes" string to be printed by ap_send_error_response()             * Note; this goes nowhere, canned error response need an overhaul.             */            apr_table_setn(r->notes, "error-notes",                           "TRACE with request body is not allowed");            apr_table_setn(r->notes, "verbose-error-to", "*");            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                          "proxy: TRACE with request body is not allowed");            return HTTP_REQUEST_ENTITY_TOO_LARGE;        }    }    uri = r->filename + 6;    p = strchr(uri, ':');    if (p == NULL) {        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,                      "proxy_handler no URL in %s", r->filename);        return HTTP_BAD_REQUEST;    }    /* If the host doesn't have a domain name, add one and redirect. */    if (conf->domain != NULL) {        rc = proxy_needsdomain(r, uri, conf->domain);        if (ap_is_HTTP_REDIRECT(rc))            return HTTP_MOVED_PERMANENTLY;    }    scheme = apr_pstrndup(r->pool, uri, p - uri);    /* Check URI's destination host against NoProxy hosts */    /* Bypass ProxyRemote server lookup if configured as NoProxy */    for (direct_connect = i = 0; i < conf->dirconn->nelts &&                                        !direct_connect; i++) {        direct_connect = list[i].matcher(&list[i], r);    }#if DEBUGGING    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,                (direct_connect) ? "NoProxy for %s" : "UseProxy for %s",                r->uri);#endif    do {        char *url = uri;        /* Try to obtain the most suitable worker */        access_status = ap_proxy_pre_request(&worker, &balancer, r, conf, &url);        if (access_status != OK) {            /*             * Only return if access_status is not HTTP_SERVICE_UNAVAILABLE             * This gives other modules the chance to hook into the             * request_status hook and decide what to do in this situation.             */            if (access_status != HTTP_SERVICE_UNAVAILABLE)                return access_status;            /*             * Ensure that balancer is NULL if worker is NULL to prevent             * potential problems in the post_request hook.             */            if (!worker)                balancer = NULL;            goto cleanup;        }        if (balancer && balancer->max_attempts_set && !max_attempts)            max_attempts = balancer->max_attempts;        /* firstly, try a proxy, unless a NoProxy directive is active */        if (!direct_connect) {            for (i = 0; i < proxies->nelts; i++) {                p2 = ap_strchr_c(ents[i].scheme, ':');  /* is it a partial URL? */                if (strcmp(ents[i].scheme, "*") == 0 ||                    (ents[i].use_regex &&                     ap_regexec(ents[i].regexp, url, 0, NULL, 0) == 0) ||                    (p2 == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||                    (p2 != NULL &&                    strncasecmp(url, ents[i].scheme,                                strlen(ents[i].scheme)) == 0)) {                    /* handle the scheme */                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                                 "Trying to run scheme_handler against proxy");                    access_status = proxy_run_scheme_handler(r, worker,                                                             conf, url,                                                             ents[i].hostname,                                                             ents[i].port);                    /* an error or success */                    if (access_status != DECLINED &&                        access_status != HTTP_BAD_GATEWAY) {                        goto cleanup;                    }                    /* we failed to talk to the upstream proxy */                }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?