/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/
/* Read and discard all output from the brigade. Note that with the * CGI bucket, the brigade will become empty once the script's stdout * is closed (or on error/timeout), but the stderr output may not have
* been entirely captured at this point. */ staticvoid discard_script_output(apr_bucket_brigade *bb)
{
apr_bucket *e; constchar *buf;
apr_size_t len;
for (e = APR_BRIGADE_FIRST(bb);
e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e);
e = APR_BRIGADE_FIRST(bb))
{ if (apr_bucket_read(e, &buf, &len, APR_BLOCK_READ)) { break;
}
apr_bucket_delete(e);
}
}
/* Soak up stderr from a script and redirect it to the error log.
*/ static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err)
{ char argsbuffer[HUGE_STRING_LEN]; char *newline;
apr_status_t rv;
cgi_server_conf *conf = ap_get_module_config(r->server->module_config, &cgi_module);
while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN,
script_err)) == APR_SUCCESS) {
if (!ctx->argc) {
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
0, r, APLOGNO(03195) "missing argument for exec element in %s", r->filename);
}
if (!(ctx->flags & SSI_FLAG_PRINTING)) { return APR_SUCCESS;
}
if (!ctx->argc) {
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); return APR_SUCCESS;
}
if (ctx->flags & SSI_FLAG_NO_EXEC) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01228) "exec used but not allowed " "in %s", r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); return APR_SUCCESS;
}
while (1) {
cgi_pfn_gtv(ctx, &tag, &tag_val, SSI_VALUE_DECODED); if (!tag || !tag_val) { break;
}
if (cgi_pfn_reg_with_ssi && cgi_pfn_gtv && cgi_pfn_ps) { /* Required by mod_include filter. This is how mod_cgi registers * with mod_include to provide processing of the exec directive.
*/
cgi_pfn_reg_with_ssi("exec", cgi_handle_exec);
}
}
#ifdef WANT_CGI_BUCKET /* A CGI bucket type is needed to catch any output to stderr from the
* script; see PR 22030. */ staticconst apr_bucket_type_t bucket_type_cgi;
/* Change the current bucket to refer to what we read */
a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free);
h = a->data;
h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
*str = buf;
APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list));
} else {
apr_bucket_free(buf);
a = apr_bucket_immortal_make(a, "", 0);
*str = a->data;
} return rv;
}
/* Read method of CGI bucket: polls on stderr and stdout of the child,
* sending any stderr output immediately away to the error log. */ static apr_status_t cgi_bucket_read(apr_bucket *b, constchar **str,
apr_size_t *len, apr_read_type_e block)
{ struct cgi_bucket_data *data = b->data;
apr_interval_time_t timeout = 0;
apr_status_t rv; int gotdata = 0;
/* Handle the CGI response output, having set up the brigade with the
* CGI or PIPE bucket as appropriate. */ staticint cgi_handle_response(request_rec *r, int nph, apr_bucket_brigade *bb,
apr_interval_time_t timeout, cgi_server_conf *conf, char *logdata, apr_file_t *script_err)
{
apr_status_t rv;
/* Handle script return... */ if (!nph) { constchar *location; char sbuf[MAX_STRING_LEN]; int ret;
ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf,
APLOG_MODULE_INDEX);
/* xCGI has its own body framing mechanism which we don't * match against any provided Content-Length, so let the * core determine C-L vs T-E based on what's actually sent.
*/ 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");
if (ret != OK) { /* In the case of a timeout reading script output, clear * the brigade to avoid a second attempt to read the
* output. */ if (ret == HTTP_GATEWAY_TIME_OUT) {
apr_brigade_cleanup(bb);
}
ret = log_script(r, conf, ret, logdata, sbuf, bb, script_err);
/* * ret could be HTTP_NOT_MODIFIED in the case that the CGI script * does not set an explicit status and ap_meets_conditions, which * is called by ap_scan_script_header_err_brigade, detects that * the conditions of the requests are met and the response is * not modified. * In this case set r->status and return OK in order to prevent * running through the error processing stack as this would * break with mod_cache, if the conditions had been set by * mod_cache itself to validate a stale entity. * BTW: We circumvent the error processing stack anyway if the * CGI script set an explicit status code (whatever it is) and * the only possible values for ret here are: * * HTTP_NOT_MODIFIED (set by ap_meets_conditions) * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the * processing of the response of the CGI script, e.g broken headers * or a crashed CGI process).
*/ if (ret == HTTP_NOT_MODIFIED) {
r->status = ret; return OK;
}
if (location && r->status == 200) { /* For a redirect whether internal or not, discard any * remaining stdout from the script, and log any remaining
* stderr output, as normal. */
discard_script_output(bb);
apr_brigade_destroy(bb);
if (script_err) {
apr_file_pipe_timeout_set(script_err, timeout);
log_script_err(r, script_err);
}
}
if (location && location[0] == '/' && r->status == 200) { /* This redirect needs to be a GET no matter what the original * method was.
*/
r->method = "GET";
r->method_number = M_GET;
/* We already read the message body (if any), so don't allow * the redirected request to think it has one. We can ignore * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
*/
apr_table_unset(r->headers_in, "Content-Length");
ap_internal_redirect_handler(location, r); return OK;
} elseif (location && r->status == 200) { /* XXX: Note that if a script wants to produce its own Redirect * body, it now has to explicitly *say* "Status: 302"
*/
discard_script_output(bb);
apr_brigade_destroy(bb); return HTTP_MOVED_TEMPORARILY;
}
/* get rid of all filters up through protocol... since we * haven't parsed off the headers, there is no way they can * work
*/
cur = r->proto_output_filters; while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) {
cur = cur->next;
}
r->output_filters = r->proto_output_filters = cur;
rv = ap_pass_brigade(r->output_filters, bb);
}
/* don't soak up script output if errors occurred writing it * out... otherwise, we prolong the life of the script when the * connection drops or we stopped sending output for some other
* reason */ if (script_err && rv == APR_SUCCESS && !r->connection->aborted) {
apr_file_pipe_timeout_set(script_err, timeout);
log_script_err(r, script_err);
}
if (script_err) apr_file_close(script_err);
return OK; /* NOT r->status, even if it has changed. */
}
/* Read the request body and write it to fd 'script_out', using 'bb' * as temporary bucket brigade. If 'logbuf' is non-NULL, the first
* logbufbytes of stdout are stored in logbuf. */ static apr_status_t cgi_handle_request(request_rec *r, apr_file_t *script_out,
apr_bucket_brigade *bb, char *logbuf, apr_size_t logbufbytes)
{ int seen_eos = 0; int child_stopped_reading = 0;
apr_status_t rv; int dbpos = 0;
/* Keep writing data to the child until done or too much time * elapses with no progress or an error occurs.
*/
rv = apr_file_write_full(script_out, data, len, NULL);
if (rv != APR_SUCCESS) { /* silly script stopped reading, soak up remaining message */
child_stopped_reading = 1;
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02651) "Error writing request body to script %s",
r->filename);
}
}
apr_brigade_cleanup(bb);
} while (!seen_eos);
if (logbuf) {
logbuf[dbpos] = '\0';
}
return APR_SUCCESS;
}
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet)
¤
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 ist noch experimentell.