stoddard 99/10/11 13:44:33
Modified: src/modules/standard mod_cgi.c Log: First cut at migrating mod_cgi over to APR. Still needs some work to make it Win32 friendly (use named pipes, etc.) Submitted by: Paul Reder Reviewed by: Bill Stoddard Revision Changes Path 1.6 +109 -69 apache-2.0/src/modules/standard/mod_cgi.c Index: mod_cgi.c =================================================================== RCS file: /home/cvs/apache-2.0/src/modules/standard/mod_cgi.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- mod_cgi.c 1999/08/31 05:33:46 1.5 +++ mod_cgi.c 1999/10/11 20:44:28 1.6 @@ -166,7 +166,7 @@ static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret, int show_errno, char *error) { - FILE *f; + ap_file_t *f; struct stat finfo; ap_log_rerror(APLOG_MARK, show_errno|APLOG_ERR, r, @@ -175,20 +175,20 @@ if (!conf->logname || ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0) && (finfo.st_size > conf->logbytes)) || - ((f = ap_pfopen(r->pool, ap_server_root_relative(r->pool, conf->logname), - "a")) == NULL)) { + (ap_open(&f, r->pool, ap_server_root_relative(r->pool, conf->logname), + APR_APPEND | APR_BUFFERED, APR_OS_DEFAULT) != APR_SUCCESS)) { return ret; } /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ - fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri, + ap_fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri, r->args ? "?" : "", r->args ? r->args : "", r->protocol); /* "%% 500 /usr/local/apache/cgi-bin */ - fprintf(f, "%%%% %d %s\n", ret, r->filename); + ap_fprintf(f, "%%%% %d %s\n", ret, r->filename); - fprintf(f, "%%error\n%s\n", error); + ap_fprintf(f, "%%error\n%s\n", error); - ap_pfclose(r->pool, f); + ap_close(f); return ret; } @@ -196,17 +196,17 @@ char *dbuf, const char *sbuf, BUFF *script_in, BUFF *script_err) { ap_array_header_t *hdrs_arr = ap_table_elts(r->headers_in); - table_entry *hdrs = (table_entry *) hdrs_arr->elts; + ap_table_entry_t *hdrs = (ap_table_entry_t *) hdrs_arr->elts; char argsbuffer[HUGE_STRING_LEN]; - FILE *f; + ap_file_t *f; int i; struct stat finfo; if (!conf->logname || ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0) && (finfo.st_size > conf->logbytes)) || - ((f = ap_pfopen(r->pool, ap_server_root_relative(r->pool, conf->logname), - "a")) == NULL)) { + (ap_open(&f, r->pool, ap_server_root_relative(r->pool, conf->logname), + APR_APPEND, APR_OS_DEFAULT) != APR_SUCCESS)) { /* Soak up script output */ while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) continue; @@ -227,55 +227,55 @@ } /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ - fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri, + ap_fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri, r->args ? "?" : "", r->args ? r->args : "", r->protocol); /* "%% 500 /usr/local/apache/cgi-bin" */ - fprintf(f, "%%%% %d %s\n", ret, r->filename); + ap_fprintf(f, "%%%% %d %s\n", ret, r->filename); - fputs("%request\n", f); + ap_puts("%request\n", f); for (i = 0; i < hdrs_arr->nelts; ++i) { if (!hdrs[i].key) continue; - fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); + ap_fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); } if ((r->method_number == M_POST || r->method_number == M_PUT) && *dbuf) { - fprintf(f, "\n%s\n", dbuf); + ap_fprintf(f, "\n%s\n", dbuf); } - fputs("%response\n", f); + ap_puts("%response\n", f); hdrs_arr = ap_table_elts(r->err_headers_out); - hdrs = (table_entry *) hdrs_arr->elts; + hdrs = (ap_table_entry_t *) hdrs_arr->elts; for (i = 0; i < hdrs_arr->nelts; ++i) { if (!hdrs[i].key) continue; - fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); + ap_fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); } if (sbuf && *sbuf) - fprintf(f, "%s\n", sbuf); + ap_fprintf(f, "%s\n", sbuf); if (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) { - fputs("%stdout\n", f); - fputs(argsbuffer, f); + ap_puts("%stdout\n", f); + ap_puts(argsbuffer, f); while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) - fputs(argsbuffer, f); - fputs("\n", f); + ap_puts(argsbuffer, f); + ap_puts("\n", f); } if (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { - fputs("%stderr\n", f); - fputs(argsbuffer, f); + ap_puts("%stderr\n", f); + ap_puts(argsbuffer, f); while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) - fputs(argsbuffer, f); - fputs("\n", f); + ap_puts(argsbuffer, f); + ap_puts("\n", f); } ap_bclose(script_in); ap_bclose(script_err); - ap_pfclose(r->pool, f); + ap_close(f); return ret; } @@ -295,12 +295,20 @@ char *argv0; }; -static int cgi_child(void *child_stuff, child_info *pinfo) +static int cgi_child(struct cgi_child_stuff *child_stuff, + BUFF **script_out, BUFF **script_in, BUFF **script_err) { - struct cgi_child_stuff *cld = (struct cgi_child_stuff *) child_stuff; + struct cgi_child_stuff *cld = child_stuff; request_rec *r = cld->r; + char err_string[MAX_STRING_LEN]; char *argv0 = cld->argv0; - int child_pid; + char **args = NULL; + char **env; + ap_context_t *child_context; + ap_procattr_t *procattr; + ap_proc_t *procnew; + ap_os_proc_t fred; + int rc; #ifdef DEBUG_CGI #ifdef OS2 @@ -312,7 +320,9 @@ int i; #endif - char **env; + ap_block_alarms(); + + child_context = r->main ? r->main->pool : r->pool; RAISE_SIGSTOP(CGI_CHILD); #ifdef DEBUG_CGI @@ -321,7 +331,7 @@ #endif ap_add_cgi_vars(r); - env = ap_create_environment(r->pool, r->subprocess_env); + env = ap_create_environment(child_context, r->subprocess_env); #ifdef DEBUG_CGI fprintf(dbg, "Environment: \n"); @@ -329,40 +339,81 @@ 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. + /* Transumute ourselves into the script. * NB only ISINDEX scripts get decoded arguments. */ #ifdef TPF + ap_unblock_alarms(); + return (0); #else ap_cleanup_for_exec(); - child_pid = ap_call_exec(r, pinfo, argv0, env, 0); -#if defined(WIN32) || defined(OS2) - return (child_pid); -#else + if ((ap_createprocattr_init(&procattr, child_context) != APR_SUCCESS) || + (ap_setprocattr_io(procattr, + script_in ? 1 : 0, + script_out ? 1 : 0, + script_err ? 1 : 0) != APR_SUCCESS) || + (ap_setprocattr_dir(procattr, r->filename) != APR_SUCCESS) || + (ap_setprocattr_cmdtype(procattr, APR_PROGRAM) != APR_SUCCESS)) { + /* Something bad happened, tell the world. */ + ap_log_rerror(APLOG_MARK, APLOG_ERR, r, + "couldn't create child process: %s", r->filename); + ap_unblock_alarms(); - /* 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. - */ + return (-1); + } + else { - ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", r->filename); - exit(0); - /* NOT REACHED */ - return (0); + rc = ap_tokenize_to_argv(child_context, argv0, &args); + if (rc != APR_SUCCESS) { + ap_snprintf(err_string, sizeof(err_string), + "argv[] allocation failed, reason: %s (errno = %d)\n", + strerror(errno), errno); + write(STDERR_FILENO, err_string, strlen(err_string)); + ap_unblock_alarms(); + + exit(0); + } + + rc = ap_create_process(&procnew, child_context, r->filename, args, + env, procattr); + + if (rc != APR_SUCCESS) { + /* Bad things happened. Everyone should have cleaned up. */ + ap_log_rerror(APLOG_MARK, APLOG_ERR, r, + "couldn't create child process: %d: %s", rc, r->filename); + } + else { +#ifndef WIN32 + /* pjr - this is a cheap hack for now to get the basics working in + * stages. ap_note_subprocess and free_proc need to be redone + * to make use of ap_proc_t instead of pid. + */ + ap_get_os_proc(procnew, &fred); + ap_note_subprocess(child_context, fred, kill_after_timeout); #endif + if (script_in) { + *script_in = ap_bcreate(child_context, B_WR); + } + + if (script_out) { + *script_out = ap_bcreate(child_context, B_RD); + } + + if (script_err) { + *script_err = ap_bcreate(child_context, B_RD); + } + } + + ap_unblock_alarms(); + + return (rc); + } #endif /* TPF */ } @@ -449,12 +500,10 @@ * 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; + if (cgi_child(&cld, &script_out, &script_in, &script_err) < 0) { + 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... @@ -573,20 +622,11 @@ module MODULE_VAR_EXPORT cgi_module = { STANDARD20_MODULE_STUFF, - NULL, /* pre_config */ - NULL, /* post_config */ - NULL, /* open_logs */ - NULL, /* child 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 ap_table_t */ cgi_handlers, /* handlers */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ NULL /* register hooks */ };