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

📄 webs.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * webs.c -- GoAhead Embedded HTTP webs server * * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved. * * See the file "license.txt" for usage and redistribution license requirements * * $Id: webs.c,v 1.3.6.1 2006/02/08 16:15:09 joel Exp $ *//******************************** Description *********************************//* *	This module implements an embedded HTTP/1.1 web server. It supports *	loadable URL handlers that define the nature of URL processing performed. *//********************************* Includes ***********************************/#include	"wsIntrn.h"#ifdef DIGEST_ACCESS_SUPPORT#include	"websda.h"#endif/******************************** Global Data *********************************/websStatsType	websStats;				/* Web access stats */webs_t			*webs;					/* Open connection list head */sym_fd_t		websMime;				/* Set of mime types */int				websMax;				/* List size */int				websPort;				/* Listen port for server */char_t			websHost[64];			/* Host name for the server */char_t			websIpaddr[64];			/* IP address for the server */char_t			*websHostUrl = NULL;	/* URL to access server */char_t			*websIpaddrUrl = NULL;	/* URL to access server *//*********************************** Locals ***********************************//* *	Standard HTTP error codes */websErrorType websErrors[] = {	{ 200, T("Data follows") },	{ 204, T("No Content") },	{ 301, T("Redirect") },	{ 302, T("Redirect") },	{ 304, T("User local copy") },	{ 400, T("Page not found") },	{ 401, T("Unauthorized") },	{ 403, T("Forbidden") },	{ 404, T("Site or Page Not Found") },	{ 405, T("Access Denied") },	{ 500, T("Web Error") },	{ 501, T("Not Implemented") },	{ 503, T("Site Temporarily Unavailable. Try again.") },	{ 0, NULL }};#if WEBS_LOG_SUPPORTstatic char_t	websLogname[64] = T("log.txt");	/* Log filename */static int 		websLogFd;						/* Log file handle */#endifstatic int		websListenSock;					/* Listen socket */static char_t	websRealm[64] = T("GoAhead");	/* Realm name */static int		websOpenCount = 0;		/* count of apps using this module *//**************************** Forward Declarations ****************************/static char_t 	*websErrorMsg(int code);static int 		websGetInput(webs_t wp, char_t **ptext, int *nbytes);static int 		websParseFirst(webs_t wp, char_t *text);static void 	websParseRequest(webs_t wp);static void		websSocketEvent(int sid, int mask, int data);static int		websGetTimeSinceMark(webs_t wp);#if WEBS_LOG_SUPPORTstatic void 	websLog(webs_t wp, int code);#endif#if WEBS_IF_MODIFIED_SUPPORTstatic time_t	dateParse(time_t tip, char_t *cmd);#endif/*********************************** Code *************************************//* *	Open the GoAhead WebServer */int websOpenServer(int port, int retries){	websMimeType	*mt;	if (++websOpenCount != 1) {		return websPort;	}	a_assert(port > 0);	a_assert(retries >= 0);#if WEBS_PAGE_ROM	websRomOpen();#endif	webs = NULL;	websMax = 0;/* *	Create a mime type lookup table for quickly determining the content type */	websMime = symOpen(WEBS_SYM_INIT * 4);	a_assert(websMime >= 0);	for (mt = websMimeList; mt->type; mt++) {		symEnter(websMime, mt->ext, valueString(mt->type, 0), 0);	}/* *	Open the URL handler module. The caller should create the required *	URL handlers after calling this function. */	if (websUrlHandlerOpen() < 0) {		return -1;	}	websFormOpen();#if WEBS_LOG_SUPPORT/* *	Optional request log support */	websLogFd = gopen(websLogname, O_CREAT | O_TRUNC | O_APPEND | O_WRONLY, 		0666);	a_assert(websLogFd >= 0);#endif		return websOpenListen(port, retries);}/******************************************************************************//* *	Close the GoAhead WebServer */void websCloseServer(){	webs_t	wp;	int		wid;	if (--websOpenCount > 0) {		return;	}/* *	Close the listen handle first then all open connections. */	websCloseListen();/*  *	Close each open browser connection and free all resources */	for (wid = websMax; webs && wid >= 0; wid--) {		if ((wp = webs[wid]) == NULL) {			continue;		}		socketCloseConnection(wp->sid);		websFree(wp);	}#if WEBS_LOG_SUPPORT	if (websLogFd >= 0) {		close(websLogFd);		websLogFd = -1;	}#endif#if WEBS_PAGE_ROM	websRomClose();#endif	symClose(websMime);	websFormClose();	websUrlHandlerClose();}/******************************************************************************//* *	Open the GoAhead WebServer listen port */int websOpenListen(int port, int retries){	int		i, orig;	a_assert(port > 0);	a_assert(retries >= 0);	orig = port;/* *	Open the webs webs listen port. If we fail, try the next port. */	for (i = 0; i <= retries; i++) {		websListenSock = socketOpenConnection(NULL, port, websAccept, 0);		if (websListenSock >= 0) {			break;		}		port++;	}	if (i > retries) {		error(E_L, E_USER, T("Couldn't open a socket on ports %d - %d"),			orig, port - 1);		return -1;	} /* *	Determine the full URL address to access the home page for this web server */	websPort = port;	bfreeSafe(B_L, websHostUrl);	bfreeSafe(B_L, websIpaddrUrl);	websIpaddrUrl = websHostUrl = NULL;	if (port == 80) {		websHostUrl = bstrdup(B_L, websHost);		websIpaddrUrl = bstrdup(B_L, websIpaddr);	} else {		fmtAlloc(&websHostUrl, WEBS_MAX_URL + 80, T("%s:%d"), websHost, port);		fmtAlloc(&websIpaddrUrl, WEBS_MAX_URL + 80, T("%s:%d"), 			websIpaddr, port);	}	trace(0, T("webs: Listening for HTTP requests at address %s\n"),		websIpaddrUrl);	return port;}/******************************************************************************//* *	Close webs listen port */void websCloseListen(){	if (websListenSock >= 0) {		socketCloseConnection(websListenSock);		websListenSock = -1;	}	bfreeSafe(B_L, websHostUrl);	bfreeSafe(B_L, websIpaddrUrl);	websIpaddrUrl = websHostUrl = NULL;}/******************************************************************************//* *	Accept a connection */int websAccept(int sid, char *ipaddr, int port, int listenSid){	webs_t	wp;	int		wid;	a_assert(ipaddr && *ipaddr);	a_assert(sid >= 0);	a_assert(port >= 0);/* *	Allocate a new handle for this accepted connection. This will allocate *	a webs_t structure in the webs[] list */	if ((wid = websAlloc(sid)) < 0) {		return -1;	}	wp = webs[wid];	a_assert(wp);	wp->listenSid = listenSid;	ascToUni(wp->ipaddr, ipaddr, sizeof(wp->ipaddr));/* *	Check if this is a request from a browser on this system. This is useful *	to know for permitting administrative operations only for local access */	if (gstrcmp(wp->ipaddr, T("127.0.0.1")) == 0 || 			gstrcmp(wp->ipaddr, websIpaddr) == 0 || 			gstrcmp(wp->ipaddr, websHost) == 0) {		wp->flags |= WEBS_LOCAL_REQUEST;	}/* *	Arrange for websSocketEvent to be called when read data is available */	socketCreateHandler(sid, SOCKET_READABLE, websSocketEvent, (int) wp);/* *	Arrange for a timeout to kill hung requests */	wp->timeout = emfSchedCallback(WEBS_TIMEOUT, websTimeout, (void *) wp);	trace(8, T("webs: accept request\n"));	return 0;}/******************************************************************************//* *	The webs socket handler.  Called in response to I/O. We just pass control *	to the relevant read or write handler. A pointer to the webs structure *	is passed as an (int) in iwp. */static void websSocketEvent(int sid, int mask, int iwp){	webs_t	wp;	wp = (webs_t) iwp;	a_assert(wp);	if (! websValid(wp)) {		return;	}	if (mask & SOCKET_READABLE) {		websReadEvent(wp);	} 	if (mask & SOCKET_WRITABLE) {		if (wp->writeSocket) {			(*wp->writeSocket)(wp);		}	} }/******************************************************************************//* *	The webs read handler. This is the primary read event loop. It uses a *	state machine to track progress while parsing the HTTP request.  *	Note: we never block as the socket is always in non-blocking mode. */void websReadEvent(webs_t wp){	char_t 	*text;	int		rc, nbytes, len, done, fd;	a_assert(wp);	a_assert(websValid(wp));	websMarkTime(wp);/* *	Read as many lines as possible. socketGets is called to read the header *	and socketRead is called to read posted data. */	text = NULL;	fd = -1;	for (done = 0; !done; ) {		if (text) {			bfree(B_L, text);			text = NULL;		}/* *		Get more input into "text". Returns 0, if more data is needed *		to continue, -1 if finished with the request, or 1 if all  *		required data is available for current state. */		while ((rc = websGetInput(wp, &text, &nbytes)) == 0) {			;		}/* *		websGetInput returns -1 if it finishes with the request */		if (rc < 0) {			break;		}/* *		This is the state machine for the web server.  */		switch(wp->state) {		case WEBS_BEGIN:/* *			Parse the first line of the Http header */			if (websParseFirst(wp, text) < 0) {				done++;				break;			}			wp->state = WEBS_HEADER;			break;				case WEBS_HEADER:/* *			Store more of the HTTP header. As we are doing line reads, we *			need to separate the lines with '\n' */			if (ringqLen(&wp->header) > 0) {				ringqPutStr(&wp->header, T("\n"));			}			ringqPutStr(&wp->header, text);			break;		case WEBS_POST_CLEN:/* *			POST request with content specified by a content length. *			If this is a CGI request, write the data to the cgi stdin. *			socketGets was used to get the data and it strips \n's so *			add them back in here. */#ifndef __NO_CGI_BIN			if (wp->flags & WEBS_CGI_REQUEST) {				if (fd == -1) {					fd = gopen(wp->cgiStdin, O_CREAT | O_WRONLY | O_BINARY,						0666);				}				gwrite(fd, text, gstrlen(text));				gwrite(fd, T("\n"), sizeof(char_t));				nbytes += 1;			} else #endif			if (wp->query) {				if (wp->query[0] && !(wp->flags & WEBS_POST_DATA)) {/* *					Special case where the POST request also had query data  *					specified in the URL, ie. url?query_data. In this case *					the URL query data is separated by a '&' from the posted *					query data. */					len = gstrlen(wp->query);					wp->query = brealloc(B_L, wp->query, (len + gstrlen(text) +						2) * sizeof(char_t));					wp->query[len++] = '&';					gstrcpy(&wp->query[len], text);				} else {/* *					The existing query data came from the POST request so just *					append it. */					len = gstrlen(wp->query);					wp->query = brealloc(B_L, wp->query, (len +	gstrlen(text) +						1) * sizeof(char_t));					if (wp->query) {						gstrcpy(&wp->query[len], text);					}				}			} else {				wp->query = bstrdup(B_L, text);			}/* *			Calculate how much more post data is to be read. */			wp->flags |= WEBS_POST_DATA;			wp->clen -= nbytes;			if (wp->clen > 0) {				if (nbytes > 0) {					break;				}				done++;				break;			}/* *			No more data so process the request */			websUrlHandlerRequest(wp);			done++;			break;		case WEBS_POST:/* *			POST without content-length specification *			If this is a CGI request, write the data to the cgi stdin. *			socketGets was used to get the data and it strips \n's so *			add them back in here. */#ifndef __NO_CGI_BIN			if (wp->flags & WEBS_CGI_REQUEST) {				if (fd == -1) {					fd = gopen(wp->cgiStdin, O_CREAT | O_WRONLY | O_BINARY,						0666);				}				gwrite(fd, text, gstrlen(text));				gwrite(fd, T("\n"), sizeof(char_t));			} else#endif			if (wp->query && *wp->query && !(wp->flags & WEBS_POST_DATA)) {				len = gstrlen(wp->query);				wp->query = brealloc(B_L, wp->query, (len + gstrlen(text) +					2) * sizeof(char_t));				if (wp->query) {					wp->query[len++] = '&';					gstrcpy(&wp->query[len], text);				}			} else {				wp->query = bstrdup(B_L, text);			}			wp->flags |= WEBS_POST_DATA;			done++;			break;		default:			websError(wp, 404, T("Bad state"));			done++;			break;		}	}	if (fd != -1) {		fd = gclose (fd);	}	if (text) {		bfree(B_L, text);	}}/******************************************************************************//* *	Get input from the browser. Return TRUE (!0) if the request has been  *	handled. Return -1 on errors or if the request has been processed,  *	1 if input read, and 0 to instruct the caller to call again for more input. * *	Note: socketRead will Return the number of bytes read if successful. This *	may be less than the requested "bufsize" and may be zero. It returns -1 for *	errors. It returns 0 for EOF. Otherwise it returns the number of bytes  *	read. Since this may be zero, callers should use socketEof() to  *	distinguish between this and EOF. */static int websGetInput(webs_t wp, char_t **ptext, int *pnbytes) {	char_t	*text;	char	buf[WEBS_SOCKET_BUFSIZ+1];	int		nbytes, len, clen;	a_assert(websValid(wp));	a_assert(ptext);	a_assert(pnbytes);	*ptext = text = NULL;	*pnbytes = 0;/* *	If this request is a POST with a content length, we know the number *	of bytes to read so we use socketRead(). */	if (wp->state == WEBS_POST_CLEN) {		len = (wp->clen > WEBS_SOCKET_BUFSIZ) ? WEBS_SOCKET_BUFSIZ : wp->clen;	} else {		len = 0;	}	if (len > 0) {#ifdef WEBS_SSL_SUPPORT		if (wp->flags & WEBS_SECURE) {			nbytes = websSSLRead(wp->wsp, buf, len);		} else {			nbytes = socketRead(wp->sid, buf, len);		}#else		nbytes = socketRead(wp->sid, buf, len);#endif		if (nbytes < 0) {						/* Error */			websDone(wp, 0);			return -1;		}  else if (nbytes == 0) {				/* EOF or No data available */	                /* Bugfix for POST DoS attack with invalid content length */                  	if (socketEof(wp->sid)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -