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

📄 http.c

📁 A small implementation of web server
💻 C
📖 第 1 页 / 共 3 页
字号:
		for (p = hfp.cFilePath; *p; p++);
		
		//requesting for directory, first try opening default pages
		*(p++)=SLASH;
		for (i=0; defaultPages[i]; i++) {
			strcpy(p,defaultPages[i]);
			phsSocket->fd=open(hfp.cFilePath,OPEN_FLAG);
			if (phsSocket->fd>=0) break;
		}

		if (phsSocket->fd < 0 && (hp->flags & FLAG_DIR_LISTING)) {
			SETFLAG(phsSocket,FLAG_DATA_RAW);
			if (!hfp.fTailSlash) {
				p=phsSocket->request.pucPath;
				while(*p) p++;				//seek to the end of the string
				SETWORD(p,DEFWORD('/',0));	//add a tailing slash
				while(--p>(char*)phsSocket->request.pucPath) {
					if (*p=='/') {
						p++;
						break;
					}
				}
				_mwRedirect(phsSocket,p);
			} else {
				*(p-1)=0;
				_mwListDirectory(phsSocket,hfp.cFilePath);
			}
			return _mwStartSendRawData(hp, phsSocket);
		}
		phsSocket->response.fileType = HTTPFILETYPE_HTML;
	}
	phsSocket->response.iContentLength = !fstat(phsSocket->fd, &st) ? st.st_size - phsSocket->request.iStartByte : 0;
	if (phsSocket->response.iContentLength <= 0) {
		phsSocket->request.iStartByte = 0;
	}
	if (phsSocket->request.iStartByte) {
		lseek(phsSocket->fd, phsSocket->request.iStartByte, SEEK_SET);
	}
	if (!phsSocket->response.fileType && hfp.pchExt) {
		phsSocket->response.fileType=_mwGetContentType(hfp.pchExt);
	}
	
	// mark if substitution needed
	if (hp->pfnSubst && (phsSocket->response.fileType==HTTPFILETYPE_HTML ||phsSocket->response.fileType==HTTPFILETYPE_JS)) {
		SETFLAG(phsSocket,FLAG_SUBST);
	}

	SYSLOG(LOG_INFO,"File/requested size: %d/%d\n",st.st_size,phsSocket->response.iContentLength);

	// build http header
	phsSocket->iDataLength=_mwBuildHttpHeader(
		hp,
		phsSocket,
		st.st_mtime,
		phsSocket->pucData);

	phsSocket->response.iSentBytes=-phsSocket->iDataLength;
	hp->stats.fileSentCount++;
	return 0;
} // end of _mwStartSendFile

////////////////////////////////////////////////////////////////////////////
// _mwSendFileChunk
// Send a chunk of a file
////////////////////////////////////////////////////////////////////////////
int _mwSendFileChunk(HttpParam *hp, HttpSocket* phsSocket)
{
	int iBytesWritten;
	int iBytesRead;

	// send a chunk of data
	iBytesWritten=send(phsSocket->socket, phsSocket->pucData,phsSocket->iDataLength, 0);
	if (iBytesWritten<=0) {
		// close connection
		DBG("[%d] error sending data\n", phsSocket->socket);
		SETFLAG(phsSocket,FLAG_CONN_CLOSE);
		close(phsSocket->fd);
		phsSocket->fd = 0;
		return -1;
	}
	phsSocket->response.iSentBytes+=iBytesWritten;
	phsSocket->pucData+=iBytesWritten;
	phsSocket->iDataLength-=iBytesWritten;
	SYSLOG(LOG_INFO,"[%d] sent %d bytes of %d\n",phsSocket->socket,phsSocket->response.iSentBytes,phsSocket->response.iContentLength);
	// if only partial data sent just return wait the remaining data to be sent next time
	if (phsSocket->iDataLength>0)	return 0;

	// used all buffered data - load next chunk of file
	phsSocket->pucData=phsSocket->buffer;
	iBytesRead=read(phsSocket->fd,phsSocket->buffer,HTTP_BUFFER_SIZE);
	if (iBytesRead<=0) {
		// finished with a file
		int iRemainBytes=phsSocket->response.iContentLength-phsSocket->response.iSentBytes;
		DBG("[%d] EOF reached\n",phsSocket->socket);
		if (iRemainBytes>0) {
			if (iRemainBytes>HTTP_BUFFER_SIZE) iRemainBytes=HTTP_BUFFER_SIZE;
			DBG("Sending %d padding bytes\n",iRemainBytes);
			memset(phsSocket->buffer,0,iRemainBytes);
			phsSocket->iDataLength=iRemainBytes;
			return 0;
		} else {
			DBG("Closing file (fd=%d)\n",phsSocket->fd);
			hp->stats.fileSentBytes+=phsSocket->response.iSentBytes;
			close(phsSocket->fd);
			phsSocket->fd = 0;
			return 1;
		}
	}
	if (ISFLAGSET(phsSocket,FLAG_SUBST)) {
		int iBytesUsed;
		// substituted file - read smaller chunk
		phsSocket->iDataLength=_mwSubstVariables(hp, phsSocket->buffer,iBytesRead,&iBytesUsed);
		if (iBytesUsed<iBytesRead) {
			lseek(phsSocket->fd,iBytesUsed-iBytesRead,SEEK_CUR);
		}
	} else {
		phsSocket->iDataLength=iBytesRead;
	}
	return 0;
} // end of _mwSendFileChunk

////////////////////////////////////////////////////////////////////////////
// _mwStartSendRawData
// Start sending raw data blocks
////////////////////////////////////////////////////////////////////////////
int _mwStartSendRawData(HttpParam *hp, HttpSocket* phsSocket)
{
	unsigned char header[HTTP200_HDR_EST_SIZE];
	int offset=0,hdrsize,bytes;
	hdrsize=_mwBuildHttpHeader(hp, phsSocket,time(NULL),header);
	// send http header
	do {
		bytes=send(phsSocket->socket, header+offset,hdrsize-offset,0);
		if (bytes<=0) break;
		offset+=bytes;
	} while (offset<hdrsize);
	if (bytes<=0) {
		// failed to send header (socket may have been closed by peer)
		SYSLOG(LOG_INFO,"Failed to send header\n");
		return -1;
	}
	return 0;
}

////////////////////////////////////////////////////////////////////////////
// _mwSendRawDataChunk
// Send a chunk of a raw data block
////////////////////////////////////////////////////////////////////////////
int _mwSendRawDataChunk(HttpParam *hp, HttpSocket* phsSocket)
{
	int  iBytesWritten;

    // send a chunk of data
	if (phsSocket->iDataLength==0) {
		if (ISFLAGSET(phsSocket,FLAG_DATA_STREAM) && phsSocket->ptr) {
			//FIXME: further implementation of FLAG_DATA_STREAM case
		}
		hp->stats.fileSentBytes+=phsSocket->response.iSentBytes;
		return 1;
	}
	iBytesWritten=(int)send(phsSocket->socket, phsSocket->pucData,phsSocket->iDataLength, 0);
    if (iBytesWritten<=0) {
		// failure - close connection
		SYSLOG(LOG_INFO,"Connection closed\n");
		SETFLAG(phsSocket,FLAG_CONN_CLOSE);
		return -1;
    } else {
		SYSLOG(LOG_INFO,"[%d] sent %d bytes of raw data\n",phsSocket->socket,iBytesWritten);
		phsSocket->response.iSentBytes+=iBytesWritten;
		phsSocket->pucData+=iBytesWritten;
		phsSocket->iDataLength-=iBytesWritten;
	}
	if (phsSocket->iDataLength<=0 && 
			ISFLAGSET(phsSocket,FLAG_DATA_STREAM) &&
			phsSocket->response.iSentBytes<phsSocket->response.iContentLength) {
		//load next chuck of raw data
		UrlHandlerParam uhp;
		memset(&uhp,0,sizeof(UrlHandlerParam));
		uhp.hp=hp;
		uhp.iContentBytes=phsSocket->response.iContentLength;
		uhp.iSentBytes=phsSocket->response.iSentBytes;
		uhp.pucBuffer=phsSocket->buffer;
		uhp.iDataBytes=HTTP_BUFFER_SIZE;
		if ((*(PFNURLCALLBACK)(phsSocket->ptr))(&uhp)) {
			phsSocket->pucData=uhp.pucBuffer;
			phsSocket->iDataLength=uhp.iDataBytes;
		}
	}
	return 0;
} // end of _mwSendRawDataChunk

////////////////////////////////////////////////////////////////////////////
// _mwRedirect
// Setup for redirect to another file
////////////////////////////////////////////////////////////////////////////
void _mwRedirect(HttpSocket* phsSocket, char* pchPath)
{
	char* path;
	// raw (not file) data send mode
	SETFLAG(phsSocket,FLAG_DATA_RAW);

	// messages is HTML
	phsSocket->response.fileType=HTTPFILETYPE_HTML;

	// build redirect message
	SYSLOG(LOG_INFO,"[%d] Http redirection to %s\n",phsSocket->socket,pchPath);
	path = (pchPath == phsSocket->pucData) ? strdup(pchPath) : pchPath;
	phsSocket->iDataLength=sprintf(phsSocket->pucData,HTTPBODY_REDIRECT,path);
	phsSocket->response.iContentLength=phsSocket->iDataLength;
	if (path != pchPath) free(path);
} // end of _mwRedirect

////////////////////////////////////////////////////////////////////////////
// _mwSubstVariables
// Perform substitution of variables in a buffer
// returns new length
////////////////////////////////////////////////////////////////////////////
int _mwSubstVariables(HttpParam* hp, char* pchData, int iLength, int* piBytesUsed)
{
	int lastpos,pos=0,used=0;
	SubstParam sp;
	int iValueBytes;
    DBG("_SubstVariables input len %d\n",iLength);
	iLength--;
	for(;;) {
		lastpos=pos;
		for (; pos<iLength && *(WORD*)(pchData+pos)!=HTTP_SUBST_PATTERN; pos++);
		used+=(pos-lastpos);
		if (pos==iLength) {
			*piBytesUsed=used+1;
			return iLength+1;
		}
		lastpos=pos;
		for (pos=pos+2; pos<iLength && *(WORD*)(pchData+pos)!=HTTP_SUBST_PATTERN; pos++);
		if (pos==iLength) {
			*piBytesUsed=used;
			return lastpos;
		}
		pos+=2;
		used+=pos-lastpos;
		pchData[pos-2]=0;
		sp.pchParamName=pchData+lastpos+2;
		sp.iMaxValueBytes=pos-lastpos;
		sp.pchParamValue=pchData+lastpos;
		iValueBytes=hp->pfnSubst(&sp);
		if (iValueBytes>=0) {
			if (iValueBytes>sp.iMaxValueBytes) iValueBytes=sp.iMaxValueBytes;
			memmove(pchData+lastpos+iValueBytes,pchData+pos,iLength-pos);
			iLength=iLength+iValueBytes-(pos-lastpos);
			pos=lastpos+iValueBytes;
		} else {
			DBG("No matched variable for %s\n",sp.pchParamName);
			pchData[pos-2]='$';
		}
	}
} // end of _mwSubstVariables

////////////////////////////////////////////////////////////////////////////
// _mwStrStrNoCase
// Case insensitive version of ststr
////////////////////////////////////////////////////////////////////////////
char* _mwStrStrNoCase(char* pchHaystack, char* pchNeedle)
{
  char* pchReturn=NULL;

  while(*pchHaystack!='\0' && pchReturn==NULL) {
    if (toupper(*pchHaystack)==toupper(pchNeedle[0])) {
      char* pchTempHay=pchHaystack;
      char* pchTempNeedle=pchNeedle;
      // start of match
      while(*pchTempHay!='\0') {
        if(toupper(*pchTempHay)!=toupper(*pchTempNeedle)) {
          // failed to match
          break;
        }
        pchTempNeedle++;
        pchTempHay++;
        if (*pchTempNeedle=='\0') {
          // completed match
          pchReturn=pchHaystack;
          break;
        }
      }
    }
    pchHaystack++;
  }

  return pchReturn;
} // end of _mwStrStrNoCase

////////////////////////////////////////////////////////////////////////////
// _mwStrDword
////////////////////////////////////////////////////////////////////////////
char* _mwStrDword(char* pchHaystack, DWORD dwSub, DWORD dwCharMask)
{
	char* pchReturn=NULL;
	dwCharMask = dwCharMask?(dwCharMask & 0xdfdfdfdf):0xdfdfdfdf;
	dwSub &= dwCharMask;
	while(*pchHaystack) {
		if (((*(DWORD*)pchHaystack) & dwCharMask)==dwSub)
			return pchHaystack;
	    pchHaystack++;
	}
	return NULL;
}

////////////////////////////////////////////////////////////////////////////
// _mwDecodeCharacter
// Convert and individual character
////////////////////////////////////////////////////////////////////////////
__inline char _mwDecodeCharacter(char* s)
{
  	register unsigned char v;
	if (!*s) return 0;
	if (*s>='a' && *s<='f')
		v = *s-('a'-'A'+7);
	else if (*s>='A' && *s<='F')
		v = *s-7;
	else
		v = *s;
	if (*(++s)==0) return v;
	v <<= 4;
	if (*s>='a' && *s<='f')
		v |= (*s-('a'-'A'+7)) & 0xf;
	else if (*s>='A' && *s<='F')
		v |= (*s-7) & 0xf;
	else
		v |= *s & 0xf;
	return v;
} // end of _mwDecodeCharacter

////////////////////////////////////////////////////////////////////////////
// _mwDecodeString
// This function converts URLd characters back to ascii. For example
// %3A is '.'
////////////////////////////////////////////////////////////////////////////
void _mwDecodeString(char* pchString)
{
  int bEnd=FALSE;
  char* pchInput=pchString;
  char* pchOutput=pchString;

  do {
    switch (*pchInput) {
    case '%':
      if (*(pchInput+1)=='\0' || *(pchInput+2)=='\0') {
        // something not right - terminate the string and abort
        *pchOutput='\0';
        bEnd=TRUE;
      } else {
        *pchOutput=_mwDecodeCharacter(pchInput+1);
        pchInput+=3;
      }
      break;
/*
    case '+':
      *pchOutput=' ';
      pchInput++;
      break;
*/
    case '\0':
      bEnd=TRUE;
      // drop through
    default:
      // copy character
      *pchOutput=*pchInput;
      pchInput++;
    }
    pchOutput++;
  } while (!bEnd);
} // end of _mwDecodeString

int _mwGetContentType(char *pchExtname)
{
	// check type of file requested
	if (pchExtname[1]=='\0') {
		return HTTPFILETYPE_OCTET;
	} else if (pchExtname[2]=='\0') {
		switch (GETDWORD(pchExtname) & 0xffdfdf) {
		case FILEEXT_JS: return HTTPFILETYPE_JS;
		}
	} else if (pchExtname[3]=='\0' || pchExtname[3]=='?') {
		//identify 3-char file extensions
		switch (GETDWORD(pchExtname) & 0xffdfdfdf) {
		case FILEEXT_HTM:	return HTTPFILETYPE_HTML;
		case FILEEXT_XML:	return HTTPFILETYPE_XML;
		case FILEEXT_TEXT:	return HTTPFILETYPE_TEXT;
		case FILEEXT_CSS:	return HTTPFILETYPE_CSS;
		case FILEEXT_PNG:	return HTTPFILETYPE_PNG;
		case FILEEXT_JPG:	return HTTPFILETYPE_JPEG;
		case FILEEXT_GIF:	return HTTPFILETYPE_GIF;
		case FILEEXT_SWF:	return HTTPFILETYPE_SWF;
		case FILEEXT_MPA:	return HTTPFILETYPE_MPA;
		case FILEEXT_MPG:	return HTTPFILETYPE_MPEG;
		case FILEEXT_AVI:	return HTTPFILETYPE_AVI;
		case FILEEXT_MP4:	return HTTPFILETYPE_MP4;
		case FILEEXT_MOV:	return HTTPFILETYPE_MOV;
		}
	} else if (pchExtname[4]=='\0' || pchExtname[4]=='?') {
		//logic-and with 0xdfdfdfdf gets the uppercase of 4 chars
		switch (GETDWORD(pchExtname)&0xdfdfdfdf) {
		case FILEEXT_HTML:	return HTTPFILETYPE_HTML;
		case FILEEXT_MPEG:	return HTTPFILETYPE_MPEG;
		}
	}
	return HTTPFILETYPE_OCTET;
}

int _mwGrabToken(char *pchToken, char chDelimiter, char *pchBuffer, int iMaxTokenSize)
{
	char *p=pchToken;
	int iCharCopied=0;

	while (*p && *p!=chDelimiter && iCharCopied<iMaxTokenSize) {
		*(pchBuffer++)=*(p++);
		iCharCopied++;
	}
	pchBuffer='\0';
	return (*p==chDelimiter)?iCharCopied:0;
}

int _mwParseHttpHeader(HttpSocket* phsSocket)
{
	int iLen;
	char buf[12];
	char *p=phsSocket->buffer;		//pointer to header data
	HttpRequest *req=&phsSocket->request;

	//analyze rest of the header
	for(;;) {
		//look for a valid field name
		while (*p && *p!='\r') p++;		//travel to '\r'
		if (!*p || GETDWORD(p)==HTTP_HEADEREND) break;
		p+=2;							//skip "\r\n"
		switch (*(p++)) {
		case 'C':
			if (!memcmp(p,"onnection: ",11)) {
				p+=11;
				if (!memcmp(p,"close",5)) {
					SETFLAG(phsSocket,FLAG_CONN_CLOSE);
					p+=5;
				}
			} else if (!memcmp(p,"ontent-Length: ",15)) {
				p+=15;
				p+=_mwGrabToken(p,'\r',buf,sizeof(buf));
				phsSocket->response.iContentLength=atoi(buf);
			}
			break;
		case 'R':
			if (!memcmp(p,"eferer: ",8)) {
				p+=8;
				phsSocket->request.ofReferer=(int)p-(int)phsSocket->buffer;
			} else if (!memcmp(p,"ange: bytes=",12)) {
				p+=12;
				iLen=_mwGrabToken(p,'-',buf,sizeof(buf));
				if (iLen==0) continue;
				p+=iLen;
				phsSocket->request.iStartByte=atoi(buf);
				iLen=_mwGrabToken(p,'/',buf,sizeof(buf));
				if (iLen==0) continue;
				p+=iLen;
                phsSocket->response.iContentLength=atoi(buf)-phsSocket->request.iStartByte+1;
			}
			break;
		case 'H':
			if (!memcmp(p,"ost: ",5)) {
				p+=5;
				phsSocket->request.ofHost=(int)p-(int)phsSocket->buffer;
			}
			break;
		}
	}
	return 0;					//end of header
}
//////////////////////////// END OF FILE ///////////////////////////////////

⌨️ 快捷键说明

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