📄 mod_cgi.c
字号:
int i;#endif char **env; RAISE_SIGSTOP(CGI_CHILD);#ifdef DEBUG_CGI fprintf(dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n", r->filename, cld->nph ? "NPH " : "", argv0);#endif ap_add_cgi_vars(r); env = ap_create_environment(r->pool, r->subprocess_env);#ifdef DEBUG_CGI fprintf(dbg, "Environment: \n"); for (i = 0; env[i]; ++i) fprintf(dbg, "'%s'\n", env[i]);#endif#ifndef WIN32 ap_chdir_file(r->filename);#endif if (!cld->debug) ap_error_log2stderr(r->server); /* Transumute outselves into the script. * NB only ISINDEX scripts get decoded arguments. */ ap_cleanup_for_exec(); child_pid = ap_call_exec(r, pinfo, argv0, env, 0);#ifdef WIN32 return (child_pid);#else /* Uh oh. Still here. Where's the kaboom? There was supposed to be an * EARTH-shattering kaboom! * * Oh, well. Muddle through as best we can... * * Note that only stderr is available at this point, so don't pass in * a server to aplog_error. */ ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", r->filename); exit(0); /* NOT REACHED */ return (0);#endif}static int cgi_handler(request_rec *r){ int retval, nph, dbpos = 0; char *argv0, *dbuf = NULL; BUFF *script_out, *script_in, *script_err; char argsbuffer[HUGE_STRING_LEN]; int is_included = !strcmp(r->protocol, "INCLUDED"); void *sconf = r->server->module_config; cgi_server_conf *conf = (cgi_server_conf *) ap_get_module_config(sconf, &cgi_module); struct cgi_child_stuff cld; if (r->method_number == M_OPTIONS) { /* 99 out of 100 CGI scripts, this is all they support */ r->allowed |= (1 << M_GET); r->allowed |= (1 << M_POST); return DECLINED; } if ((argv0 = strrchr(r->filename, '/')) != NULL) argv0++; else argv0 = r->filename; nph = !(strncmp(argv0, "nph-", 4)); if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, "Options ExecCGI is off in this directory"); if (nph && is_included) return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, "attempt to include NPH CGI script");#if defined(OS2) || defined(WIN32) /* Allow for cgi files without the .EXE extension on them under OS/2 */ if (r->finfo.st_mode == 0) { struct stat statbuf; r->filename = ap_pstrcat(r->pool, r->filename, ".EXE", NULL); if ((stat(r->filename, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode))) { return log_scripterror(r, conf, NOT_FOUND, 0, "script not found or unable to stat"); } }#else if (r->finfo.st_mode == 0) return log_scripterror(r, conf, NOT_FOUND, APLOG_NOERRNO, "script not found or unable to stat");#endif if (S_ISDIR(r->finfo.st_mode)) return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, "attempt to invoke directory as script"); if (!ap_suexec_enabled) { if (!ap_can_exec(&r->finfo)) return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, "file permissions deny server execution"); } if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) return retval; ap_add_common_vars(r); cld.argv0 = argv0; cld.r = r; cld.nph = nph; cld.debug = conf->logname ? 1 : 0;#ifdef CHARSET_EBCDIC /* XXX:@@@ Is the generated/included output ALWAYS in text/ebcdic format? */ /* Or must we check the Content-Type first? */ ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, 1);#endif /*CHARSET_EBCDIC*/ /* * we spawn out of r->main if it's there so that we can avoid * waiting for free_proc_chain to cleanup in the middle of an * SSI request -djg */ if (!ap_bspawn_child(r->main ? r->main->pool : r->pool, cgi_child, (void *) &cld, kill_after_timeout, &script_out, &script_in, &script_err)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "couldn't spawn child process: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* Transfer any put/post args, CERN style... * Note that if a buggy script fails to read everything we throw * at it, or a buggy client sends too much, we get a SIGPIPE, so * we have to ignore SIGPIPE while doing this. CERN does the same * (and in fact, they pretty nearly guarantee themselves a SIGPIPE * on every invocation by chasing the real client data with a * spurious newline). */ if (ap_should_client_block(r)) { void (*handler) (int); int dbsize, len_read; if (conf->logname) { dbuf = ap_pcalloc(r->pool, conf->bufbytes + 1); dbpos = 0; } ap_hard_timeout("copy script args", r);#ifdef SIGPIPE handler = signal(SIGPIPE, SIG_IGN);#endif while ((len_read = ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0) { if (conf->logname) { if ((dbpos + len_read) > conf->bufbytes) { dbsize = conf->bufbytes - dbpos; } else { dbsize = len_read; } memcpy(dbuf + dbpos, argsbuffer, dbsize); dbpos += dbsize; } ap_reset_timeout(r); if (ap_bwrite(script_out, argsbuffer, len_read) < len_read) { /* silly script stopped reading, soak up remaining message */ while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0) { /* dump it */ } break; } } ap_bflush(script_out); signal(SIGPIPE, handler); ap_kill_timeout(r); } ap_bclose(script_out); /* Handle script return... */ if (script_in && !nph) { const char *location; char sbuf[MAX_STRING_LEN]; int ret; if ((ret = ap_scan_script_header_err_buff(r, script_in, sbuf))) { return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err); }#ifdef CHARSET_EBCDIC /* Now check the Content-Type to decide if conversion is needed */ ap_checkconv(r);#endif /*CHARSET_EBCDIC*/ location = ap_table_get(r->headers_out, "Location"); if (location && location[0] == '/' && r->status == 200) { /* Soak up all the script output */ ap_hard_timeout("read from script", r); while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) { continue; } while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { continue; } ap_kill_timeout(r); /* This redirect needs to be a GET no matter what the original * method was. */ r->method = ap_pstrdup(r->pool, "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. */ ap_table_unset(r->headers_in, "Content-Length"); ap_internal_redirect_handler(location, r); return OK; } else if (location && r->status == 200) { /* XX Note that if a script wants to produce its own Redirect * body, it now has to explicitly *say* "Status: 302" */ return REDIRECT; } ap_send_http_header(r); if (!r->header_only) { ap_send_fb(script_in, r); } ap_bclose(script_in); ap_soft_timeout("soaking script stderr", r); while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { continue; } ap_kill_timeout(r); ap_bclose(script_err); } if (script_in && nph) { ap_send_fb(script_in, r); } return OK; /* NOT r->status, even if it has changed. */}static const handler_rec cgi_handlers[] ={ {CGI_MAGIC_TYPE, cgi_handler}, {"cgi-script", cgi_handler}, {NULL}};module MODULE_VAR_EXPORT cgi_module ={ STANDARD_MODULE_STUFF, NULL, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ create_cgi_config, /* server config */ merge_cgi_config, /* merge server config */ cgi_cmds, /* command table */ cgi_handlers, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -