/* 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.
*/
/* We do not call ap_proxy_canonenc_ex() on the path here, don't *letcontrolcharacterspassstill,andforphp-fpmno'?'either.
*/ if (FCGI_MAY_BE_FPM(dconf)) { while (!apr_iscntrl(*c) && *c != '?')
c++;
} else { while (!apr_iscntrl(*c))
c++;
} if (*c) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10414) "To be forwarded path contains control characters%s (%s)",
FCGI_MAY_BE_FPM(dconf) ? " or '?'" : "", url); return HTTP_FORBIDDEN;
}
path = url; /* this is the raw path */
} else {
core_dir_config *d = ap_get_core_module_config(r->per_dir_config); int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
/* Resolve SCRIPT_NAME/FILENAME from the filesystem? */ if (rconf && rconf->dirwalk_uri_path) { char *saved_uri = r->uri; char *saved_path_info = r->path_info; char *saved_canonical_filename = r->canonical_filename; int saved_filetype = r->finfo.filetype; int i = 0;
r->proxyreq = PROXYREQ_NONE; do {
r->path_info = NULL;
r->finfo.filetype = APR_NOFILE;
r->uri = r->filename = r->canonical_filename = rconf->dirwalk_uri_path; /* Try without than with DocumentRoot prefix */ if (i && ap_core_translate(r) != OK) { continue;
}
ap_directory_walk(r);
} while (r->finfo.filetype != APR_REG && ++i < 2);
r->proxyreq = PROXYREQ_REVERSE;
/* If no actual script was found, fall back to the "proxy:" *SCRIPT_FILENAMEdealtwithbeloworbyFPMdirectly.
*/ if (r->finfo.filetype != APR_REG) {
r->filename = proxy_filename;
r->canonical_filename = saved_canonical_filename;
r->finfo.filetype = saved_filetype;
r->path_info = saved_path_info;
}
/* Restore REQUEST_URI in any case */
r->uri = saved_uri;
}
if (!strncmp(r->filename, "proxy:balancer://", 17)) {
newfname = apr_pstrdup(r->pool, r->filename+17);
}
if (!FCGI_MAY_BE_FPM(dconf)) { if (!strncmp(r->filename, "proxy:fcgi://", 13)) { /* If we strip this under FPM, and any internal redirect occurs *onPATH_INFO,FPMmayusePATH_TRANSLATEDinsteadof *SCRIPT_FILENAME(alamod_fastcgi+Action).
*/
newfname = apr_pstrdup(r->pool, r->filename+13);
}
if (newfname) {
r->filename = ap_strchr(newfname, '/');
}
}
ap_add_common_vars(r);
ap_add_cgi_vars(r);
/* SCRIPT_NAME/FILENAME set, restore original */
r->filename = proxy_filename;
/* XXX are there any FastCGI specific env vars we need to send? */
/* Give admins final option to fine-tune env vars */ if (APR_SUCCESS != (rv = fix_cgivars(r, dconf))) { return rv;
}
/* XXX mod_cgi/mod_cgid use ap_create_environment here, which fills in *theTZvaluespecially.Wecouldusethat,butitwouldmean *parsingthekey/valuepairsbackOUToftheallocatedenvarray, *nottomentionallocatingatotallyuselessarrayinthefirst
* place, which would suck. */
for (i = 0; i < envarr->nelts; ++i) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, APLOGNO(01062) "sending env var '%s' value '%s'",
elts[i].key, elts[i].val);
}
}
/* Send envvars over in as many FastCGI records as it takes, */
next_elem = 0; /* starting with the first one */
avail_len = 16 * 1024; /* our limit per record, which could have been up *toAP_FCGI_MAX_CONTENT_LEN
*/
if (!required_len) { if (next_elem < envarr->nelts) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
APLOGNO(02536) "couldn't encode envvar '%s' in %"
APR_SIZE_T_FMT " bytes",
elts[next_elem].key, avail_len); /* skip this envvar and continue */
++next_elem; continue;
} /* only an unused element at the end of the array */ break;
}
body = apr_palloc(temp_pool, required_len);
rv = ap_fcgi_encode_env(r, r->subprocess_env, body, required_len,
&starting_elem); /* we pre-compute, so we can't run out of space */
ap_assert(rv == APR_SUCCESS); /* compute and encode must be in sync */
ap_assert(starting_elem == next_elem);
/* Try to find the end of the script headers in the response from the back *endfastcgiserver.STATEholdsthecurrentheaderparsingstateforthis *request. * *Returns0ifitcan'tfindtheendoftheheaders,and1ifitfoundthe
* end of the headers. */ staticint handle_headers(request_rec *r, int *state, constchar *readbuf, apr_size_t readlen)
{ constchar *itr = readbuf;
while (readlen--) { if (*itr == '\r') { switch (*state) { case HDR_STATE_GOT_CRLF:
*state = HDR_STATE_GOT_CRLFCR; break;
/* Now get the actual data. Yes it sucks to do this in a second *recvcall,thiswilleventuallychangewhenwemovetoreal
* nonblocking recv calls. */ if (readbuflen != 0) {
rv = get_data(conn, iobuf, &readbuflen); if (rv != APR_SUCCESS) {
*err = "reading response body"; break;
}
}
switch (type) { case AP_FCGI_STDOUT: if (clen != 0) {
b = apr_bucket_transient_create(iobuf,
readbuflen,
c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ob, b);
if (! seen_end_of_headers) { int st = handle_headers(r, &header_state,
iobuf, readbuflen);
if (st == 1) { int status;
seen_end_of_headers = 1;
status = ap_scan_script_header_err_brigade_ex(r, ob,
NULL, APLOG_MODULE_INDEX);
/* FCGI has its own body framing mechanism which we don't *matchagainstanyprovidedContent-Length,soletthe *coredetermineC-LvsT-Ebasedonwhat'sactuallysent.
*/ if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
apr_table_unset(r->headers_out, "Content-Length");
apr_table_unset(r->headers_out, "Transfer-Encoding");
/* suck in all the rest */ if (status != OK) {
apr_bucket *tmp_b;
apr_brigade_cleanup(ob);
tmp_b = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ob, tmp_b);
if (script_error_status == HTTP_OK
&& !APR_BRIGADE_EMPTY(ob) && !ignore_body) { /* Send the part of the body that we read while *readingtheheaders.
*/
*has_responded = 1;
rv = ap_pass_brigade(r->output_filters, ob); if (rv != APR_SUCCESS) {
*err = "passing brigade to output filters"; break;
}
mayflush = 1;
}
apr_brigade_cleanup(ob);
apr_pool_clear(setaside_pool);
} else { /* We're still looking for the end of the *headers,sothispartofthedatawillneed
* to persist. */
apr_bucket_setaside(b, setaside_pool);
}
} else { /* we've already passed along the headers, so now pass *throughthecontent.wecouldsimplycontinueto *setasidethecontentandnotpassuntilweseethe *0content-length(below,whereweappendtheEOS), *butthatcouldbeahugeamountofdata;sowepass *alongsmallerchunks
*/ if (script_error_status == HTTP_OK && !ignore_body) {
*has_responded = 1;
rv = ap_pass_brigade(r->output_filters, ob); if (rv != APR_SUCCESS) {
*err = "passing brigade to output filters"; break;
}
mayflush = 1;
}
apr_brigade_cleanup(ob);
}
/* If we didn't read all the data, go back and get the
* rest of it. */ if (clen > readbuflen) {
clen -= readbuflen; goto recv_again;
}
} else { /* XXX what if we haven't seen end of the headers yet? */
if (script_error_status == HTTP_OK) {
b = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ob, b);
/* XXX Why don't we cleanup here? (logic from AJP) */
} break;
case AP_FCGI_STDERR: /* TODO: Should probably clean up this logging a bit... */ if (clen) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01071) "Got error '%.*s'", (int)readbuflen, iobuf);
}
/* Step 3: Read records from the back end server and handle them. */
rv = dispatch(conn, conf, r, temp_pool, request_id,
&err, &bad_request, &has_responded,
input_brigade); if (rv != APR_SUCCESS) { /* If the client aborted the connection during retrieval or (partially) *sendingtheresponse,don'treturnaHTTP_SERVICE_UNAVAILABLE,since
* this is not a backend problem. */ if (r->connection->aborted) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "The client aborted the connection.");
conn->close = 1; return OK;
}
/* Create space for state information */
status = ap_proxy_acquire_connection(FCGI_SCHEME, &backend, worker,
r->server); if (status != OK) { if (backend) {
backend->close = 1;
ap_proxy_release_connection(FCGI_SCHEME, backend, r->server);
} return status;
}
backend->is_ssl = 0;
/* Step One: Determine Who To Connect To */
uri = apr_palloc(p, sizeof(*uri));
status = ap_proxy_determine_connection(p, r, conf, worker, backend,
uri, &url, proxyname, proxyport,
server_portstr, sizeof(server_portstr)); if (status != OK) { goto cleanup;
}
/* We possibly reuse input data prefetched in previous call(s), e.g. for a *balancerfallbackscenario.
*/
apr_pool_userdata_get((void **)&input_brigade, "proxy-fcgi-input", p); if (input_brigade == NULL) { constchar *old_te = apr_table_get(r->headers_in, "Transfer-Encoding"); constchar *old_cl = NULL; if (old_te) {
apr_table_unset(r->headers_in, "Content-Length");
} else {
old_cl = apr_table_get(r->headers_in, "Content-Length");
}
/* This scheme handler does not reuse connections by default, to *avoidtyingupafastcgithatisn'texpectingtoworkon *parallelrequests.Butiftheuserwentoutoftheirwayto *typethedefaultvalueofdisablereuse=off,we'llallowit.
*/
backend->close = 1; if (worker->s->disablereuse_set && !worker->s->disablereuse) {
backend->close = 0;
}
/* Step Two: Make the Connection */ if (ap_proxy_check_connection(FCGI_SCHEME, backend, r->server, 0,
PROXY_CHECK_CONN_EMPTY)
&& ap_proxy_connect_backend(FCGI_SCHEME, backend, worker,
r->server)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01079) "failed to make connection to backend: %s",
backend->hostname);
status = HTTP_SERVICE_UNAVAILABLE; goto cleanup;
}
/* Step Three: Process the Request */
status = fcgi_do_request(p, r, backend, origin, dconf, uri, url,
server_portstr, input_brigade);
new = apr_array_push(dconf->env_fixups); new->cond = ap_expr_parse_cmd(cmd, arg1, 0, &err, NULL); if (err) { return apr_psprintf(cmd->pool, "Could not parse expression \"%s\": %s",
arg1, err);
}
if (envvar[0] == '!') { /* Unset mode. */ if (arg3) { return apr_psprintf(cmd->pool, "Third argument (\"%s\") is not " "allowed when using ProxyFCGISetEnvIf's unset " "mode (%s)", arg3, envvar);
} elseif (!envvar[1]) { /* i.e. someone tried to give us a name of just "!" */ return"ProxyFCGISetEnvIf: \"!\" is not a valid variable name";
}
new->subst = NULL;
} else { /* Set mode. */ if (!arg3) { /* A missing expr-value should be treated as empty. */
arg3 = "";
}
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.