📄 http.c
字号:
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 + -