diff options
Diffstat (limited to 'agen5/agCgi.c')
-rw-r--r-- | agen5/agCgi.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/agen5/agCgi.c b/agen5/agCgi.c new file mode 100644 index 0000000..641988d --- /dev/null +++ b/agen5/agCgi.c @@ -0,0 +1,172 @@ + +/** + * @file agCgi.c + * + * Time-stamp: "2012-03-04 19:19:12 bkorb" + * + * 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-2012 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 <http://www.gnu.org/licenses/>. + */ + +typedef struct { + char const* pzName; + char* pzValue; +} tNameMap; + +#define ENV_TABLE \ + _ET_(SERVER_SOFTWARE) \ + _ET_(SERVER_NAME) \ + _ET_(GATEWAY_INTERFACE) \ + _ET_(SERVER_PROTOCOL) \ + _ET_(SERVER_PORT) \ + _ET_(REQUEST_METHOD) \ + _ET_(PATH_INFO) \ + _ET_(PATH_TRANSLATED) \ + _ET_(SCRIPT_NAME) \ + _ET_(QUERY_STRING) \ + _ET_(REMOTE_HOST) \ + _ET_(REMOTE_ADDR) \ + _ET_(AUTH_TYPE) \ + _ET_(REMOTE_USER) \ + _ET_(REMOTE_IDENT) \ + _ET_(CONTENT_TYPE) \ + _ET_(CONTENT_LENGTH) \ + _ET_(HTTP_ACCEPT) \ + _ET_(HTTP_USER_AGENT) \ + _ET_(HTTP_REFERER) + +static tNameMap nameValueMap[] = { +#define _ET_(n) { #n, NULL }, + ENV_TABLE +#undef _ET_ + { NULL, NULL } +}; + +typedef enum { +#define _ET_(n) n ## _IDX, + ENV_TABLE +#undef _ET_ + NAME_CT +} tNameIdx; + +#define pzCgiMethod nameValueMap[ REQUEST_METHOD_IDX ].pzValue +#define pzCgiQuery nameValueMap[ QUERY_STRING_IDX ].pzValue +#define pzCgiLength nameValueMap[ CONTENT_LENGTH_IDX ].pzValue + +/* = = = START-STATIC-FORWARD = = = */ +static char* +parseInput(char* pzSrc, int len); +/* = = = END-STATIC-FORWARD = = = */ + +LOCAL void +loadCgi(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); + (void)fdopen(STDERR_FILENO, "w" FOPEN_BINARY_FLAG); + oops_pfx = CGI_ERR_MSG_FMT; + { + int tmpfd; + 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. + */ + { + tNameMap* pNM = nameValueMap; + tNameIdx ix = (tNameIdx)0; + + do { + pNM->pzValue = getenv(pNM->pzName); + if (pNM->pzValue == NULL) + pNM->pzValue = (char*)zNil; + } while (pNM++, ++ix < NAME_CT); + } + + base_ctx = (scan_ctx_t*)AGALOC(sizeof(scan_ctx_t), "CGI ctx"); + memset((void*)base_ctx, 0, sizeof(scan_ctx_t)); + + { + size_t textLen = strtoul(pzCgiLength, NULL, 0); + char* pzText; + + if (strcasecmp(pzCgiMethod, "POST") == 0) { + if (textLen == 0) + AG_ABEND(LOAD_CGI_NO_DATA_MSG); + + pzText = AGALOC(textLen + 1, "CGI POST"); + if (fread(pzText, (size_t)1, textLen, stdin) != textLen) + AG_CANT(LOAD_CGI_READ_NAME, LOAD_CGI_READ_WHAT); + + pzText[ textLen ] = NUL; + + base_ctx->scx_data = parseInput(pzText, (int)textLen); + AGFREE(pzText); + + } else if (strcasecmp(pzCgiMethod, LOAD_CGI_GET_NAME) == 0) { + if (textLen == 0) + textLen = strlen(pzCgiQuery); + base_ctx->scx_data = parseInput(pzCgiQuery, (int)textLen); + + } else { + AG_ABEND(aprf(LOAD_CGI_INVAL_REQ_FMT, pzCgiMethod)); + /* NOTREACHED */ +#ifdef WARNING_WATCH + pzText = NULL; +#endif + } + } + + base_ctx->scx_line = 1; + base_ctx->scx_fname = LOAD_CGI_DEFS_MARKER; + base_ctx->scx_scan = base_ctx->scx_data; +} + + +static char* +parseInput(char* pzSrc, int len) +{ +# define defLen (sizeof("Autogen Definitions cgi;\n") - 1) + char* pzRes = AGALOC((len * 2) + defLen + 1, "CGI Definitions"); + + memcpy(pzRes, PARSE_INPUT_AG_DEF_STR, defLen); + (void)cgi_run_fsm(pzSrc, len, pzRes + defLen, len*2); + return AGREALOC(pzRes, strlen(pzRes)+1, "CGI input"); +} + +/* + * Local Variables: + * mode: C + * c-file-style: "stroustrup" + * indent-tabs-mode: nil + * End: + * end of agen5/agCgi.c */ |