📄 mod_proxy.c
字号:
/* 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; } if (maxfwd >= 0) { apr_table_set(r->headers_in, "Max-Forwards", apr_psprintf(r->pool, "%ld", maxfwd)); } 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_METHOD_NOT_ALLOWED; } /* 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); /* Did the scheme handler process the request? */ if (access_status != DECLINED) { const char *cl_a; char *end; apr_off_t cl; /* * An fatal error or success, so no point in * retrying with a direct connection. */ if (access_status != HTTP_BAD_GATEWAY) { goto cleanup; } cl_a = apr_table_get(r->headers_in, "Content-Length"); if (cl_a) { apr_strtoff(&cl, cl_a, &end, 0); /* * The request body is of length > 0. We cannot * retry with a direct connection since we already * sent (parts of) the request body to the proxy * and do not have any longer. */ if (cl > 0) { goto cleanup; } } /* * Transfer-Encoding was set as input header, so we had * a request body. We cannot retry with a direct * connection for the same reason as above. */ if (apr_table_get(r->headers_in, "Transfer-Encoding")) { goto cleanup; } } } } } /* otherwise, try it direct */ /* N.B. what if we're behind a firewall, where we must use a proxy or * give up?? */ /* handle the scheme */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Running scheme %s handler (attempt %d)", scheme, attempts); access_status = proxy_run_scheme_handler(r, worker, conf, url, NULL, 0); if (access_status == OK) break; else if (access_status == HTTP_INTERNAL_SERVER_ERROR) { /* Unrecoverable server error. * We can not failover to another worker. * Mark the worker as unusable if member of load balancer */ if (balancer) worker->s->status |= PROXY_WORKER_IN_ERROR; break; } else if (access_status == HTTP_SERVICE_UNAVAILABLE) { /* Recoverable server error. * We can failover to another worker * Mark the worker as unusable if member of load balancer */ if (balancer) { worker->s->status |= PROXY_WORKER_IN_ERROR; } } else { /* Unrecoverable error. * Return the origin status code to the client. */ break; } /* Try again if the worker is unusable and the service is * unavailable. */ } while (!PROXY_WORKER_IS_USABLE(worker) && max_attempts > attempts++); if (DECLINED == access_status) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: No protocol handler was valid for the URL %s. " "If you are using a DSO version of mod_proxy, make sure " "the proxy submodules are included in the configuration " "using LoadModule.", r->uri); access_status = HTTP_INTERNAL_SERVER_ERROR; goto cleanup; }cleanup: if (balancer) { int post_status = proxy_run_post_request(worker, balancer, r, conf); if (post_status == DECLINED) { post_status = OK; /* no post_request handler available */ /* TODO: recycle direct worker */ } } proxy_run_request_status(&access_status, r); return access_status;}/* -------------------------------------------------------------- *//* Setup configurable data */static void * create_proxy_config(apr_pool_t *p, server_rec *s){ proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf)); ps->sec_proxy = apr_array_make(p, 10, sizeof(ap_conf_vector_t *)); ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote)); ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias)); ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry)); ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry)); ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int)); ps->workers = apr_array_make(p, 10, sizeof(proxy_worker)); ps->balancers = apr_array_make(p, 10, sizeof(proxy_balancer)); ps->forward = NULL; ps->reverse = NULL; ps->domain = NULL; ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */ ps->viaopt_set = 0; /* 0 means default */ ps->req = 0; ps->req_set = 0; ps->recv_buffer_size = 0; /* this default was left unset for some reason */ ps->recv_buffer_size_set = 0; ps->io_buffer_size = AP_IOBUFSIZE; ps->io_buffer_size_set = 0; ps->maxfwd = DEFAULT_MAX_FORWARDS; ps->maxfwd_set = 0; ps->error_override = 0; ps->error_override_set = 0; ps->preserve_host_set = 0; ps->preserve_host = 0; ps->timeout = 0; ps->timeout_set = 0; ps->badopt = bad_error; ps->badopt_set = 0; ps->pool = p; return ps;}static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv){ proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf)); proxy_server_conf *base = (proxy_server_conf *) basev; proxy_server_conf *overrides = (proxy_server_conf *) overridesv; ps->proxies = apr_array_append(p, base->proxies, overrides->proxies); ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy); ps->aliases = apr_array_append(p, base->aliases, overrides->aliases); ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies); ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn); ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports); ps->workers = apr_array_append(p, base->workers, overrides->workers); ps->balancers = apr_array_append(p, base->balancers, overrides->balancers);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -