📄 proxy_http.c
字号:
* ap_send_error relies on a headers_out to be present. we * are in a bad position here.. so force everything we send out * to have nothing to do with the incoming packet */ r->headers_out = apr_table_make(r->pool,1); r->status = HTTP_BAD_GATEWAY; r->status_line = "bad gateway"; return r->status; } else { /* strip connection listed hop-by-hop headers from response */ const char *buf; p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_out, "Connection"), "close"); ap_proxy_clear_connection(p, r->headers_out); 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) { /* 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), ap_get_server_name(r), server_portstr, AP_SERVER_BASEVERSION) : apr_psprintf(p, "%d.%d %s%s", HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num), ap_get_server_name(r), server_portstr) ); } /* cancel keepalive if HTTP/1.0 or less */ if ((major < 1) || (minor < 1)) { p_conn->close += 1; origin->keepalive = AP_CONN_CLOSE; } } else { /* an http/0.9 response */ backasswards = 1; r->status = 200; r->status_line = "200 OK"; p_conn->close += 1; } if ( r->status != HTTP_CONTINUE ) { received_continue = 0; } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "proxy: HTTP: received 100 CONTINUE"); } /* we must accept 3 kinds of date, but generate only 1 kind of date */ { const char *buf; if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) { apr_table_set(r->headers_out, "Date", ap_proxy_date_canon(p, buf)); } if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) { apr_table_set(r->headers_out, "Expires", ap_proxy_date_canon(p, buf)); } if ((buf = apr_table_get(r->headers_out, "Last-Modified")) != NULL) { apr_table_set(r->headers_out, "Last-Modified", ap_proxy_date_canon(p, buf)); } } /* munge the Location and URI response headers according to * ProxyPassReverse */ { const char *buf; if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) { apr_table_set(r->headers_out, "Location", ap_proxy_location_reverse_map(r, conf, buf)); } if ((buf = apr_table_get(r->headers_out, "Content-Location")) != NULL) { apr_table_set(r->headers_out, "Content-Location", ap_proxy_location_reverse_map(r, conf, buf)); } if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) { apr_table_set(r->headers_out, "URI", ap_proxy_location_reverse_map(r, conf, buf)); } } 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? If so, send the extra data */ if (backasswards) { apr_ssize_t cntr = 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 */ (r->status > 199) && /* not any 1xx response */ (r->status != HTTP_NO_CONTENT) && /* not 204 */ (r->status != HTTP_RESET_CONTENT) && /* not 205 */ (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) || r->status < 400 ) { /* read the body, pass it to the output filters */ int finish = FALSE; while (ap_get_brigade(rp->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, conf->io_buffer_size) == APR_SUCCESS) {#if DEBUGGING { apr_off_t readbytes; apr_brigade_length(bb, 0, &readbytes); 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))) { /* if this is the last brigade, cleanup the * backend connection first to prevent the * backend server from hanging around waiting * for a slow client to eat these bytes */ ap_proxy_http_cleanup(r, p_conn, backend); /* 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! */ p_conn->close = 1; /* this causes socket close below */ finish = TRUE; } /* make sure we always clean up after ourselves */ apr_brigade_cleanup(bb); /* if we are done, leave */ if (TRUE == finish) { break; } } } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: end body send"); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: header only"); } } if ( conf->error_override ) { /* the code above this checks for 'OK' which is what the hook expects */ if ( r->status == HTTP_OK ) 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 > 199) && /* not any 1xx response */ (status != HTTP_NO_CONTENT) && /* not 204 */ (status != HTTP_RESET_CONTENT) && /* not 205 */ (status != HTTP_NOT_MODIFIED)) { /* not 304 */ ap_discard_request_body(rp); } return status; } } else return OK;}staticapr_status_t ap_proxy_http_cleanup(request_rec *r, proxy_http_conn_t *p_conn, proxy_conn_rec *backend) { /* If there are no KeepAlives, or if the connection has been signalled * to close, close the socket and clean up */ /* if the connection is < HTTP/1.1, or Connection: close, * we close the socket, otherwise we leave it open for KeepAlive support */ if (p_conn->close || (r->proto_num < HTTP_VERSION(1,1))) { if (p_conn->sock) { apr_socket_close(p_conn->sock); p_conn->sock = NULL; backend->connection = NULL; } } 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.) */int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf, char *url, const char *proxyname, apr_port_t proxyport){ int status; char server_portstr[32]; conn_rec *origin = NULL; 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_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri)); proxy_http_conn_t *p_conn = apr_pcalloc(r->connection->pool, sizeof(*p_conn)); /* is it for us? */ if (strncasecmp(url, "https:", 6) == 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; } else if (!(strncasecmp(url, "http:", 5)==0 || (strncasecmp(url, "ftp:", 4)==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 */ } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: HTTP: serving URL %s", url); /* only use stored info for top-level pages. Sub requests don't share * in keepalives */ if (!r->main) { backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_http_module); } /* create space for state information */ if (!backend) { backend = apr_pcalloc(c->pool, sizeof(proxy_conn_rec)); backend->connection = NULL; backend->hostname = NULL; backend->port = 0; if (!r->main) { ap_set_module_config(c->conn_config, &proxy_http_module, backend); } } backend->is_ssl = is_ssl; /* Step One: Determine Who To Connect To */ status = ap_proxy_http_determine_connection(p, r, p_conn, c, conf, uri, &url, proxyname, proxyport, server_portstr, sizeof(server_portstr)); if ( status != OK ) { return status; } /* Step Two: Make the Connection */ status = ap_proxy_http_create_connection(p, r, p_conn, c, &origin, backend, conf, proxyname); if ( status != OK ) { return status; } /* Step Three: Send the Request */ status = ap_proxy_http_request(p, r, p_conn, origin, conf, uri, url, bb, server_portstr); if ( status != OK ) { return status; } /* Step Four: Receive the Response */ status = ap_proxy_http_process_response(p, r, p_conn, origin, backend, conf, bb, server_portstr); if ( status != OK ) { /* clean up even if there is an error */ ap_proxy_http_cleanup(r, p_conn, backend); return status; } /* Step Five: Clean Up */ status = ap_proxy_http_cleanup(r, p_conn, backend); if ( status != OK ) { return status; } return OK;}static void ap_proxy_http_register_hook(apr_pool_t *p){ proxy_hook_scheme_handler(ap_proxy_http_handler, NULL, NULL, APR_HOOK_FIRST); proxy_hook_canon_handler(ap_proxy_http_canon, NULL, NULL, APR_HOOK_FIRST);}module AP_MODULE_DECLARE_DATA proxy_http_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ NULL, /* create per-server config structure */ NULL, /* merge per-server config structures */ NULL, /* command apr_table_t */ ap_proxy_http_register_hook/* register hooks */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -