/* Licensed to the Apache Software Foundation (ASF) under one or more *contributorlicenseagreements.SeetheNOTICEfiledistributedwith *thisworkforadditionalinformationregardingcopyrightownership. *TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 *(the"License");youmaynotusethisfileexceptincompliancewith *theLicense.YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense.
*/
staticint stream_reqbody(proxy_http_req_t *req)
{
request_rec *r = req->r; int seen_eos = 0, rv = OK;
apr_size_t hdr_len; char chunk_hdr[20]; /* must be here due to transient bucket. */
conn_rec *origin = req->origin;
proxy_conn_rec *p_conn = req->backend;
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
apr_bucket_brigade *header_brigade = req->header_brigade;
apr_bucket_brigade *input_brigade = req->input_brigade;
rb_methods rb_method = req->rb_method;
apr_off_t bytes, bytes_streamed = 0;
apr_bucket *e;
do { if (APR_BRIGADE_EMPTY(input_brigade)
&& APR_BRIGADE_EMPTY(header_brigade)) {
rv = ap_proxy_read_input(r, p_conn, input_brigade,
HUGE_STRING_LEN); if (rv != OK) { return rv;
}
}
if (!APR_BRIGADE_EMPTY(input_brigade)) { /* If this brigade contains EOS, remove it and be done. */ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
seen_eos = 1;
/* We can't pass this EOS to the output_filters. */
e = APR_BRIGADE_LAST(input_brigade);
apr_bucket_delete(e);
}
if (seen_eos && apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) {
e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
APR_BRIGADE_INSERT_TAIL(input_brigade, e);
}
}
/* If we never sent the header brigade, go ahead and take care of *thatnowbyprependingit(onceonlysinceheader_brigadewillbe *emptyafterward).
*/
APR_BRIGADE_PREPEND(input_brigade, header_brigade);
/* Flush here on EOS because we won't ap_proxy_read_input() again. */
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin,
input_brigade, seen_eos); if (rv != OK) { return rv;
}
} while (!seen_eos);
/* *HandleConnection:headerifwedoHTTP/1.1request: *IfweplantoclosethebackendconnectionsentConnection:close *otherwisesentConnection:Keep-Alive.
*/ if (!req->force10) { if (req->upgrade) {
buf = apr_pstrdup(req->p, "Connection: Upgrade" CRLF);
ap_xlate_proto_to_ascii(buf, strlen(buf));
e = apr_bucket_pool_create(buf, strlen(buf), req->p, bucket_alloc);
APR_BRIGADE_INSERT_TAIL(req->header_brigade, e);
/* Tell the backend that it can upgrade the connection. */
buf = apr_pstrcat(req->p, "Upgrade: ", req->upgrade, CRLF, NULL);
} elseif (ap_proxy_connection_reusable(req->backend)) {
buf = apr_pstrdup(req->p, "Connection: Keep-Alive" CRLF);
} else {
buf = apr_pstrdup(req->p, "Connection: close" CRLF);
}
ap_xlate_proto_to_ascii(buf, strlen(buf));
e = apr_bucket_pool_create(buf, strlen(buf), req->p, bucket_alloc);
APR_BRIGADE_INSERT_TAIL(req->header_brigade, e);
}
/* add empty line at the end of the headers */
e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
APR_BRIGADE_INSERT_TAIL(req->header_brigade, e);
}
/* Use chunked request body encoding or send a content-length body? * *PreferC-Lwhen: * *Wehavenorequestbody(handledbyRB_STREAM_CL) * *Wehavearequestbodylength<=MAX_MEM_SPOOL * *Theadministratorhassetenvforce-proxy-request-1.0 * *TheclientsentaC-Lbody,andtheadministratorhas *notsetenvproxy-sendchunkedorhassetsetenvproxy-sendcl * *TheclientsentaT-Ebody,andtheadministratorhas *setenvproxy-sendcl,andnotsetenvproxy-sendchunked * *Ifbothproxy-sendclandproxy-sendchunkedareset,the *behavioristhesameasifneitherwereset,largebodies *thatcan'tbereadwillbeforwardedintheiroriginal *formofC-L,orT-E. * *Toensuremaximumcompatibility,setenvproxy-sendcl *Toreduceserverresourceuse,setenvproxy-sendchunked * *Thenaddressspecificserverswithconditionalsetenv *optionstorestorethedefaultbehaviorwheredesirable. * *Wehavetocomputecontentlengthbyreadingtheentirerequest *body;ifrequestbodyisnotsmall,we'llspooltheremaining *inputtoatemporaryfile.Chunkedisalwayspreferable. * *Wecanonlytrusttheclient-providedC-LiftheT-Eheader *isabsent,andthefiltersareunchanged(thebodywon't *beresizedbyanothercontentfilter).
*/ if (!APR_BRIGADE_EMPTY(input_brigade)
&& APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { /* The whole thing fit, so our decision is trivial, use *thefilteredbytesreadfromtheclientfortherequest *bodyContent-Length. * *Ifweexpectednobody,andreadnobody,donotset *theContent-Length.
*/ if (req->old_cl_val || req->old_te_val || bytes_read) {
req->old_cl_val = apr_off_t_toa(r->pool, bytes_read);
req->cl_val = bytes_read;
}
req->rb_method = RB_STREAM_CL;
} elseif (req->old_te_val) { if (req->force10
|| (apr_table_get(r->subprocess_env, "proxy-sendcl")
&& !apr_table_get(r->subprocess_env, "proxy-sendchunks")
&& !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) {
req->rb_method = RB_SPOOL_CL;
} else {
req->rb_method = RB_STREAM_CHUNKED;
}
} elseif (req->old_cl_val) { if (r->input_filters == r->proto_input_filters) { if (!ap_parse_strict_length(&req->cl_val, req->old_cl_val)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01085) "could not parse request Content-Length (%s)",
req->old_cl_val); return HTTP_BAD_REQUEST;
}
req->rb_method = RB_STREAM_CL;
} elseif (!req->force10
&& (apr_table_get(r->subprocess_env, "proxy-sendchunks")
|| apr_table_get(r->subprocess_env, "proxy-sendchunked"))
&& !apr_table_get(r->subprocess_env, "proxy-sendcl")) {
req->rb_method = RB_STREAM_CHUNKED;
} else {
req->rb_method = RB_SPOOL_CL;
}
} else { /* This is an appropriate default; very efficient for no-body *requests,andhasthebehaviorthatitwillnotaddanyC-L *whentheold_cl_valisNULL.
*/
req->rb_method = RB_SPOOL_CL;
}
switch (req->rb_method) { case RB_STREAM_CHUNKED:
add_te_chunked(req->p, bucket_alloc, header_brigade); break;
case RB_STREAM_CL: if (req->old_cl_val) {
add_cl(req->p, bucket_alloc, header_brigade, req->old_cl_val);
} break;
default: /* => RB_SPOOL_CL */ /* If we have to spool the body, do it now, before connecting or *reusingthebackendconnection.
*/
rv = ap_proxy_spool_input(r, p_conn, input_brigade,
&bytes, MAX_MEM_SPOOL); if (rv != OK) { return rv;
} if (bytes || req->old_te_val || req->old_cl_val) {
add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes));
}
}
/* Yes I hate gotos. This is the subrequest shortcut */
skip_body:
terminate_headers(req);
return OK;
}
staticint ap_proxy_http_request(proxy_http_req_t *req)
{ int rv;
request_rec *r = req->r;
/* send the request header/body, if any. */ switch (req->rb_method) { case RB_SPOOL_CL: case RB_STREAM_CL: case RB_STREAM_CHUNKED: if (req->do_100_continue) {
rv = ap_proxy_pass_brigade(req->bucket_alloc, r, req->backend,
req->origin, req->header_brigade, 1);
} else {
rv = stream_reqbody(req);
} break;
default: /* shouldn't be possible */
rv = HTTP_INTERNAL_SERVER_ERROR; break;
}
if (rv != OK) {
conn_rec *c = r->connection; /* apr_status_t value has been logged in lower level method */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) "pass request body failed to %pI (%s) from %s (%s)",
req->backend->addr,
req->backend->hostname ? req->backend->hostname: "",
c->client_ip, c->remote_host ? c->remote_host: ""); return rv;
}
if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */
/* We may encounter invalid headers, usually from buggy *MSIISservers,soweneedtodeterminejusthowtohandle *them.Wecaneitherignorethem,assumethattheymarkthe *start-of-body(eg:amissingCRLF)or(thedefault)mark *theheadersastotallybogusandreturna500.Thesole *exceptionisanextra"HTTP/1.0200,OK"linesprinkled *inbetweentheusualMIMEheaders,whichisafavorite *IISbug.
*/ /* 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 APR_EINVAL;
} elseif (psc->badopt == bad_body) { /* if we've already started loading headers_out, then *returnwhatwe'veaccumulatedsofar,inthehopes *thattheyareuseful;alsonotethatwelikelypre-read *thefirstlineoftheresponse.
*/ if (saw_headers) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01098) "Starting body due to bogus non-header " "in headers returned by %s (%s)",
r->uri, r->method);
*pread_len = len; return APR_SUCCESS;
} else {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01099) "No HTTP headers returned by %s (%s)",
r->uri, r->method); return APR_SUCCESS;
}
}
} /* this is the psc->badopt == bad_ignore case */
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01100) "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...andsoaremanyothersprobably.
*/ 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 *Modifyheadersrequiringcanonicalisationand/oraffected *byProxyPassReverseandfamilywithprocess_proxy_header
*/
process_proxy_header(r, dconf, buffer, value);
saw_headers = 1;
} return APR_SUCCESS;
}
/* Only use dynamically sized buffer if user specifies ResponseFieldSize */ if(backend->worker->s->response_field_size_set) {
response_field_size = backend->worker->s->response_field_size;
/* Setup for 100-Continue timeout if appropriate */ if (do_100_continue && worker->s->ping_timeout_set) {
apr_socket_timeout_get(backend->sock, &old_timeout); if (worker->s->ping_timeout != old_timeout) {
apr_status_t rc;
rc = apr_socket_timeout_set(backend->sock, worker->s->ping_timeout); if (rc != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(01101) "could not set 100-Continue timeout");
}
}
}
/* Get response from the remote server, and pass it up the *filterchain
*/
backend->r = make_fake_req(origin, r); /* In case anyone needs to know, this is a fake request that is really a *response.
*/
backend->r->proxyreq = PROXYREQ_RESPONSE;
apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu",
origin->local_addr->port)); do {
apr_status_t rc; constchar *upgrade = NULL; int major = 0, minor = 0; int toclose = 0;
apr_brigade_cleanup(bb);
rc = ap_proxygetline(backend->tmp_bb, buffer, response_field_size,
backend->r, 0, &len); if (len == 0) { /* handle one potential stray CRLF */
rc = ap_proxygetline(backend->tmp_bb, buffer, response_field_size,
backend->r, 0, &len);
} if (len <= 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(01102) "error reading status line from remote " "server %s:%d", backend->hostname, backend->port); if (APR_STATUS_IS_TIMEUP(rc)) {
apr_table_setn(r->notes, "proxy_timedout", "1");
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01103) "read timeout"); if (do_100_continue) { return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, "Timeout on 100-Continue");
}
} /* *Ifweareareverseproxyrequestshutdowntheconnection *WITHOUTANYresponsetotriggeraretrybytheclient *ifallowed(asforidempotentrequests). *BUTcurrentlyweshouldnotdothisiftherequestisthe *firstrequestonakeepaliveconnectionasbrowserslike *seamonkeyonlydisplayanemptypageinthiscaseanddo *notdoaretry.Weshouldalsonotdothisona *connectionwhichtimesout;insteadhandleas *wenormallywouldhandletimeouts
*/ if (r->proxyreq == PROXYREQ_REVERSE && c->keepalives &&
!APR_STATUS_IS_TIMEUP(rc)) {
apr_bucket *eos;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01104) "Closing connection to client because" " reading from backend server %s:%d failed." " Number of keepalives %i", backend->hostname,
backend->port, c->keepalives);
ap_proxy_backend_broke(r, bb); /* *AddanEOCbuckettosignaltheap_http_header_filter *thatitshouldgetoutofourway,BUTensurethatthe *EOCbucketisinsertedBEFOREanEOSbucketinbbas *someresourcefilterslikemod_deflatepasseverything *uptotheEOSdownthechainimmediatelyandsentthe *remainderofthebrigadelater(orevennever).Butin *thiscasetheap_http_header_filterdoesnotgetoutof *ourwaysoonenough.
*/
e = ap_bucket_eoc_create(c->bucket_alloc);
eos = APR_BRIGADE_LAST(bb); while ((APR_BRIGADE_SENTINEL(bb) != eos)
&& !APR_BUCKET_IS_EOS(eos)) {
eos = APR_BUCKET_PREV(eos);
} if (eos == APR_BRIGADE_SENTINEL(bb)) {
APR_BRIGADE_INSERT_TAIL(bb, e);
} else {
APR_BUCKET_INSERT_BEFORE(eos, e);
}
ap_pass_brigade(r->output_filters, bb); /* Mark the backend connection for closing */
backend->close = 1; if (origin->keepalives) { /* We already had a request on this backend connection and *mightjusthaverunintoakeepaliverace.Hencewe *thinkpositiveandassumethatthebackendisfineand *wedonotneedtosignalanerroronbackendside.
*/ return OK;
} /* *Thishappenedonourfirstrequestonthisconnectiontothe *backend.Thisindicatessomethingfishywiththebackend. *ReturnHTTP_INTERNAL_SERVER_ERRORtosignalanunrecoverable *servererror.Wedonotworryaboutr->statuscodeanda *possibleerrorresponsehereastheap_http_outerror_filter *willfixallofthisforus.
*/ return HTTP_INTERNAL_SERVER_ERROR;
} if (!c->keepalives) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01105) "NOT Closing connection to client" " although reading from backend server %s:%d" " failed.",
backend->hostname, backend->port);
} 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? *ThisisbuggyifweeverseeanHTTP/1.10
*/ if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
major = buffer[5] - '0';
minor = buffer[7] - '0';
/* If not an HTTP/1 message or *ifthestatuslinewas>8192bytes
*/ if ((major != 1) || (len >= response_field_size - 1)) { return ap_proxyerror(r, HTTP_BAD_GATEWAY,
apr_pstrcat(p, "Corrupt status line returned " "by remote server: ", buffer, NULL));
}
backasswards = 0;
if (keepchar != '\0') {
buffer[12] = keepchar;
} else { /* 2616 requires the space in Status-Line; the origin *servermayhavesentonebutap_rgetline_corewill
* have stripped it. */
buffer[12] = ' ';
buffer[13] = '\0';
}
proxy_status_line = apr_pstrdup(p, &buffer[9]);
/* The status out of the front is the same as the status coming in *fromtheback,untilfurthernotice.
*/
r->status = proxy_status;
r->status_line = proxy_status_line;
ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "Status from backend: %d", proxy_status);
/* read the headers. */ /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/ /* Also, take care with headers with multiple occurrences. */
/* 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 */
rc = ap_proxy_read_headers(r, backend->r, buffer, response_field_size,
origin, &pread_len);
/* 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);
}
/* *SaveapossibleTransfer-Encodingheaderasweneeditlaterfor *ap_http_filtertoknowwheretoend.
*/
te = apr_table_get(r->headers_out, "Transfer-Encoding");
/* can't have both Content-Length and Transfer-Encoding */ if (te && apr_table_get(r->headers_out, "Content-Length")) { /* *2616section4.4,point3:"ifbothTransfer-Encoding *andContent-Lengtharereceived,thelatterMUSTbe *ignored"; * *TohelpmitigateHTTPSplitting,unsetContent-Length *andshutdownthebackendserverconnection *XXX:Weaughttotreatsucharesponseasuncachable
*/
apr_table_unset(r->headers_out, "Content-Length");
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01107) "server %s:%d returned Transfer-Encoding" " and Content-Length",
backend->hostname, backend->port);
backend->close = 1;
}
if (do_send_body) {
status = send_continue_body(req); if (status != OK) { return status;
}
} else { /* If we don't read the client connection any further, since *therearependingdataitshouldbe"Connection:close"dto *preventreuse.Wedon'texactlyc->keepalive=AP_CONN_CLOSE *herethough,becauseerror_overrideorapotentialretryon *anotherbackendcouldfinallyreadthatdataandfinalize *therequestprocessing,makingkeep-alivepossible.Sowhat *wedoisleavingr->expecting_100alone,ap_set_keepalive() *willdotherightthingaccordingtothefinalresponseand *anylaterupdateofr->expecting_100.
*/
}
/* If we didn't send the full body yet, do it now */ if (do_100_continue) {
r->expecting_100 = 0;
status = send_continue_body(req); if (status != OK) { return status;
}
}
/* send body - but only if a body is expected */ if ((!r->header_only) && /* not HEAD request */
(proxy_status != HTTP_NO_CONTENT) && /* not 204 */
(proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */
apr_read_type_e mode; int finish;
/* We need to copy the output headers and treat them as input *headersaswell.BUT,weneedtodothisbeforeweremove *TE,sothattheyarepreservedaccordinglyfor *ap_http_filtertoknowwheretoend.
*/
backend->r->headers_in = apr_table_clone(backend->r->pool, r->headers_out); /* *RestoreTransfer-Encodingheaderfromresponseifwesaved *onebeforeandthereisnoneleft.Weneeditforthe *ap_http_filter.Seeabove.
*/ if (te && !apr_table_get(backend->r->headers_in, "Transfer-Encoding")) {
apr_table_add(backend->r->headers_in, "Transfer-Encoding", te);
}
ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "start body send");
/* read the body, pass it to the output filters */
/* Handle the case where the error document is itself reverse *proxiedandwassuccessful.Wemustmaintainanyprevious *errorstatussothatanunderlyingerror(egHTTP_NOT_FOUND) *doesn'tbecomeanHTTP_OK.
*/ if (ap_proxy_should_override(dconf, original_status)) {
r->status = original_status;
r->status_line = original_status_line;
}
/* Switch the allocator lifetime of the buckets */
ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);
/* found the last brigade? */ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pass_bb))) {
/* signal that we must leave */
finish = TRUE;
/* the brigade may contain transient buckets that contain *datathatlivesonlyaslongasthebackendconnection. *Forceasetasidesothesetransientbucketsbecomeheap *bucketsthatliveaslongastherequest.
*/ for (e = APR_BRIGADE_FIRST(pass_bb); e
!= APR_BRIGADE_SENTINEL(pass_bb); e
= APR_BUCKET_NEXT(e)) {
apr_bucket_setaside(e, r->pool);
}
/* finally it is safe to clean up the brigade from the *connectionpool,aswehaveforcedasetasideonall *buckets.
*/
apr_brigade_cleanup(bb);
/* make sure we release the backend connection as soon *asweknowwearedone,sothatthebackendisn't *leftwaitingforaslowclienttoeventually *acknowledgethedata.
*/
ap_proxy_release_connection(backend->worker->s->scheme,
backend, r->server); /* Ensure that the backend is not reused */
req->backend = NULL;
}
/* try send what we read */ if (ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS
|| c->aborted) { /* Ack! Phbtt! Die! User aborted! */ /* Only close backend if we haven't got all from the *backend.Furthermoreifreq->backendisNULLitisno *longersafetofiddlearoundwithbackendasitmight *bealreadyinusebyanotherthread.
*/ if (req->backend) { /* this causes socket close below */
req->backend->close = 1;
}
finish = TRUE;
}
/* make sure we always clean up after ourselves */
apr_brigade_cleanup(pass_bb);
apr_brigade_cleanup(bb);
/* make sure we release the backend connection as soon *asweknowwearedone,sothatthebackendisn't *leftwaitingforaslowclienttoeventually *acknowledgethedata.
*/
ap_proxy_release_connection(backend->worker->s->scheme,
backend, r->server); /* Ensure that the backend is not reused */
req->backend = NULL;
/* Pass EOS bucket down the filter chain. */
e = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, e);
ap_pass_brigade(r->output_filters, bb);
apr_brigade_cleanup(bb);
}
} while (interim_response && (interim_response < AP_MAX_INTERIM_RESPONSES));
/* We have to cleanup bb brigade, because buckets inserted to it could be
* created from scpool and this pool can be freed before this brigade. */
apr_brigade_cleanup(bb);
/* See define of AP_MAX_INTERIM_RESPONSES for why */ if (interim_response >= AP_MAX_INTERIM_RESPONSES) { return ap_proxyerror(r, HTTP_BAD_GATEWAY,
apr_psprintf(p, "Too many (%d) interim responses from origin server",
interim_response));
}
/* If our connection with the client is to be aborted, return DONE. */ if (c->aborted || backend_broke) { return DONE;
}
/* We possibly reuse input data prefetched in previous call(s), e.g. for a *balancerfallbackscenario,andinthiscasethe100continuesettings *shouldbeconsistentbetweenbalancermembers.Ifnot,weneedtoignore *Proxy100Continueon=>offoncewetriedtoprefetchalready,otherwise *theHTTP_INfilterwon'tsend100Continueforusanymore,andwemight *deadlockwiththeclientwaitingforeachother.Notethatoff=>onis *notanissuebecauseinthiscaser->expecting_100isfalse(the100 *Continueisoutalready),butwemakesurethatprefetchwillbe *nonblockingtoavoidpassingmoretimethere.
*/
apr_pool_userdata_get((void **)&input_brigade, "proxy-req-input", p);
/* Should we handle end-to-end or ping 100-continue? */ if (!req->force10
&& ((r->expecting_100 && (dconf->forward_100_continue || input_brigade))
|| PROXY_SHOULD_PING_100_CONTINUE(worker, r))) { /* Tell ap_proxy_create_hdrbrgd() to preserve/add the Expect header */
apr_table_setn(r->notes, "proxy-100-continue", "1");
req->do_100_continue = 1;
}
/* Should we block while prefetching the body or try nonblocking and flush *datatothebackendASAP?
*/ if (input_brigade
|| req->do_100_continue
|| apr_table_get(r->subprocess_env, "proxy-prefetch-nonblocking")) {
req->prefetch_nonblocking = 1;
}
/* Step One: Determine Who To Connect To */
uri = apr_palloc(p, sizeof(*uri)); if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend,
uri, &locurl, proxyname,
proxyport, req->server_portstr, sizeof(req->server_portstr)))) goto cleanup;
/* The header is always (re-)built since it depends on worker settings, *butthebodycanbefetchedonlyonce(evenpartially),soit'ssaved *inbetweenproxy_http_handler()callsshouldwecomebackhere.
*/
req->header_brigade = apr_brigade_create(p, req->bucket_alloc); if (input_brigade == NULL) {
input_brigade = apr_brigade_create(p, req->bucket_alloc);
apr_pool_userdata_setn(input_brigade, "proxy-req-input", NULL, p);
}
req->input_brigade = input_brigade;
/* Prefetch (nonlocking) the request body so to increase the chance to get *thewhole(orenough)bodyanddetermineContent-Lengthvschunkedor *spooled.Bydoingthisbeforeconnectingorreusingthebackend,wewant *tominimizethedelaybetweenthisconnectionisconsideredaliveand *thefirstbytessent(shouldtheclient'slinkbesloworsomeinput *filterretainthedata).Thisisabestefforttopreventthebackend *fromclosing(fromunderus)whatitthinksisanidleconnection,hence *toreducetotheminimumtheunavoidablelocalis_socket_connected()vs *remotekeepaliveracecondition.
*/ if ((status = ap_proxy_http_prefetch(req, uri, locurl)) != OK) goto cleanup;
/* We need to reset backend->close now, since ap_proxy_http_prefetch() set *ittodisablethereuseoftheconnection*after*thisrequest(nokeep- *alive),nottocloseanyreusableconnectionbeforethisrequest.However *assurewhatisexpectedlaterbyusingalocalflaganddotherightthing *whenap_proxy_connect_backend()belowprovidestheconnectiontoclose.
*/
toclose = backend->close;
backend->close = 0;
while (retry < 2) { if (retry) { char *newurl = url;
/* Step One (again): (Re)Determine Who To Connect To */ if ((status = ap_proxy_determine_connection(p, r, conf, worker,
backend, uri, &newurl, proxyname, proxyport,
req->server_portstr, sizeof(req->server_portstr)))) break;
/* The code assumes locurl is not changed during the loop, or *ap_proxy_http_prefetch()wouldhavetobecalledeverytime, *andheader_brigadebechangedaccordingly...
*/
AP_DEBUG_ASSERT(strcmp(newurl, locurl) == 0);
}
/* Step Two: Make the Connection */ if (ap_proxy_check_connection(scheme, backend, r->server, 1,
PROXY_CHECK_CONN_EMPTY)
&& ap_proxy_connect_backend(scheme, backend, worker,
r->server)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114) "HTTP: failed to make connection to backend: %s",
backend->hostname);
status = HTTP_SERVICE_UNAVAILABLE; break;
}
/* proxy_http_post_config() will be called twice during startup. So, don't
* set up the static data the 1st time through. */ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) { return OK;
}
ap_proxy_clear_connection_fn =
APR_RETRIEVE_OPTIONAL_FN(ap_proxy_clear_connection); if (!ap_proxy_clear_connection_fn) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02477) "mod_proxy must be loaded for mod_proxy_http"); return !OK;
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.81Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.