📄 webs.c
字号:
* 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 qRichErrorPageextern int dmfRichError(webs_t wp, int code, char_t* userMsg);#endifvoid 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)); va_start(vargs, fmt); buf = NULL; rc = 0; if (fmtValloc(&buf, WEBS_BUFSIZE, fmt, vargs) >= WEBS_BUFSIZE) { trace(0, T("webs: websWrite lost data, buffer overflow\n")); } va_end(vargs); a_assert(buf); if (buf) { rc = websWriteBlock(wp, buf, gstrlen(buf)); bfree(B_L, buf); } return rc;}/******************************************************************************//* * Write a block of data of length "nChars" to the user's browser. Public * write block procedure. If unicode is turned on this function expects * buf to be a unicode string and it converts it to ASCII before writing. * See websWriteDataNonBlock to always write binary or ASCII data with no * unicode conversion. This returns the number of char_t's processed. * It spins until nChars are flushed to the socket. For non-blocking * behavior, use websWriteDataNonBlock. */int websWriteBlock(webs_t wp, char_t *buf, int nChars){ int len, done; char *asciiBuf, *pBuf; a_assert(wp); a_assert(websValid(wp)); a_assert(buf); a_assert(nChars >= 0); done = len = 0;/* * ballocUniToAsc will convert Unicode to strings to Ascii. If Unicode is * not turned on then ballocUniToAsc will not do the conversion. */ pBuf = asciiBuf = ballocUniToAsc(buf, nChars); while (nChars > 0) { #ifdef WEBS_SSL_SUPPORT if (wp->flags & WEBS_SECURE) { if ((len = websSSLWrite(wp->wsp, pBuf, nChars)) < 0) { bfree(B_L, asciiBuf); return -1; } websSSLFlush(wp->wsp); } else { if ((len = socketWrite(wp->sid, pBuf, nChars)) < 0) { bfree(B_L, asciiBuf); return -1; } socketFlush(wp->sid); }#else /* ! WEBS_SSL_SUPPORT */ if ((len = socketWrite(wp->sid, pBuf, nChars)) < 0) { bfree(B_L, asciiBuf); return -1; } socketFlush(wp->sid);#endif /* WEBS_SSL_SUPPORT */ nChars -= len; pBuf += len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -