📄 mod_proxy_http.c
字号:
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) { ap_set_content_type(r, apr_pstrdup(p, buf)); } ap_proxy_pre_http_request(origin,rp); /* handle Via header in response */ if (conf->viaopt != via_off && conf->viaopt != via_block) { const char *server_name = ap_get_server_name(r); /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host, * then the server name returned by ap_get_server_name() is the * origin server name (which does make too much sense with Via: headers) * so we use the proxy vhost's name instead. */ if (server_name == r->hostname) server_name = r->server->server_hostname; /* create a "Via:" response header entry and merge it */ apr_table_mergen(r->headers_out, "Via", (conf->viaopt == via_full) ? apr_psprintf(p, "%d.%d %s%s (%s)", HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num), server_name, server_portstr, AP_SERVER_BASEVERSION) : apr_psprintf(p, "%d.%d %s%s", HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num), server_name, server_portstr) ); } /* cancel keepalive if HTTP/1.0 or less */ if ((major < 1) || (minor < 1)) { backend->close += 1; origin->keepalive = AP_CONN_CLOSE; } } else { /* an http/0.9 response */ backasswards = 1; r->status = 200; r->status_line = "200 OK"; backend->close += 1; } interim_response = ap_is_HTTP_INFO(r->status); if (interim_response) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "proxy: HTTP: received interim %d response", r->status); } /* Moved the fixups of Date headers and those affected by * ProxyPassReverse/etc from here to ap_proxy_read_headers */ if ((r->status == 401) && (conf->error_override != 0)) { const char *buf; const char *wa = "WWW-Authenticate"; if ((buf = apr_table_get(r->headers_out, wa))) { apr_table_set(r->err_headers_out, wa, buf); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: origin server sent 401 without WWW-Authenticate header"); } } r->sent_bodyct = 1; /* * Is it an HTTP/0.9 response or did we maybe preread the 1st line of * the response? If so, load the extra data. These are 2 mutually * exclusive possibilities, that just happen to require very * similar behavior. */ if (backasswards || pread_len) { apr_ssize_t cntr = (apr_ssize_t)pread_len; if (backasswards) { /*@@@FIXME: * At this point in response processing of a 0.9 response, * we don't know yet whether data is binary or not. * mod_charset_lite will get control later on, so it cannot * decide on the conversion of this buffer full of data. * However, chances are that we are not really talking to an * HTTP/0.9 server, but to some different protocol, therefore * the best guess IMHO is to always treat the buffer as "text/x": */ ap_xlate_proto_to_ascii(buffer, len); cntr = (apr_ssize_t)len; } e = apr_bucket_heap_create(buffer, cntr, NULL, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); } /* send body - but only if a body is expected */ if ((!r->header_only) && /* not HEAD request */ !interim_response && /* not any 1xx response */ (r->status != HTTP_NO_CONTENT) && /* not 204 */ (r->status != HTTP_NOT_MODIFIED)) { /* not 304 */ /* We need to copy the output headers and treat them as input * headers as well. BUT, we need to do this before we remove * TE, so that they are preserved accordingly for * ap_http_filter to know where to end. */ rp->headers_in = apr_table_copy(r->pool, r->headers_out); apr_table_unset(r->headers_out,"Transfer-Encoding"); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: start body send"); /* * if we are overriding the errors, we can't put the content * of the page into the brigade */ if (conf->error_override == 0 || ap_is_HTTP_SUCCESS(r->status)) { /* read the body, pass it to the output filters */ apr_read_type_e mode = APR_NONBLOCK_READ; int finish = FALSE; do { apr_off_t readbytes; apr_status_t rv; rv = ap_get_brigade(rp->input_filters, bb, AP_MODE_READBYTES, mode, conf->io_buffer_size); /* ap_get_brigade will return success with an empty brigade * for a non-blocking read which would block: */ if (APR_STATUS_IS_EAGAIN(rv) || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) { /* flush to the client and switch to blocking mode */ e = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); if (ap_pass_brigade(r->output_filters, bb) || c->aborted) { backend->close = 1; break; } apr_brigade_cleanup(bb); mode = APR_BLOCK_READ; continue; } else if (rv == APR_EOF) { break; } else if (rv != APR_SUCCESS) { /* In this case, we are in real trouble because * our backend bailed on us. Pass along a 502 error * error bucket */ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, "proxy: error reading response"); ap_proxy_backend_broke(r, bb); ap_pass_brigade(r->output_filters, bb); backend_broke = 1; backend->close = 1; break; } /* next time try a non-blocking read */ mode = APR_NONBLOCK_READ; apr_brigade_length(bb, 0, &readbytes); backend->worker->s->read += readbytes;#if DEBUGGING { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy (PID %d): readbytes: %#x", getpid(), readbytes); }#endif /* sanity check */ if (APR_BRIGADE_EMPTY(bb)) { apr_brigade_cleanup(bb); break; } /* found the last brigade? */ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) { /* signal that we must leave */ finish = TRUE; } /* try send what we read */ if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS || c->aborted) { /* Ack! Phbtt! Die! User aborted! */ backend->close = 1; /* this causes socket close below */ finish = TRUE; } /* make sure we always clean up after ourselves */ apr_brigade_cleanup(bb); } while (!finish); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: end body send"); } else if (!interim_response) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: header only"); /* Pass EOS bucket down the filter chain. */ e = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS || c->aborted) { /* Ack! Phbtt! Die! User aborted! */ backend->close = 1; /* this causes socket close below */ } apr_brigade_cleanup(bb); } } while (interim_response); /* If our connection with the client is to be aborted, return DONE. */ if (c->aborted || backend_broke) { return DONE; } if (conf->error_override) { /* the code above this checks for 'OK' which is what the hook expects */ if (ap_is_HTTP_SUCCESS(r->status)) return OK; else { /* clear r->status for override error, otherwise ErrorDocument * thinks that this is a recursive error, and doesn't find the * custom error page */ int status = r->status; r->status = HTTP_OK; /* Discard body, if one is expected */ if ((status != HTTP_NO_CONTENT) && /* not 204 */ (status != HTTP_NOT_MODIFIED)) { /* not 304 */ ap_discard_request_body(rp); } return status; } } else return OK;}staticapr_status_t ap_proxy_http_cleanup(const char *scheme, request_rec *r, proxy_conn_rec *backend){ ap_proxy_release_connection(scheme, backend, r->server); return OK;}/* * This handles http:// URLs, and other URLs using a remote proxy over http * If proxyhost is NULL, then contact the server directly, otherwise * go via the proxy. * Note that if a proxy is used, then URLs other than http: can be accessed, * also, if we have trouble which is clearly specific to the proxy, then * we return DECLINED so that we can try another proxy. (Or the direct * route.) */static int proxy_http_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, char *url, const char *proxyname, apr_port_t proxyport){ int status; char server_portstr[32]; char *scheme; const char *proxy_function; const char *u; proxy_conn_rec *backend = NULL; int is_ssl = 0; /* Note: Memory pool allocation. * A downstream keepalive connection is always connected to the existence * (or not) of an upstream keepalive connection. If this is not done then * load balancing against multiple backend servers breaks (one backend * server ends up taking 100% of the load), and the risk is run of * downstream keepalive connections being kept open unnecessarily. This * keeps webservers busy and ties up resources. * * As a result, we allocate all sockets out of the upstream connection * pool, and when we want to reuse a socket, we check first whether the * connection ID of the current upstream connection is the same as that * of the connection when the socket was opened. */ apr_pool_t *p = r->connection->pool; conn_rec *c = r->connection; apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri)); /* find the scheme */ u = strchr(url, ':'); if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0') return DECLINED; if ((u - url) > 14) return HTTP_BAD_REQUEST; scheme = apr_pstrndup(c->pool, url, u - url); /* scheme is lowercase */ ap_str_tolower(scheme); /* is it for us? */ if (strcmp(scheme, "https") == 0) { if (!ap_proxy_ssl_enable(NULL)) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: HTTPS: declining URL %s" " (mod_ssl not configured?)", url); return DECLINED; } is_ssl = 1; proxy_function = "HTTPS"; } else if (!(strcmp(scheme, "http") == 0 || (strcmp(scheme, "ftp") == 0 && proxyname))) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: HTTP: declining URL %s", url); return DECLINED; /* only interested in HTTP, or FTP via proxy */ } else { if (*scheme == 'h') proxy_function = "HTTP"; else proxy_function = "FTP"; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: HTTP: serving URL %s", url); /* create space for state information */ if ((status = ap_proxy_acquire_connection(proxy_function, &backend, worker, r->server)) != OK) goto cleanup; backend->is_ssl = is_ssl; /* * TODO: Currently we cannot handle persist
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -