📄 cgic.cpp
字号:
// stdafx.cpp : source file that includes just the standard includes
// TestWeb.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include <io.h>
#include <fcntl.h>
#include <iostream>
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
#define NO_UNISTD 1
#if CGICDEBUG
#define CGICDEBUGSTART \
{ \
FILE *dout; \
dout = fopen("/home/boutell/public_html/debug", "a"); \
#define CGICDEBUGEND \
fclose(dout); \
}
#else /* CGICDEBUG */
#define CGICDEBUGSTART
#define CGICDEBUGEND
#endif /* CGICDEBUG */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#ifndef NO_UNISTD
#include <unistd.h>
#endif /* NO_UNISTD */
#include "cgic.h"
#define cgiStrEq(a, b) (!strcmp((a), (b)))
char *cgiServerSoftware;
char *cgiServerName;
char *cgiGatewayInterface;
char *cgiServerProtocol;
char *cgiServerPort;
char *cgiRequestMethod;
char *cgiPathInfo;
char *cgiPathTranslated;
char *cgiScriptName;
char *cgiQueryString;
char *cgiRemoteHost;
char *cgiRemoteAddr;
char *cgiAuthType;
char *cgiRemoteUser;
char *cgiRemoteIdent;
char *cgiContentType;
int cgiContentLength;
char *cgiAccept;
char *cgiUserAgent;
char *cgiReferrer;
char *cgiCookie;
FILE *cgiIn;
FILE *cgiOut;
/* One form entry, consisting of an attribute-value pair. */
typedef struct cgiFormEntryStruct {
char *attr;
char *value;
struct cgiFormEntryStruct *next;
} cgiFormEntry;
/* The first form entry. */
static cgiFormEntry *cgiFormEntryFirst;
/* True if CGI environment was restored from a file. */
static int cgiRestored = 0;
static void cgiGetenv(char **s, char *var);
typedef enum {
cgiParseSuccess,
cgiParseMemory,
cgiParseIO
} cgiParseResultType;
static cgiParseResultType cgiParseGetFormInput();
static cgiParseResultType cgiParsePostFormInput();
static cgiParseResultType cgiParseFormInput(char *data, int length);
static void cgiSetupConstants();
static void cgiFreeResources();
static int cgiStrEqNc(char *s1, char *s2);
int main(int argc, char *argv[]) {
int result;
char *cgiContentLengthString;
cgiSetupConstants();
cgiGetenv(&cgiServerSoftware, "SERVER_SOFTWARE");
cgiGetenv(&cgiServerName, "SERVER_NAME");
cgiGetenv(&cgiGatewayInterface, "GATEWAY_INTERFACE");
cgiGetenv(&cgiServerProtocol, "SERVER_PROTOCOL");
cgiGetenv(&cgiServerPort, "SERVER_PORT");
cgiGetenv(&cgiRequestMethod, "REQUEST_METHOD");
cgiGetenv(&cgiPathInfo, "PATH_INFO");
cgiGetenv(&cgiPathTranslated, "PATH_TRANSLATED");
cgiGetenv(&cgiScriptName, "SCRIPT_NAME");
cgiGetenv(&cgiQueryString, "QUERY_STRING");
cgiGetenv(&cgiRemoteHost, "REMOTE_HOST");
cgiGetenv(&cgiRemoteAddr, "REMOTE_ADDR");
cgiGetenv(&cgiAuthType, "AUTH_TYPE");
cgiGetenv(&cgiRemoteUser, "REMOTE_USER");
cgiGetenv(&cgiRemoteIdent, "REMOTE_IDENT");
cgiGetenv(&cgiContentType, "CONTENT_TYPE");
cgiGetenv(&cgiContentLengthString, "CONTENT_LENGTH");
cgiContentLength = atoi(cgiContentLengthString);
cgiGetenv(&cgiAccept, "HTTP_ACCEPT");
cgiGetenv(&cgiUserAgent, "HTTP_USER_AGENT");
cgiGetenv(&cgiReferrer, "HTTP_REFERER");
cgiGetenv(&cgiCookie, "HTTP_COOKIE");
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "%d\n", cgiContentLength);
fprintf(dout, "%s\n", cgiRequestMethod);
fprintf(dout, "%s\n", cgiContentType);
CGICDEBUGEND
#endif /* CGICDEBUG */
#ifdef WIN32
/* 1.07: Must set stdin and stdout to binary mode */
_setmode( _fileno( stdin ), _O_BINARY );
_setmode( _fileno( stdout ), _O_BINARY );
#endif /* WIN32 */
cgiFormEntryFirst = 0;
cgiIn = stdin;
cgiOut = stdout;
cgiRestored = 0;
/* These five lines keep compilers from
producing warnings that argc and argv
are unused. They have no actual function. */
if (argc) {
if (argv[0]) {
cgiRestored = 0;
}
}
if (cgiStrEqNc(cgiRequestMethod, "post")) {
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "POST recognized\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
if (cgiStrEqNc(cgiContentType, "application/x-www-form-urlencoded")) {
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "Calling PostFormInput\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
if (cgiParsePostFormInput() != cgiParseSuccess) {
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "PostFormInput failed\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
cgiFreeResources();
return -1;
}
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "PostFormInput succeeded\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
}
} else if (cgiStrEqNc(cgiRequestMethod, "get")) {
/* The spec says this should be taken care of by
the server, but... it isn't */
cgiContentLength = strlen(cgiQueryString);
if (cgiParseGetFormInput() != cgiParseSuccess) {
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "GetFormInput failed\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
cgiFreeResources();
return -1;
} else {
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "GetFormInput succeeded\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
}
}
result = cgiMain();
cgiFreeResources();
return result;
}
static void cgiGetenv(char **s, char *var){
*s = getenv(var);
if (!(*s)) {
*s = "";
}
}
static cgiParseResultType cgiParsePostFormInput() {
char *input;
cgiParseResultType result;
if (!cgiContentLength) {
return cgiParseSuccess;
}
input = (char *) malloc(cgiContentLength);
if (!input) {
return cgiParseMemory;
}
if (fread(input, 1, cgiContentLength, cgiIn) != cgiContentLength) {
return cgiParseIO;
}
result = cgiParseFormInput(input, cgiContentLength);
free(input);
return result;
}
static cgiParseResultType cgiParseGetFormInput() {
return cgiParseFormInput(cgiQueryString, cgiContentLength);
}
typedef enum {
cgiEscapeRest,
cgiEscapeFirst,
cgiEscapeSecond
} cgiEscapeState;
typedef enum {
cgiUnescapeSuccess,
cgiUnescapeMemory
} cgiUnescapeResultType;
static cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len);
static cgiParseResultType cgiParseFormInput(char *data, int length) {
/* Scan for pairs, unescaping and storing them as they are found. */
int pos = 0;
cgiFormEntry *n;
cgiFormEntry *l = 0;
while (pos != length) {
int foundEq = 0;
int foundAmp = 0;
int start = pos;
int len = 0;
char *attr;
char *value;
while (pos != length) {
if (data[pos] == '=') {
foundEq = 1;
pos++;
break;
}
pos++;
len++;
}
if (!foundEq) {
break;
}
if (cgiUnescapeChars(&attr, data+start, len)
!= cgiUnescapeSuccess) {
return cgiParseMemory;
}
start = pos;
len = 0;
while (pos != length) {
if (data[pos] == '&') {
foundAmp = 1;
pos++;
break;
}
pos++;
len++;
}
/* The last pair probably won't be followed by a &, but
that's fine, so check for that after accepting it */
if (cgiUnescapeChars(&value, data+start, len)
!= cgiUnescapeSuccess) {
return cgiParseMemory;
}
/* OK, we have a new pair, add it to the list. */
n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry));
if (!n) {
return cgiParseMemory;
}
n->attr = attr;
n->value = value;
n->next = 0;
if (!l) {
cgiFormEntryFirst = n;
} else {
l->next = n;
}
l = n;
if (!foundAmp) {
break;
}
}
return cgiParseSuccess;
}
static int cgiHexValue[256];
cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len) {
char *s;
cgiEscapeState escapeState = cgiEscapeRest;
int escapedValue = 0;
int srcPos = 0;
int dstPos = 0;
s = (char *) malloc(len + 1);
if (!s) {
return cgiUnescapeMemory;
}
while (srcPos < len) {
int ch = cp[srcPos];
switch (escapeState) {
case cgiEscapeRest:
if (ch == '%') {
escapeState = cgiEscapeFirst;
} else if (ch == '+') {
s[dstPos++] = ' ';
} else {
s[dstPos++] = ch;
}
break;
case cgiEscapeFirst:
escapedValue = cgiHexValue[ch] << 4;
escapeState = cgiEscapeSecond;
break;
case cgiEscapeSecond:
escapedValue += cgiHexValue[ch];
s[dstPos++] = escapedValue;
escapeState = cgiEscapeRest;
break;
}
srcPos++;
}
s[dstPos] = '\0';
*sp = s;
return cgiUnescapeSuccess;
}
static void cgiSetupConstants() {
int i;
for (i=0; (i < 256); i++) {
cgiHexValue[i] = 0;
}
cgiHexValue['0'] = 0;
cgiHexValue['1'] = 1;
cgiHexValue['2'] = 2;
cgiHexValue['3'] = 3;
cgiHexValue['4'] = 4;
cgiHexValue['5'] = 5;
cgiHexValue['6'] = 6;
cgiHexValue['7'] = 7;
cgiHexValue['8'] = 8;
cgiHexValue['9'] = 9;
cgiHexValue['A'] = 10;
cgiHexValue['B'] = 11;
cgiHexValue['C'] = 12;
cgiHexValue['D'] = 13;
cgiHexValue['E'] = 14;
cgiHexValue['F'] = 15;
cgiHexValue['a'] = 10;
cgiHexValue['b'] = 11;
cgiHexValue['c'] = 12;
cgiHexValue['d'] = 13;
cgiHexValue['e'] = 14;
cgiHexValue['f'] = 15;
}
static void cgiFreeResources() {
cgiFormEntry *c = cgiFormEntryFirst;
cgiFormEntry *n;
while (c) {
n = c->next;
free(c->attr);
free(c->value);
free(c);
c = n;
}
/* If the cgi environment was restored from a saved environment,
then these are in allocated space and must also be freed */
if (cgiRestored) {
free(cgiServerSoftware);
free(cgiServerName);
free(cgiGatewayInterface);
free(cgiServerProtocol);
free(cgiServerPort);
free(cgiRequestMethod);
free(cgiPathInfo);
free(cgiPathTranslated);
free(cgiScriptName);
free(cgiQueryString);
free(cgiRemoteHost);
free(cgiRemoteAddr);
free(cgiAuthType);
free(cgiRemoteUser);
free(cgiRemoteIdent);
free(cgiContentType);
free(cgiAccept);
free(cgiUserAgent);
free(cgiReferrer);
}
}
static cgiFormResultType cgiFormEntryString(
cgiFormEntry *e, char *result, int max, int newlines);
static cgiFormEntry *cgiFormEntryFindFirst(char *name);
static cgiFormEntry *cgiFormEntryFindNext();
cgiFormResultType cgiFormString(
char *name, char *result, int max) {
cgiFormEntry *e;
e = cgiFormEntryFindFirst(name);
if (!e) {
strcpy(result, "");
return cgiFormNotFound;
}
return cgiFormEntryString(e, result, max, 1);
}
cgiFormResultType cgiFormStringNoNewlines(
char *name, char *result, int max) {
cgiFormEntry *e;
e = cgiFormEntryFindFirst(name);
if (!e) {
strcpy(result, "");
return cgiFormNotFound;
}
return cgiFormEntryString(e, result, max, 0);
}
cgiFormResultType cgiFormStringMultiple(
char *name, char ***result) {
char **stringArray;
cgiFormEntry *e;
int i;
int total = 0;
/* Make two passes. One would be more efficient, but this
function is not commonly used. The select menu and
radio box functions are faster. */
e = cgiFormEntryFindFirst(name);
if (e != 0) {
do {
total++;
} while ((e = cgiFormEntryFindNext()) != 0);
}
stringArray = (char **) malloc(sizeof(char *) * (total + 1));
if (!stringArray) {
*result = 0;
return cgiFormMemory;
}
/* initialize all entries to null; the last will stay that way */
for (i=0; (i <= total); i++) {
stringArray[i] = 0;
}
/* Now go get the entries */
e = cgiFormEntryFindFirst(name);
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "StringMultiple Beginning\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
if (e) {
i = 0;
do {
int max = strlen(e->value) + 1;
stringArray[i] = (char *) malloc(max);
if (stringArray[i] == 0) {
/* Memory problems */
cgiStringArrayFree(stringArray);
*result = 0;
return cgiFormMemory;
}
strcpy(stringArray[i], e->value);
cgiFormEntryString(e, stringArray[i], max, 1);
i++;
} while ((e = cgiFormEntryFindNext()) != 0);
*result = stringArray;
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "StringMultiple Succeeding\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
return cgiFormSuccess;
} else {
*result = stringArray;
#ifdef CGICDEBUG
CGICDEBUGSTART
fprintf(dout, "StringMultiple found nothing\n");
CGICDEBUGEND
#endif /* CGICDEBUG */
return cgiFormNotFound;
}
}
cgiFormResultType cgiFormStringSpaceNeeded(
char *name, int *result) {
cgiFormEntry *e;
e = cgiFormEntryFindFirst(name);
if (!e) {
*result = 1;
return cgiFormNotFound;
}
*result = strlen(e->value) + 1;
return cgiFormSuccess;
}
static cgiFormResultType cgiFormEntryString(
cgiFormEntry *e, char *result, int max, int newlines) {
char *dp, *sp;
int truncated = 0;
int len = 0;
int avail = max-1;
int crCount = 0;
int lfCount = 0;
dp = result;
sp = e->value;
while (1) {
int ch;
/* 1.07: don't check for available space now.
We check for it immediately before adding
an actual character. 1.06 handled the
trailing null of the source string improperly,
resulting in a cgiFormTruncated error. */
ch = *sp;
/* Fix the CR/LF, LF, CR nightmare: watch for
consecutive bursts of CRs and LFs in whatever
pattern, then actually output the larger number
of LFs. Consistently sane, yet it still allows
consecutive blank lines when the user
actually intends them. */
if ((ch == 13) || (ch == 10)) {
if (ch == 13) {
crCount++;
} else {
lfCount++;
}
} else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -