📄 mod_proxy_http.c
字号:
break; case RB_STREAM_CL: status = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, input_brigade, old_cl_val); break; case RB_SPOOL_CL: status = spool_reqbody_cl(p, r, p_conn, origin, header_brigade, input_brigade, (old_cl_val != NULL) || (old_te_val != NULL) || (bytes_read > 0)); break; default: /* shouldn't be possible */ status = APR_EINVAL; break; } if (status != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, "proxy: pass request body failed to %pI (%s)" " from %s (%s)", p_conn->addr, p_conn->hostname ? p_conn->hostname: "", c->remote_ip, c->remote_host ? c->remote_host: ""); return status; } return APR_SUCCESS;}static void process_proxy_header(request_rec* r, proxy_dir_conf* c, const char* key, const char* value){ static const char* date_hdrs[] = { "Date", "Expires", "Last-Modified", NULL } ; static const struct { const char* name; ap_proxy_header_reverse_map_fn func; } transform_hdrs[] = { { "Location", ap_proxy_location_reverse_map } , { "Content-Location", ap_proxy_location_reverse_map } , { "URI", ap_proxy_location_reverse_map } , { "Destination", ap_proxy_location_reverse_map } , { "Set-Cookie", ap_proxy_cookie_reverse_map } , { NULL, NULL } } ; int i ; for ( i = 0 ; date_hdrs[i] ; ++i ) { if ( !strcasecmp(date_hdrs[i], key) ) { apr_table_add(r->headers_out, key, ap_proxy_date_canon(r->pool, value)) ; return ; } } for ( i = 0 ; transform_hdrs[i].name ; ++i ) { if ( !strcasecmp(transform_hdrs[i].name, key) ) { apr_table_add(r->headers_out, key, (*transform_hdrs[i].func)(r, c, value)) ; return ; } } apr_table_add(r->headers_out, key, value) ; return ;}/* * Note: pread_len is the length of the response that we've mistakenly * read (assuming that we don't consider that an error via * ProxyBadHeader StartBody). This depends on buffer actually being * local storage to the calling code in order for pread_len to make * any sense at all, since we depend on buffer still containing * what was read by ap_getline() upon return. */static void ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c, int *pread_len){ int len; char *value, *end; char field[MAX_STRING_LEN]; int saw_headers = 0; void *sconf = r->server->module_config; proxy_server_conf *psc; proxy_dir_conf *dconf; dconf = ap_get_module_config(r->per_dir_config, &proxy_module); psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); r->headers_out = apr_table_make(r->pool, 20); *pread_len = 0; /* * Read header lines until we get the empty separator line, a read error, * the connection closes (EOF), or we timeout. */ while ((len = ap_getline(buffer, size, rr, 1)) > 0) { if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */ /* We may encounter invalid headers, usually from buggy * MS IIS servers, so we need to determine just how to handle * them. We can either ignore them, assume that they mark the * start-of-body (eg: a missing CRLF) or (the default) mark * the headers as totally bogus and return a 500. The sole * exception is an extra "HTTP/1.0 200, OK" line sprinkled * in between the usual MIME headers, which is a favorite * IIS bug. */ /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */ if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) { if (psc->badopt == bad_error) { /* Nope, it wasn't even an extra HTTP header. Give up. */ r->headers_out = NULL; return ; } else if (psc->badopt == bad_body) { /* if we've already started loading headers_out, then * return what we've accumulated so far, in the hopes * that they are useful; also note that we likely pre-read * the first line of the response. */ if (saw_headers) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: Starting body due to bogus non-header in headers " "returned by %s (%s)", r->uri, r->method); *pread_len = len; return ; } else { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: No HTTP headers " "returned by %s (%s)", r->uri, r->method); return ; } } } /* this is the psc->badopt == bad_ignore case */ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: Ignoring bogus HTTP header " "returned by %s (%s)", r->uri, r->method); continue; } *value = '\0'; ++value; /* XXX: RFC2068 defines only SP and HT as whitespace, this test is * wrong... and so are many others probably. */ while (apr_isspace(*value)) ++value; /* Skip to start of value */ /* should strip trailing whitespace as well */ for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) *end = '\0'; /* make sure we add so as not to destroy duplicated headers * Modify headers requiring canonicalisation and/or affected * by ProxyPassReverse and family with process_proxy_header */ process_proxy_header(r, dconf, buffer, value) ; saw_headers = 1; /* the header was too long; at the least we should skip extra data */ if (len >= size - 1) { while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1)) >= MAX_STRING_LEN - 1) { /* soak up the extra data */ } if (len == 0) /* time to exit the larger loop as well */ break; } }}static int addit_dammit(void *v, const char *key, const char *val){ apr_table_addn(v, key, val); return 1;}staticapr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, proxy_conn_rec *backend, conn_rec *origin, proxy_server_conf *conf, char *server_portstr) { conn_rec *c = r->connection; char buffer[HUGE_STRING_LEN]; const char *buf; char keepchar; request_rec *rp; apr_bucket *e; apr_bucket_brigade *bb; int len, backasswards; int interim_response; /* non-zero whilst interim 1xx responses * are being read. */ int pread_len = 0; apr_table_t *save_table; int backend_broke = 0; bb = apr_brigade_create(p, c->bucket_alloc); /* Get response from the remote server, and pass it up the * filter chain */ rp = ap_proxy_make_fake_req(origin, r); /* In case anyone needs to know, this is a fake request that is really a * response. */ rp->proxyreq = PROXYREQ_RESPONSE; do { apr_brigade_cleanup(bb); len = ap_getline(buffer, sizeof(buffer), rp, 0); if (len == 0) { /* handle one potential stray CRLF */ len = ap_getline(buffer, sizeof(buffer), rp, 0); } if (len <= 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error reading status line from remote " "server %s", backend->hostname); return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server"); } /* XXX: Is this a real headers length send from remote? */ backend->worker->s->read += len; /* Is it an HTTP/1 response? * This is buggy if we ever see an HTTP/1.10 */ if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) { int major, minor; if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) { major = 1; minor = 1; } /* If not an HTTP/1 message or * if the status line was > 8192 bytes */ else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1)) { return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p, "Corrupt status line returned by remote " "server: ", buffer, NULL)); } backasswards = 0; keepchar = buffer[12]; buffer[12] = '\0'; r->status = atoi(&buffer[9]); if (keepchar != '\0') { buffer[12] = keepchar; } else { /* 2616 requires the space in Status-Line; the origin * server may have sent one but ap_rgetline_core will * have stripped it. */ buffer[12] = ' '; buffer[13] = '\0'; } r->status_line = apr_pstrdup(p, &buffer[9]); /* read the headers. */ /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/ /* Also, take care with headers with multiple occurences. */ /* First, tuck away all already existing cookies */ save_table = apr_table_make(r->pool, 2); apr_table_do(addit_dammit, save_table, r->headers_out, "Set-Cookie", NULL); /* shove the headers direct into r->headers_out */ ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin, &pread_len); if (r->headers_out == NULL) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: bad HTTP/%d.%d header " "returned by %s (%s)", major, minor, r->uri, r->method); backend->close += 1; /* * 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; } /* Now, add in the just read cookies */ apr_table_do(addit_dammit, save_table, r->headers_out, "Set-Cookie", NULL); /* and now load 'em all in */ if (!apr_is_empty_table(save_table)) { apr_table_unset(r->headers_out, "Set-Cookie"); r->headers_out = apr_table_overlay(r->pool, r->headers_out, save_table); } /* can't have both Content-Length and Transfer-Encoding */ if (apr_table_get(r->headers_out, "Transfer-Encoding") && apr_table_get(r->headers_out, "Content-Length")) { /* * 2616 section 4.4, point 3: "if both Transfer-Encoding * and Content-Length are received, the latter MUST be * ignored"; * * To help mitigate HTTP Splitting, unset Content-Length * and shut down the backend server connection * XXX: We aught to treat such a response as uncachable */ apr_table_unset(r->headers_out, "Content-Length"); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: server %s returned Transfer-Encoding" " and Content-Length", backend->hostname); backend->close += 1; } /* strip connection listed hop-by-hop headers from response */ backend->close += ap_proxy_liststr(apr_table_get(r->headers_out, "Connection"), "close"); ap_proxy_clear_connection(p, r->headers_out);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -