📄 webs.c
字号:
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; 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; nonce = websCalcNonce(wp), opaque = websCalcOpaque(wp), 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);}/******************************************************************************//* * Output an error message and cleanup */void websError(webs_t wp, int code, char_t *fmt, ...){ va_list args; char_t *msg, *userMsg, *buf; a_assert(websValid(wp)); a_assert(fmt); websStats.errors++; va_start(args, fmt); userMsg = NULL; fmtValloc(&userMsg, WEBS_BUFSIZE, fmt, args); va_end(args); msg = T("<html><head><title>Document Error: %s</title></head>\r\n\ <body><h2>Access Error: %s</h2>\r\n\ when trying to obtain <b>%s</b><br><p>%s</p></body></html>\r\n");/* * Ensure we have plenty of room */ buf = NULL; fmtAlloc(&buf, WEBS_BUFSIZE, msg, websErrorMsg(code), websErrorMsg(code), wp->url, 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){ 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; done += len; } bfree(B_L, asciiBuf); return done;}/******************************************************************************//* * Write a block of data of length "nChars" to the user's browser. Same as * websWriteBlock except that it expects straight ASCII or binary and does no * unicode conversion before writing the data. If the socket cannot hold all * the data, it will return the number of bytes flushed to the socket before * it would have blocked. This returns the number of chars processed or -1 * if socketWrite fails. */int websWriteDataNonBlock(webs_t wp, char *buf, int nChars){ int r; a_assert(wp); a_assert(websValid(wp)); a_assert(buf); a_assert(nChars >= 0);#ifdef WEBS_SSL_SUPPORT if (wp->flags & WEBS_SECURE) { r = websSSLWrite(wp->wsp, buf, nChars); websSSLFlush(wp->wsp); } else { r = socketWrite(wp->sid, buf, nChars); socketFlush(wp->sid); }#else r = socketWrite(wp->sid, buf, nChars); socketFlush(wp->sid);#endif return r;}/******************************************************************************//* * Decode a URL (or part thereof). Allows insitu decoding. */void websDecodeUrl(char_t *decoded, char_t *token, int len){ char_t *ip, *op; int num, i, c; a_assert(decoded); a_assert(token); op = decoded; for (ip = token; *ip && len > 0; ip++, op++) { if (*ip == '+') { *op = ' '; } else if (*ip == '%' && gisxdigit(ip[1]) && gisxdigit(ip[2])) {/* * Convert %nn to a single character */ ip++; for (i = 0, num = 0; i < 2; i++, ip++) { c = tolower(*ip); if (c >= 'a' && c <= 'f') { num = (num * 16) + 10 + c - 'a'; } else { num = (num * 16) + c - '0'; } } *op = (char_t) num; ip--; } else { *op = *ip; } len--; } *op = '\0';}/******************************************************************************/#if WEBS_LOG_SUPPORT/* * Output a log message */static void websLog(webs_t wp, int code){ char_t *buf; char *abuf; int len; a_assert(websValid(wp)); buf = NULL; fmtAlloc(&buf, WEBS_MAX_URL + 80, T("%d %s %d %d\n"), time(0), wp->url, code, wp->written); len = gstrlen(buf); abuf = ballocUniToAsc(buf, len+1); write(websLogFd, abuf, len); bfreeSafe(B_L, buf); bfreeSafe(B_L, abuf);}#endif /* WEBS_LOG_SUPPORT *//******************************************************************************//* * Request timeout. The timeout triggers if we have not read any data from * the users browser in the last WEBS_TIMEOUT period. If we have heard from * the browser, simply re-issue the timeout. */void websTimeout(void *arg, int id){ webs_t wp; int delay, tm; wp = (webs_t) arg; a_assert(websValid(wp)); tm = websGetTimeSinceMark(wp) * 1000; if (tm >= WEBS_TIMEOUT) { websStats.timeouts++; emfUnschedCallback(id);/* * Clear the timeout id */ wp->timeout = -1; websDone(wp, 404); } else { delay = WEBS_TIMEOUT - tm; a_assert(delay > 0); emfReschedCallback(id, delay); }}/******************************************************************************//* * Called when the request is done. */void websDone(webs_t wp, int code){ a_assert(websValid(wp));/* * Disable socket handler in case keep alive set. */ socketDeleteHandler(wp->sid); if (code != 200) { wp->flags &= ~WEBS_KEEP_ALIVE; }#if WEBS_PROXY_SUPPORT if (! (wp->flags & WEBS_LOCAL_PAGE)) { websStats.activeNetRequests--; }#endif#if WEBS_LOG_SUPPORT if (! (wp->flags & WEBS_REQUEST_DONE)) { websLog(wp, code); }#endif/* * Close any opened document by a handler */ websPageClose(wp);/* * Exit if secure. */#ifdef WEBS_SSL_SUPPORT if (wp->flags & WEBS_SECURE) { websTimeoutCancel(wp); websSSLFlush(wp->wsp); socketCloseConnection(wp->sid); websFree(wp); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -