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

📄 http.c

📁 小型的web服务器源码
💻 C
📖 第 1 页 / 共 3 页
字号:
///////////////////////////////////////////////////////////////////////////////// http.c//// MiniWeb - mini webserver implementation///////////////////////////////////////////////////////////////////////////////#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include "httppil.h"#include "httpapi.h"#include "httpint.h"////////////////////////////////////////////////////////////////////////////// global variables////////////////////////////////////////////////////////////////////////////// default pageschar g_chDefaultPage[]="index.htm";char g_chPasswordPage[]="password.htm";// post and substitution callbacksPFNSUBSTCALLBACK g_pfnSubst=NULL;UrlProcParam *g_urlProcParams=NULL;int g_urlProcCount=0;#ifdef HTTPPOSTextern PFNFILEUPLOADCALLBACK g_pfnFileUpload;extern PFNPOSTCALLBACK g_pfnPost;#endifchar *pchFileTypeTable[]={	HTTPTYPE_HTML,HTTPTYPE_TEXT,HTTPTYPE_GIF,HTTPTYPE_JPEG,	HTTPTYPE_PNG,HTTPTYPE_JS,HTTPTYPE_CSS,HTTPTYPE_SWF,HTTPTYPE_OCTET};	int   g_bKillWebserver; int   g_bWebserverRunning=FALSE; #ifdef HTTPAUTHextern DWORD g_dwAuthenticatedNode;extern DWORD g_dwAuthenticationExpirationTime;extern OCTET g_bAuthenticationOn;#endif#ifndef NOTHREADpthread_t g_tidHttpThread;#endifchar g_nSocketRcvBuf = 0;char *g_webRoot;HttpStats g_stats;////////////////////////////////////////////////////////////////////////////// API calls///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// mwSetRcvBufSize. Change the TCP windows size of acceped sockets///////////////////////////////////////////////////////////////////////int mwSetRcvBufSize(WORD wSize){  g_nSocketRcvBuf = (char)wSize;  return wSize;}HttpStats* mwGetHttpStats(){  return &g_stats;}////////////////////////////////////////////////////////////////////////////// mwServerStart// Start the webserver////////////////////////////////////////////////////////////////////////////int mwServerStart(httpParam *param){	SOCKET listenSocket;	if (!g_bWebserverRunning) {#ifdef WIN32#ifndef NOTHREAD		DWORD dwId;#endif#endif		if (!initSocket()) {			DEBUG("Error initializing Winsock\n");			return 0;		}		g_bKillWebserver=FALSE;		g_bWebserverRunning=TRUE;		memset(&g_stats,0,sizeof(g_stats));#ifdef HTTPPOST		if (g_pfnPost==NULL || g_pfnFileUpload==NULL) return 0;#endif		listenSocket=_mwStartListening(param);		if (!listenSocket) return 0;		if (g_urlProcCount>0) {			DEBUG("Number of URL preprocessors: %d\n",g_urlProcCount);		}		if (param->webPath) {			g_webRoot=malloc(strlen(param->webPath)+1);			strcpy(g_webRoot,param->webPath);			DEBUG("Web document root: %s\n",g_webRoot);		} else {			g_webRoot=NULL;		}		g_stats.startTime=gettime();#ifndef NOTHREAD#ifndef WIN32		pthread_create(&g_tidHttpThread,NULL,_mwHttpThread, (void*)listenSocket);#else		g_tidHttpThread=CreateThread(0,0,(LPTHREAD_START_ROUTINE)_mwHttpThread,(void*)listenSocket,0,&dwId);#endif#else		_mwHttpThread(listenSocket);#endif	} else {		DEBUG("Error: Webserver thread already running\n");	}  	return g_bWebserverRunning;}////////////////////////////////////////////////////////////////////////////// mwServerShutdown// Shutdown the webserver////////////////////////////////////////////////////////////////////////////int mwServerShutdown(){  DEBUG("Shutting down web server thread\n");    // signal webserver thread to quit  g_bKillWebserver=TRUE;    // and wait for thread to exit#ifndef NOTHREAD#ifndef WIN32  pthread_join(g_tidHttpThread,0);#else  WaitForSingleObject(g_tidHttpThread,3);  WSACleanup( );#endif#endif  if (g_webRoot) free(g_webRoot);  if (g_urlProcParams) free(g_urlProcParams);  DEBUG("Webserver shutdown complete\n");    return 0;}////////////////////////////////////////////////////////////////////////////// HttpUrlRegister// Register a URL preprocessing callback////////////////////////////////////////////////////////////////////////////int mwUrlProcessorRegister(char *pchUrlBegin, PFNURLCALLBACK pfnCallback) {	int i;	for (i=0;i<g_urlProcCount;i++) {		if (!strcmp(pchUrlBegin,(g_urlProcParams+i)->pchUrlPrefix)) {			DEBUG("The preprocessor for '%s' is already registered\n",pchUrlBegin);			return -1;		}	}	g_urlProcCount++;	g_urlProcParams=(UrlProcParam*)realloc(g_urlProcParams,g_urlProcCount*sizeof(UrlProcParam));	(g_urlProcParams+g_urlProcCount-1)->pchUrlPrefix=pchUrlBegin;	(g_urlProcParams+g_urlProcCount-1)->pfnUrlProcCallback=pfnCallback;	return g_urlProcCount;}////////////////////////////////////////////////////////////////////////////// mwSubstRegister// Register a substitution callback////////////////////////////////////////////////////////////////////////////PFNSUBSTCALLBACK mwSubstRegister(PFNSUBSTCALLBACK pfnSubstCb) {  PFNSUBSTCALLBACK pfnSubstPrevCb=g_pfnSubst;  // save new CB  if (pfnSubstCb==NULL) return NULL;  g_pfnSubst=pfnSubstCb;  // return previous CB (so app can chain onto it)  return pfnSubstPrevCb;}////////////////////////////////////////////////////////////////////////////// Internal (private) helper functions////////////////////////////////////////////////////////////////////////////SOCKET _mwStartListening(httpParam *param){	SOCKET listenSocket;	// open listening socket	int iRc;    // create a new socket    listenSocket=socket(AF_INET,SOCK_STREAM,0);    if (listenSocket<0) return 0;    // allow reuse of port number    {      int iOptVal=1;      iRc=setsockopt(listenSocket,SOL_SOCKET,SO_REUSEADDR,                     (char*)&iOptVal,sizeof(iOptVal));      if (iRc<0) return 0;    }    // bind it to the http port    {      struct sockaddr_in sinAddress;      memset(&sinAddress,0,sizeof(struct sockaddr_in));      sinAddress.sin_family=AF_INET;      sinAddress.sin_addr.s_addr=htonl(INADDR_ANY);      sinAddress.sin_port=htons(param->httpPort); // http port      iRc=bind(listenSocket,(struct sockaddr*)&sinAddress,               sizeof(struct sockaddr_in));	  if (iRc<0) {		DEBUG("Error binding on port %d\n",param->httpPort);		return 0;	  }    }#ifndef WIN32    // set to non-blocking to avoid lockout issue (see Section 15.6    // in Unix network programming book)    {      int iSockFlags;      iSockFlags = fcntl(listenSocket, F_GETFL, 0);      iSockFlags |= O_NONBLOCK;      iRc = fcntl(listenSocket, F_SETFL, iSockFlags);    }#endif    // listen on the socket for incoming calls	if (listen(listenSocket,HTTPMAXPENDINGCON-1)) {		DEBUG("Unable to listen on socket %d\n",listenSocket);		return 0;	}    DEBUG("Http listen socket %d opened\n",listenSocket);	return listenSocket;}////////////////////////////////////////////////////////////////////////////// _mwHttpThread// Webserver independant processing thread. Handles all connections////////////////////////////////////////////////////////////////////////////void* _mwHttpThread(SOCKET listenSocket){ 	HttpSocket hsSockets[HTTPMAXPENDINGCON];	int iMaxSocket;    struct timeval tvSelectWait;	// clear pending sockets array	memset(hsSockets, 0, sizeof(hsSockets));    // and add to socket list (always first entry)    hsSockets[0].hssState=HTTPSOCKETSTATE_LISTENING;    hsSockets[0].iSocket=listenSocket;  // main processing loop  while (!g_bKillWebserver) {	int lCurrentTime;    int i;    int iRc;    SOCKET iSelectMaxFds=(SOCKET)0;    fd_set fdsSelectRead;    fd_set fdsSelectWrite;    // clear descriptor sets    FD_ZERO(&fdsSelectRead);    FD_ZERO(&fdsSelectWrite);    // build descriptor sets    for (i=0;i<HTTPMAXPENDINGCON;i++) {      if (hsSockets[i].hssState!=HTTPSOCKETSTATE_NOTINUSE) {        SOCKET iSocket;        // get socket fd        iSocket=hsSockets[i].iSocket;		iMaxSocket=i;        switch(hsSockets[i].hssState) {        case HTTPSOCKETSTATE_LISTENING:        case HTTPSOCKETSTATE_RECEIVING:          // add to read descriptor set          FD_SET(iSocket,&fdsSelectRead);          break;        case HTTPSOCKETSTATE_SENDING:          // add to write descriptor set          FD_SET(iSocket,&fdsSelectWrite);          break;        }                // check if new max socket        if (iSocket>iSelectMaxFds) {          iSelectMaxFds=iSocket;        }      }    }        // initialize select delay	tvSelectWait.tv_sec = 10;	tvSelectWait.tv_usec = 0; // note: using timeval here -> usec not nsec    // and check sockets (may take a while!)    iRc=select(iSelectMaxFds+1, &fdsSelectRead, &fdsSelectWrite,               NULL, &tvSelectWait);    //get current time	lCurrentTime=gettime();  	for (i=1;i<=iMaxSocket;i++) {		// check expiration timer (for non-listening, in-use sockets)		if (hsSockets[i].hssState!=HTTPSOCKETSTATE_NOTINUSE && 				lCurrentTime > hsSockets[i].lExpirationTime) {			DEBUG("Http socket timeout expired\n");			g_stats.timeOutCount++;			// close connection			_mwCloseSocket(&hsSockets[i]);			continue;		}	}    if (iRc>0) {		// check if any socket to accept		if (FD_ISSET(hsSockets[0].iSocket, &fdsSelectRead)) {			int j;			// find an empty slot			for (j=0;j<HTTPMAXPENDINGCON;j++) {				if (hsSockets[j].hssState==HTTPSOCKETSTATE_NOTINUSE) {					// accept the socket					_mwAcceptSocket(&hsSockets[0], &hsSockets[j]);					break;				}			}		}		// check which sockets are read/write able		for (i=1;i<=iMaxSocket;i++) {			if (hsSockets[i].hssState!=HTTPSOCKETSTATE_NOTINUSE) {				SOCKET iSocket;				BOOL bRead;				BOOL bWrite;	          				// get socket fd				iSocket=hsSockets[i].iSocket;	          				// get read/write status for socket				bRead=FD_ISSET(iSocket, &fdsSelectRead);				bWrite=FD_ISSET(iSocket, &fdsSelectWrite);	          				// if readable or writeable then process				if (bRead || bWrite) {					// process the socket					_mwProcessSocket(&hsSockets[i], bRead, bWrite);				}			}		}      }  }    {    // Close any open sockets    int i;    for (i=0;i<HTTPMAXPENDINGCON;i++) {      _mwCloseSocket(&hsSockets[i]);    }  }        // clear state vars  g_bKillWebserver=FALSE;  g_bWebserverRunning=FALSE;    return NULL;} // end of _mwHttpThread////////////////////////////////////////////////////////////////////////////// _mwAcceptSocket// Accept an incoming connection////////////////////////////////////////////////////////////////////////////void _mwAcceptSocket(HttpSocket* phsListenSocket, HttpSocket* phsNewSocket){    SOCKET iSocket;    DEBUG("Accpeting socket %d\n",phsListenSocket->iSocket);    iSocket=accept(phsListenSocket->iSocket, NULL, NULL);    if (iSocket<=0) {	DEBUG("Error accepting socket\n");    } else {      DEBUG("Http connection on socket %d\n",iSocket);#ifndef WIN32      // set to non-blocking to stop sends from locking up thread      {        int iRc;        int iSockFlags;        iSockFlags = fcntl(iSocket, F_GETFL, 0);        //ASSERT(iSockFlags >= 0);        iSockFlags |= O_NONBLOCK;        iRc = fcntl(iSocket, F_SETFL, iSockFlags);        //ASSERT(iRc >= 0);      }#endif      if (g_nSocketRcvBuf != 0) {        setsockopt(iSocket, SOL_SOCKET, SO_RCVBUF, &g_nSocketRcvBuf, sizeof(g_nSocketRcvBuf));      }      // allocate buffer 	  phsNewSocket->pucData=malloc(HTTPMAXFILECHUNK);	  phsNewSocket->iBufferLength=HTTPMAXFILECHUNK;      phsNewSocket->iSocket=iSocket;      phsNewSocket->hssState=HTTPSOCKETSTATE_RECEIVING;      // set expiration timer      phsNewSocket->lExpirationTime=gettime()+HTTPEXPIRATIONTIME;	  g_stats.reqCount++;    }} // end of _mwAcceptSocket////////////////////////////////////////////////////////////////////////////// _mwProcessSocket// Process a socket (read or write)////////////////////////////////////////////////////////////////////////////void _mwProcessSocket(HttpSocket* phsSocket, BOOL bRead, BOOL bWrite){  DEBUG("socket %d bWrite=%s, bRead=%s\n",                phsSocket->iSocket,bWrite?"yes":"no",bRead?"yes":"no");  // ready to write  if (bWrite && phsSocket->hssState==HTTPSOCKETSTATE_SENDING) {	switch (phsSocket->hcsSource) {	case HTTPSRC_DEFAULT:	case HTTPSRC_FILE:		// write next chunk of data		if (phsSocket->bRawDataSend) {			_mwSendRawDataChunk(phsSocket);		} else {			_mwSendFileChunk(phsSocket);		}		break;	case HTTPSRC_MEM:		_mwSendMemoryChunk(phsSocket);		break;

⌨️ 快捷键说明

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