/** * @file agCgi.c * * This is a CGI wrapper for AutoGen. It will take POST-method * name-value pairs and emit AutoGen definitions to a spawned * AutoGen process. * * This file is part of AutoGen. * AutoGen Copyright (C) 1992-2016 by Bruce Korb - all rights reserved * * AutoGen is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * AutoGen is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ typedef struct { char const * name; char * cgi_val; } name_map_t; #define ENV_TABLE \ _ET_(REQUEST_METHOD) \ _ET_(QUERY_STRING) \ _ET_(CONTENT_LENGTH) \ \ _ET_(AUTH_TYPE) \ _ET_(CONTENT_TYPE) \ _ET_(GATEWAY_INTERFACE) \ _ET_(HTTP_ACCEPT) \ _ET_(HTTP_REFERER) \ _ET_(HTTP_USER_AGENT) \ _ET_(PATH_INFO) \ _ET_(PATH_TRANSLATED) \ _ET_(REMOTE_ADDR) \ _ET_(REMOTE_HOST) \ _ET_(REMOTE_IDENT) \ _ET_(REMOTE_USER) \ _ET_(SCRIPT_NAME) \ _ET_(SERVER_NAME) \ _ET_(SERVER_PORT) \ _ET_(SERVER_PROTOCOL) \ _ET_(SERVER_SOFTWARE) static name_map_t name_val_map[] = { #define _ET_(n) { #n, NULL }, ENV_TABLE #undef _ET_ { NULL, NULL } }; typedef enum { #define _ET_(n) n ## _IDX, ENV_TABLE #undef _ET_ NAME_CT } name_idx_t; #define cgi_method name_val_map[ REQUEST_METHOD_IDX ].cgi_val #define cgi_query name_val_map[ QUERY_STRING_IDX ].cgi_val #define cgi_len name_val_map[ CONTENT_LENGTH_IDX ].cgi_val static inline char * parse_input(char * src, int len) { size_t rsz = (len * 4) + PARSE_INPUT_AG_DEF_STR_LEN; char * res = AGALOC(rsz, "CGI Defs"); memcpy(res, PARSE_INPUT_AG_DEF_STR, PARSE_INPUT_AG_DEF_STR_LEN); (void)cgi_run_fsm(src, len, res + PARSE_INPUT_AG_DEF_STR_LEN, len * 2); assert(rsz > strlen(res)); return AGREALOC(res, strlen(res)+1, "CGI input"); } LOCAL void load_cgi(void) { /* * Redirect stderr to a file. If it gets used, we must trap it * and emit the content-type: preamble before actually emitting it. * First, tho, do a simple stderr->stdout redirection just in case * we stumble before we're done with this. */ dup2(STDOUT_FILENO, STDERR_FILENO); { FILE * fp = fdopen(STDERR_FILENO, "w" FOPEN_BINARY_FLAG); (void)fp; } { int tmpfd; oops_pfx = CGI_ERR_MSG_FMT; AGDUPSTR(cgi_stderr, CGI_TEMP_ERR_FILE_STR, "stderr file"); tmpfd = mkstemp(cgi_stderr); if (tmpfd < 0) AG_ABEND(aprf(MKSTEMP_FAIL_FMT, cgi_stderr)); dup2(tmpfd, STDERR_FILENO); close(tmpfd); } /* * Pull the CGI-relevant environment variables. Anything we don't find * gets an empty string default. */ { name_map_t * nm_map = name_val_map; name_idx_t ix = (name_idx_t)0; do { nm_map->cgi_val = getenv(nm_map->name); if (nm_map->cgi_val == NULL) nm_map->cgi_val = (char *)zNil; } while (nm_map++, ++ix < NAME_CT); } base_ctx = (scan_ctx_t *)AGALOC(sizeof(scan_ctx_t), "CGI ctx"); memset(VOIDP(base_ctx), 0, sizeof(scan_ctx_t)); { size_t len = strtoul(cgi_len, NULL, 0); char * text; if (strcasecmp(cgi_method, "POST") == 0) { if (len == 0) AG_ABEND(LOAD_CGI_NO_DATA_MSG); text = AGALOC(len + 1, "CGI POST"); if (fread(text, (size_t)1, len, stdin) != len) AG_CANT(LOAD_CGI_READ_NAME, LOAD_CGI_READ_WHAT); text[ len ] = NUL; base_ctx->scx_data = parse_input(text, (int)len); AGFREE(text); } else if (strcasecmp(cgi_method, LOAD_CGI_GET_NAME) == 0) { if (len == 0) len = strlen(cgi_query); base_ctx->scx_data = parse_input(cgi_query, (int)len); } else { AG_ABEND(aprf(LOAD_CGI_INVAL_REQ_FMT, cgi_method)); /* NOTREACHED */ #ifdef WARNING_WATCH text = NULL; #endif } } base_ctx->scx_line = 1; base_ctx->scx_fname = LOAD_CGI_DEFS_MARKER; base_ctx->scx_scan = base_ctx->scx_data; } /* * Local Variables: * mode: C * c-file-style: "stroustrup" * indent-tabs-mode: nil * End: * end of agen5/agCgi.c */