📄 mod_cgi.c
字号:
e_info->in_pipe, e_info->out_pipe, e_info->err_pipe)) != APR_SUCCESS) || ((rc = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) ||#ifdef RLIMIT_CPU ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu)) != APR_SUCCESS) ||#endif#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem)) != APR_SUCCESS) ||#endif#ifdef RLIMIT_NPROC ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc)) != APR_SUCCESS) ||#endif ((rc = apr_procattr_cmdtype_set(procattr, e_info->cmd_type)) != APR_SUCCESS) || ((rc = apr_procattr_detach_set(procattr, e_info->detached)) != APR_SUCCESS) || ((rc = apr_procattr_addrspace_set(procattr, e_info->addrspace)) != APR_SUCCESS) || ((rc = apr_procattr_child_errfn_set(procattr, cgi_child_errfn)) != APR_SUCCESS)) { /* Something bad happened, tell the world. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "couldn't set child process attributes: %s", r->filename); } else { procnew = apr_pcalloc(p, sizeof(*procnew)); rc = ap_os_create_privileged_process(r, procnew, command, argv, env, procattr, p); if (rc != APR_SUCCESS) { /* Bad things happened. Everyone should have cleaned up. */ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, rc, r, "couldn't create child process: %d: %s", rc, apr_filepath_name_get(r->filename)); } else { apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); *script_in = procnew->out; if (!*script_in) return APR_EBADF; apr_file_pipe_timeout_set(*script_in, r->server->timeout); if (e_info->prog_type == RUN_AS_CGI) { *script_out = procnew->in; if (!*script_out) return APR_EBADF; apr_file_pipe_timeout_set(*script_out, r->server->timeout); *script_err = procnew->err; if (!*script_err) return APR_EBADF; apr_file_pipe_timeout_set(*script_err, r->server->timeout); } } }#ifdef DEBUG_CGI fclose(dbg);#endif return (rc);}static apr_status_t default_build_command(const char **cmd, const char ***argv, request_rec *r, apr_pool_t *p, cgi_exec_info_t *e_info){ int numwords, x, idx; char *w; const char *args = NULL; if (e_info->process_cgi) { *cmd = r->filename; /* Do not process r->args if they contain an '=' assignment */ if (r->args && r->args[0] && !ap_strchr_c(r->args, '=')) { args = r->args; } } if (!args) { numwords = 1; } else { /* count the number of keywords */ for (x = 0, numwords = 2; args[x]; x++) { if (args[x] == '+') { ++numwords; } } } /* Everything is - 1 to account for the first parameter * which is the program name. */ if (numwords > APACHE_ARG_MAX - 1) { numwords = APACHE_ARG_MAX - 1; /* Truncate args to prevent overrun */ } *argv = apr_palloc(p, (numwords + 2) * sizeof(char *)); (*argv)[0] = *cmd; for (x = 1, idx = 1; x < numwords; x++) { w = ap_getword_nulls(p, &args, '+'); ap_unescape_url(w); (*argv)[idx++] = ap_escape_shell_cmd(p, w); } (*argv)[idx] = NULL; return APR_SUCCESS;}static void discard_script_output(apr_bucket_brigade *bb){ apr_bucket *e; const char *buf; apr_size_t len; apr_status_t rv; for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { if (APR_BUCKET_IS_EOS(e)) { break; } rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) { break; } }}#if APR_FILES_AS_SOCKETS/* A CGI bucket type is needed to catch any output to stderr from the * script; see PR 22030. */static const apr_bucket_type_t bucket_type_cgi;struct cgi_bucket_data { apr_pollset_t *pollset; request_rec *r;};/* Create a CGI bucket using pipes from script stdout 'out' * and stderr 'err', for request 'r'. */static apr_bucket *cgi_bucket_create(request_rec *r, apr_file_t *out, apr_file_t *err, apr_bucket_alloc_t *list){ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); apr_status_t rv; apr_pollfd_t fd; struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); APR_BUCKET_INIT(b); b->free = apr_bucket_free; b->list = list; b->type = &bucket_type_cgi; b->length = (apr_size_t)(-1); b->start = -1; /* Create the pollset */ rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); AP_DEBUG_ASSERT(rv == APR_SUCCESS); fd.desc_type = APR_POLL_FILE; fd.reqevents = APR_POLLIN; fd.p = r->pool; fd.desc.f = out; /* script's stdout */ fd.client_data = (void *)1; rv = apr_pollset_add(data->pollset, &fd); AP_DEBUG_ASSERT(rv == APR_SUCCESS); fd.desc.f = err; /* script's stderr */ fd.client_data = (void *)2; rv = apr_pollset_add(data->pollset, &fd); AP_DEBUG_ASSERT(rv == APR_SUCCESS); data->r = r; b->data = data; return b;}/* Create a duplicate CGI bucket using given bucket data */static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data, apr_bucket_alloc_t *list){ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); APR_BUCKET_INIT(b); b->free = apr_bucket_free; b->list = list; b->type = &bucket_type_cgi; b->length = (apr_size_t)(-1); b->start = -1; b->data = data; return b;}/* Handle stdout from CGI child. Duplicate of logic from the _read * method of the real APR pipe bucket implementation. */static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out, const char **str, apr_size_t *len){ char *buf; apr_status_t rv; *str = NULL; *len = APR_BUCKET_BUFF_SIZE; buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ rv = apr_file_read(out, buf, len); if (rv != APR_SUCCESS && rv != APR_EOF) { apr_bucket_free(buf); return rv; } if (*len > 0) { struct cgi_bucket_data *data = a->data; apr_bucket_heap *h; /* 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, const char **str, apr_size_t *len, apr_read_type_e block){ struct cgi_bucket_data *data = b->data; apr_interval_time_t timeout; apr_status_t rv; int gotdata = 0; timeout = block == APR_NONBLOCK_READ ? 0 : data->r->server->timeout; do { const apr_pollfd_t *results; apr_int32_t num; rv = apr_pollset_poll(data->pollset, timeout, &num, &results); if (APR_STATUS_IS_TIMEUP(rv)) { if (timeout) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, data->r, "Timeout waiting for output from CGI script %s", data->r->filename); return rv; } else { return APR_EAGAIN; } } else if (APR_STATUS_IS_EINTR(rv)) { continue; } else if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, "poll failed waiting for CGI child"); return rv; } for (; num; num--, results++) { if (results[0].client_data == (void *)1) { /* stdout */ rv = cgi_read_stdout(b, results[0].desc.f, str, len); if (APR_STATUS_IS_EOF(rv)) { rv = APR_SUCCESS; } gotdata = 1; } else { /* stderr */ apr_status_t rv2 = log_script_err(data->r, results[0].desc.f); if (APR_STATUS_IS_EOF(rv2)) { apr_pollset_remove(data->pollset, &results[0]); } } } } while (!gotdata); return rv;}static const apr_bucket_type_t bucket_type_cgi = { "CGI", 5, APR_BUCKET_DATA, apr_bucket_destroy_noop, cgi_bucket_read, apr_bucket_setaside_notimpl, apr_bucket_split_notimpl, apr_bucket_copy_notimpl};#endifstatic int cgi_handler(request_rec *r){ int nph; apr_size_t dbpos = 0; const char *argv0; const char *command; const char **argv; char *dbuf = NULL; apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL; apr_bucket_brigade *bb; apr_bucket *b; int is_included; int seen_eos, child_stopped_reading; apr_pool_t *p; cgi_server_conf *conf; apr_status_t rv; cgi_exec_info_t e_info; conn_rec *c = r->connection; if(strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) return DECLINED; is_included = !strcmp(r->protocol, "INCLUDED"); p = r->main ? r->main->pool : r->pool; argv0 = apr_filepath_name_get(r->filename); nph = !(strncmp(argv0, "nph-", 4)); conf = ap_get_module_config(r->server->module_config, &cgi_module); if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "Options ExecCGI is off in this directory"); if (nph && is_included) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "attempt to include NPH CGI script"); if (r->finfo.filetype == 0) return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, "script not found or unable to stat"); if (r->finfo.filetype == APR_DIR) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "attempt to invoke directory as script"); if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) && r->path_info && *r->path_info) { /* default to accept */ return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, "AcceptPathInfo off disallows user's path"); }/* if (!ap_suexec_enabled) { if (!ap_can_exec(&r->finfo)) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "file permissions deny server execution"); }*/ ap_add_common_vars(r); ap_add_cgi_vars(r); e_info.process_cgi = 1; e_info.cmd_type = APR_PROGRAM; e_info.detached = 0; e_info.in_pipe = APR_CHILD_BLOCK; e_info.out_pipe = APR_CHILD_BLOCK; e_info.err_pipe = APR_CHILD_BLOCK; e_info.prog_type = RUN_AS_CGI; e_info.bb = NULL; e_info.ctx = NULL; e_info.next = NULL; e_info.addrspace = 0; /* build the command line */ if ((rv = cgi_build_command(&command, &argv, r, p, &e_info)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "don't know how to spawn child process: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* run the script in its own process */ if ((rv = run_cgi_child(&script_out, &script_in, &script_err, command, argv, r, p, &e_info)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "couldn't spawn child process: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* Transfer any put/post args, CERN style... * Note that we already ignore SIGPIPE in the core server. */ bb = apr_brigade_create(r->pool, c->bucket_alloc); seen_eos = 0; child_stopped_reading = 0; if (conf->logname) { dbuf = apr_palloc(r->pool, conf->bufbytes + 1); dbpos = 0; } do { apr_bucket *bucket; rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Error reading request entity data"); return HTTP_INTERNAL_SERVER_ERROR; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -