⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 webs.c

📁 一个典型的用于嵌入式Linux环境的Webserver
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	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("&lt;")#define kGt '>'#define kGreaterThan T("&gt;")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 + -