?? webs.c
字號:
}
fmtAlloc(&cmd, 64, T("%s"), value);
if ((wp->since = dateParse(tip, cmd)) != 0) {
wp->flags |= WEBS_IF_MODIFIED;
}
bfreeSafe(B_L, cmd);
#endif /* WEBS_IF_MODIFIED_SUPPORT */
}
}
}
/******************************************************************************/
/*
* Set the variable (CGI) environment for this request. Create variables
* for all standard CGI variables. Also decode the query string and create
* a variable for each name=value pair.
*/
void websSetEnv(webs_t wp)
{
char_t portBuf[8];
char_t *keyword, *value, *valCheck, *valNew;
a_assert(websValid(wp));
websSetVar(wp, T("QUERY_STRING"), wp->query);
websSetVar(wp, T("GATEWAY_INTERFACE"), T("CGI/1.1"));
websSetVar(wp, T("SERVER_HOST"), websHost);
websSetVar(wp, T("SERVER_NAME"), websHost);
websSetVar(wp, T("SERVER_URL"), websHostUrl);
websSetVar(wp, T("REMOTE_HOST"), wp->ipaddr);
websSetVar(wp, T("REMOTE_ADDR"), wp->ipaddr);
websSetVar(wp, T("PATH_INFO"), wp->path);
stritoa(websPort, portBuf, sizeof(portBuf));
websSetVar(wp, T("SERVER_PORT"), portBuf);
websSetVar(wp, T("SERVER_ADDR"), websIpaddr);
fmtAlloc(&value, FNAMESIZE, T("%s/%s"), WEBS_NAME, WEBS_VERSION);
websSetVar(wp, T("SERVER_SOFTWARE"), value);
bfreeSafe(B_L, value);
websSetVar(wp, T("SERVER_PROTOCOL"), wp->protoVersion);
/*
* Decode and create an environment query variable for each query keyword.
* We split into pairs at each '&', then split pairs at the '='.
* Note: we rely on wp->decodedQuery preserving the decoded values in the
* symbol table.
*/
wp->decodedQuery = bstrdup(B_L, wp->query);
keyword = gstrtok(wp->decodedQuery, T("&"));
while (keyword != NULL) {
if ((value = gstrchr(keyword, '=')) != NULL) {
*value++ = '\0';
websDecodeUrl(keyword, keyword, gstrlen(keyword));
websDecodeUrl(value, value, gstrlen(value));
} else {
value = T("");
}
if (*keyword) {
/*
* If keyword has already been set, append the new value to what has
* been stored.
*/
if ((valCheck = websGetVar(wp, keyword, NULL)) != 0) {
fmtAlloc(&valNew, 256, T("%s %s"), valCheck, value);
websSetVar(wp, keyword, valNew);
bfreeSafe(B_L, valNew);
} else {
websSetVar(wp, keyword, value);
}
}
keyword = gstrtok(NULL, T("&"));
}
#ifdef EMF
/*
* Add GoAhead Embedded Management Framework defines
*/
websSetEmfEnvironment(wp);
#endif
}
/******************************************************************************/
/*
* Define a webs (CGI) variable for this connection. Also create in relevant
* scripting engines. Note: the incoming value may be volatile.
*/
void websSetVar(webs_t wp, char_t *var, char_t *value)
{
value_t v;
a_assert(websValid(wp));
/*
* value_instring will allocate the string if required.
*/
if (value) {
v = valueString(value, VALUE_ALLOCATE);
} else {
v = valueString(T(""), VALUE_ALLOCATE);
}
symEnter(wp->cgiVars, var, v, 0);
}
/******************************************************************************/
/*
* Return TRUE if a webs variable exists for this connection.
*/
int websTestVar(webs_t wp, char_t *var)
{
sym_t *sp;
a_assert(websValid(wp));
if (var == NULL || *var == '\0') {
return 0;
}
if ((sp = symLookup(wp->cgiVars, var)) == NULL) {
return 0;
}
return 1;
}
/******************************************************************************/
/*
* Get a webs variable but return a default value if string not found.
* Note, defaultGetValue can be NULL to permit testing existence.
*/
char_t *websGetVar(webs_t wp, char_t *var, char_t *defaultGetValue)
{
sym_t *sp;
a_assert(websValid(wp));
a_assert(var && *var);
if ((sp = symLookup(wp->cgiVars, var)) != NULL) {
a_assert(sp->content.type == string);
if (sp->content.value.string) {
return sp->content.value.string;
} else {
return T("");
}
}
return defaultGetValue;
}
/******************************************************************************/
/*
* Return TRUE if a webs variable is set to a given value
*/
int websCompareVar(webs_t wp, char_t *var, char_t *value)
{
a_assert(websValid(wp));
a_assert(var && *var);
if (gstrcmp(value, websGetVar(wp, var, T(" __UNDEF__ "))) == 0) {
return 1;
}
return 0;
}
/******************************************************************************/
/*
* Cancel the request timeout. Note may be called multiple times.
*/
void websTimeoutCancel(webs_t wp)
{
a_assert(websValid(wp));
if (wp->timeout >= 0) {
emfUnschedCallback(wp->timeout);
wp->timeout = -1;
}
}
/******************************************************************************/
/*
* Output a HTTP response back to the browser. If redirect is set to a
* URL, the browser will be sent to this location.
*/
void websResponse(webs_t wp, int code, char_t *message, char_t *redirect)
{
char_t *date;
a_assert(websValid(wp));
/*
* IE3.0 needs no Keep Alive for some return codes.
*/
wp->flags &= ~WEBS_KEEP_ALIVE;
/*
* Only output the header if a header has not already been output.
*/
if ( !(wp->flags & WEBS_HEADER_DONE)) {
wp->flags |= WEBS_HEADER_DONE;
/*
* Redirect behaves much better when sent with HTTP/1.0
*/
if (redirect != NULL) {
websWrite(wp, T("HTTP/1.0 %d %s\r\n"), code, websErrorMsg(code));
} else {
websWrite(wp, T("HTTP/1.1 %d %s\r\n"), code, websErrorMsg(code));
}
/*
* By license terms the following line of code must not be modified.
*/
websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
/*
* Timestamp/Date is usually the next to go
*/
if ((date = websGetDateString(NULL)) != NULL) {
websWrite(wp, T("Date: %s\r\n"), date);
bfree(B_L, date);
}
/*
* If authentication is required, send the auth header info
*/
if (code == 401) {
if (!(wp->flags & WEBS_AUTH_DIGEST)) {
websWrite(wp, T("WWW-Authenticate: Basic realm=\"%s\"\r\n"),
websGetRealm());
#ifdef DIGEST_ACCESS_SUPPORT
} else {
char_t *nonce, *opaque;
/* $$$ before... (note commas instead of semicolons...)
nonce = websCalcNonce(wp),
opaque = websCalcOpaque(wp),
$$$ after */
nonce = websCalcNonce(wp);
opaque = websCalcOpaque(wp);
/* ...$$$ end */
websWrite(wp,
T("WWW-Authenticate: Digest realm=\"%s\", domain=\"%s\",")
T("qop=\"%s\", nonce=\"%s\", opaque=\"%s\",")
T("algorithm=\"%s\", stale=\"%s\"\r\n"),
websGetRealm(),
websGetHostUrl(),
T("auth"),
nonce,
opaque, T("MD5"), T("FALSE"));
bfree(B_L, nonce);
bfree(B_L, opaque);
#endif
}
}
if (wp->flags & WEBS_KEEP_ALIVE) {
websWrite(wp, T("Connection: keep-alive\r\n"));
}
websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n"));
websWrite(wp, T("Content-Type: text/html\r\n"));
/*
* We don't do a string length here as the message may be multi-line.
* Ie. <CR><LF> will count as only one and we will have a content-length
* that is too short.
*
* websWrite(wp, T("Content-Length: %s\r\n"), message);
*/
if (redirect) {
websWrite(wp, T("Location: %s\r\n"), redirect);
}
websWrite(wp, T("\r\n"));
}
/*
* If the browser didn't do a HEAD only request, send the message as well.
*/
if ((wp->flags & WEBS_HEAD_REQUEST) == 0 && message && *message) {
websWrite(wp, T("%s\r\n"), message);
}
websDone(wp, code);
}
/******************************************************************************/
/*
* Redirect the user to another webs page
*/
void websRedirect(webs_t wp, char_t *url)
{
char_t *msgbuf, *urlbuf, *redirectFmt;
a_assert(websValid(wp));
a_assert(url);
websStats.redirects++;
msgbuf = urlbuf = NULL;
/*
* Some browsers require a http://host qualified URL for redirection
*/
if (gstrstr(url, T("http://")) == NULL) {
if (*url == '/') {
url++;
}
redirectFmt = T("http://%s/%s");
#ifdef WEBS_SSL_SUPPORT
if (wp->flags & WEBS_SECURE) {
redirectFmt = T("https://%s/%s");
}
#endif
fmtAlloc(&urlbuf, WEBS_MAX_URL + 80, redirectFmt,
websGetVar(wp, T("HTTP_HOST"), websHostUrl), url);
url = urlbuf;
}
/*
* Add human readable message for completeness. Should not be required.
*/
fmtAlloc(&msgbuf, WEBS_MAX_URL + 80,
T("<html><head></head><body>\r\n\
This document has moved to a new <a href=\"%s\">location</a>.\r\n\
Please update your documents to reflect the new location.\r\n\
</body></html>\r\n"), url);
websResponse(wp, 302, msgbuf, url);
bfreeSafe(B_L, msgbuf);
bfreeSafe(B_L, urlbuf);
}
/*
* websSafeUrl -- utility function to clean up URLs that will be printed by
* the websError() function, below. To prevent problems with the 'cross-site
* scripting exploit', where attackers request an URL containing embedded
* JavaScript code, we replace all '<' and '>' characters with HTML entities
* so that the user's browser will not interpret the URL as JavaScript.
*/
#define kLt '<'
#define kLessThan T("<")
#define kGt '>'
#define kGreaterThan T(">")
static int charCount(const char_t* str, char_t ch)
{
int count = 0;
char_t* p = (char_t*) str;
if (NULL == str)
{
return 0;
}
while (1)
{
p = gstrchr(p, ch);
if (NULL == p)
{
break;
}
/*
* increment the count, and begin looking at the next character
*/
++count;
++p;
}
return count;
}
static char_t* websSafeUrl(const char_t* url)
{
int ltCount = charCount(url, kLt);
int gtCount = charCount(url, kGt);
int safeLen = 0;
char_t* safeUrl = NULL;
char_t* src = NULL;
char_t* dest = NULL;
if (NULL != url)
{
safeLen = gstrlen(url);
if (ltCount == 0 && gtCount == 0)
{
safeUrl = bstrdup(B_L, (char_t*) url);
}
else
{
safeLen += (ltCount * 4);
safeLen += (gtCount * 4);
safeUrl = balloc(B_L, safeLen);
if (safeUrl != NULL)
{
src = (char_t*) url;
dest = safeUrl;
while (*src)
{
if (*src == kLt)
{
gstrcpy(dest, kLessThan);
dest += gstrlen(kLessThan);
}
else if (*src == kGt)
{
gstrcpy(dest, kGreaterThan);
dest += gstrlen(kGreaterThan);
}
else
{
*dest++ = *src;
}
++src;
}
/* don't forget to terminate the string...*/
*dest = '\0';
}
}
}
return safeUrl;
}
/******************************************************************************/
/*
* Output an error message and cleanup
*/
#ifdef qRichErrorPage
extern int dmfRichError(webs_t wp, int code, char_t* userMsg);
#endif
void websError(webs_t wp, int code, char_t *fmt, ...)
{
va_list args;
char_t *msg, *userMsg, *buf;
char_t* safeUrl = NULL;
char_t* safeMsg = NULL;
#ifdef qRichErrorPage
static int reEntry = 0;
int errorOk;
#endif
a_assert(websValid(wp));
a_assert(fmt);
websStats.errors++;
/* remove any dangerous characters in the url, and replace the string in the
* wp structure. The webs_t cleanup code will free this memory for us.
*/
safeUrl = websSafeUrl(wp->url);
bfreeSafe(B_L, wp->url);
wp->url = safeUrl;
va_start(args, fmt);
userMsg = NULL;
fmtValloc(&userMsg, WEBS_BUFSIZE, fmt, args);
va_end(args);
safeMsg = websSafeUrl(userMsg);
bfreeSafe(B_L, userMsg);
userMsg = safeMsg;
safeMsg = NULL;
#ifdef qRichErrorPage
if (!reEntry)
{
/*
* The dmfRichError function that we're about to call may very well call
* websError() as part of its work. If that happens, we do NOT want to
* get into a never-ending recursive call chain. When we get back here
* in a call from inside dmfRichError(), we check to see if we're
* already trying to call dmfRichError. If we are, we just revert to the
* old non-rich behavior and display a black on white error page.
*/
reEntry = 1;
errorOk = dmfRichError(wp, code, userMsg);
reEntry = 0;
if (errorOk)
{
bfreeSafe(B_L, userMsg);
return;
}
/* ...else we need to fall through and execute the simple error page. */
}
/* implicit else... */
#endif
msg = T("<html><head><title>Document Error: %s</title></head>\r\n\
<body><h2>Access Error: %s</h2>\r\n\
<p>%s</p></body></html>\r\n");
/*
* Ensure we have plenty of room
*/
buf = NULL;
fmtAlloc(&buf, WEBS_BUFSIZE, msg, websErrorMsg(code),
websErrorMsg(code), userMsg);
websResponse(wp, code, buf, NULL);
bfreeSafe(B_L, buf);
bfreeSafe(B_L, userMsg);
}
/******************************************************************************/
/*
* Return the error message for a given code
*/
/*static char_t *websErrorMsg(int code)*/
char_t *websErrorMsg(int code)
{
websErrorType *ep;
for (ep = websErrors; ep->code; ep++) {
if (code == ep->code) {
return ep->msg;
}
}
a_assert(0);
return T("");
}
/******************************************************************************/
/*
* Do formatted output to the browser. This is the public ASP and form
* write procedure.
*/
int websWrite(webs_t wp, char_t *fmt, ...)
{
va_list vargs;
char_t *buf;
int rc;
a_assert(websValid(wp));
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -