📄 http.c
字号:
if ((int)socket<=0) {
DBG("Error accepting socket\n");
return 0;
}
#ifndef WIN32
// set to non-blocking to stop sends from locking up thread
{
int iRc;
int iSockFlags;
iSockFlags = fcntl(socket, F_GETFL, 0);
iSockFlags |= O_NONBLOCK;
iRc = fcntl(socket, F_SETFL, iSockFlags);
}
#endif
if (hp->socketRcvBufSize) {
int iSocketBufSize=hp->socketRcvBufSize<<10;
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (const char*)&iSocketBufSize, sizeof(int));
}
return socket;
} // end of _mwAcceptSocket
int _mwBuildHttpHeader(HttpParam* hp, HttpSocket *phsSocket, time_t contentDateTime, unsigned char* buffer)
{
char *p=buffer;
p+=sprintf(p,HTTP200_HEADER,
(phsSocket->request.iStartByte==0)?"200 OK":"206 Partial content",
HTTP_KEEPALIVE_TIME,hp->maxReqPerConn,
ISFLAGSET(phsSocket,FLAG_CONN_CLOSE)?"close":"Keep-Alive");
p+=mwGetHttpDateTime(contentDateTime, p);
SETWORD(p,DEFWORD('\r','\n'));
p+=2;
p+=sprintf(p,"Content-Type: %s\r\n",contentTypeTable[phsSocket->response.fileType]);
if (phsSocket->response.iContentLength >= 0) {
p+=sprintf(p,"Content-Length: %d\r\n",phsSocket->response.iContentLength);
}
SETDWORD(p,DEFDWORD('\r','\n',0,0));
return (int)p-(int)buffer+2;
}
int mwParseQueryString(UrlHandlerParam* up)
{
if (up->iVarCount==-1) {
//parsing variables from query string
char *p,*s = NULL;
if (ISFLAGSET(up->hs,FLAG_REQUEST_GET)) {
// get start of query string
s = strchr(up->pucRequest, '?');
if (s) {
*(s++) = 0;
}
#ifdef HTTPPOST
} else {
s = up->hs->request.pucPayload;
#endif
}
if (s && *s) {
int i;
int n = 1;
//get number of variables
for (p = s; *p ; ) if (*(p++)=='&') n++;
up->pxVars = calloc(n + 1, sizeof(HttpVariables));
up->iVarCount = n;
//store variable name and value
for (i = 0, p = s; i < n; p++) {
switch (*p) {
case '=':
if (!(up->pxVars + i)->name) {
*p = 0;
(up->pxVars + i)->name = s;
s=p+1;
}
break;
case 0:
case '&':
*p = 0;
if ((up->pxVars + i)->name) {
(up->pxVars + i)->value = s;
_mwDecodeString(s);
} else {
(up->pxVars + i)->name = s;
(up->pxVars + i)->value = p;
}
s = p + 1;
i++;
break;
}
}
(up->pxVars + n)->name = NULL;
}
}
return up->iVarCount;
}
int _mwCheckUrlHandlers(HttpParam* hp, HttpSocket* phsSocket)
{
UrlHandler* puh;
UrlHandlerParam up;
int ret=0;
up.pxVars=NULL;
for (puh=hp->pxUrlHandler; puh->pchUrlPrefix; puh++) {
int iPrefixLen=strlen(puh->pchUrlPrefix);
if (puh->pfnUrlHandler && !strncmp(phsSocket->request.pucPath,puh->pchUrlPrefix,iPrefixLen)) {
//URL prefix matches
memset(&up, 0, sizeof(up));
up.hp=hp;
up.hs = phsSocket;
up.iDataBytes=phsSocket->response.iBufferSize;
up.pucRequest=phsSocket->request.pucPath+iPrefixLen;
up.pucHeader=phsSocket->buffer;
up.pucBuffer=phsSocket->pucData;
up.pucBuffer[0]=0;
up.iVarCount=-1;
phsSocket->ptr=(void*)puh->pfnUrlHandler;
ret=(*(PFNURLCALLBACK)phsSocket->ptr)(&up);
if (!ret) continue;
if (ret & FLAG_DATA_REDIRECT) {
_mwRedirect(phsSocket, up.pucBuffer);
DBG("URL handler: redirect\n");
} else {
phsSocket->flags|=ret;
phsSocket->response.fileType=up.fileType;
hp->stats.urlProcessCount++;
if (ret & FLAG_TO_FREE) {
phsSocket->ptr=up.pucBuffer; //keep the pointer which will be used to free memory later
}
if (ret & FLAG_DATA_RAW) {
phsSocket->pucData=up.pucBuffer;
phsSocket->iDataLength=up.iDataBytes;
phsSocket->response.iContentLength=up.iContentBytes>0?up.iContentBytes:up.iDataBytes;
DBG("URL handler: raw data)\n");
} else if (ret & FLAG_DATA_FILE) {
phsSocket->flags|=FLAG_DATA_FILE;
if (up.pucBuffer[0])
phsSocket->request.pucPath=up.pucBuffer;
DBG("URL handler: file\n");
} else if (ret & FLAG_DATA_FD) {
phsSocket->flags |= FLAG_DATA_FILE;
DBG("URL handler: file descriptor\n");
}
break;
}
}
}
if (up.pxVars) free(up.pxVars);
return ret;
}
////////////////////////////////////////////////////////////////////////////
// _mwProcessReadSocket
// Process a socket (read)
////////////////////////////////////////////////////////////////////////////
int _mwProcessReadSocket(HttpParam* hp, HttpSocket* phsSocket)
{
char *p;
#ifdef HTTPPOST
if ((HttpMultipart*)phsSocket->ptr != NULL) {
//_mwProcessMultipartPost(phsSocket);
return 0;
}
#endif
// check if receive buffer full
if (phsSocket->iDataLength>=MAX_REQUEST_SIZE) {
// close connection
SYSLOG(LOG_INFO,"Invalid request header size (%d bytes)\n",phsSocket->iDataLength);
SETFLAG(phsSocket, FLAG_CONN_CLOSE);
return -1;
}
// read next chunk of data
{
int sLength;
sLength=recv(phsSocket->socket,
phsSocket->pucData+phsSocket->iDataLength,
phsSocket->response.iBufferSize-phsSocket->iDataLength, 0);
if (sLength <= 0) {
SYSLOG(LOG_INFO,"[%d] socket closed by client\n",phsSocket->socket);
SETFLAG(phsSocket, FLAG_CONN_CLOSE);
return -1;
}
// add in new data received
phsSocket->iDataLength+=sLength;
}
//check request type
switch (GETDWORD(phsSocket->pucData)) {
case HTTP_GET:
SETFLAG(phsSocket,FLAG_REQUEST_GET);
phsSocket->request.pucPath=phsSocket->pucData+5;
break;
#ifdef HTTPPOST
case HTTP_POST:
SETFLAG(phsSocket,FLAG_REQUEST_POST);
phsSocket->request.pucPath=phsSocket->pucData+6;
break;
#endif
}
// check if end of request
if (phsSocket->request.siHeaderSize==0) {
int i=0;
while (GETDWORD(phsSocket->buffer + i) != HTTP_HEADEREND) {
if (++i > phsSocket->iDataLength - 3) return 0;
}
// reach the end of the header
if (!ISFLAGSET(phsSocket,FLAG_REQUEST_GET|FLAG_REQUEST_POST)) {
SYSLOG(LOG_INFO,"[%d] Unsupported method\n",phsSocket->socket);
SETFLAG(phsSocket,FLAG_CONN_CLOSE);
return -1;
}
phsSocket->request.siHeaderSize = i + 4;
DBG("[%d] header size: %d bytes\n",phsSocket->socket,phsSocket->request.siHeaderSize);
if (_mwParseHttpHeader(phsSocket)) {
SYSLOG(LOG_INFO,"Error parsing request\n");
SETFLAG(phsSocket, FLAG_CONN_CLOSE);
return -1;
#ifdef HTTPPOST
} else if (ISFLAGSET(phsSocket,FLAG_REQUEST_POST)) {
hp->stats.reqPostCount++;
phsSocket->request.pucPayload=malloc(phsSocket->response.iContentLength+1);
phsSocket->request.pucPayload[phsSocket->response.iContentLength]=0;
phsSocket->iDataLength -= phsSocket->request.siHeaderSize;
memcpy(phsSocket->request.pucPayload, phsSocket->buffer + phsSocket->request.siHeaderSize, phsSocket->iDataLength);
phsSocket->pucData = phsSocket->request.pucPayload;
#endif
}
// add header zero terminator
phsSocket->buffer[phsSocket->request.siHeaderSize]=0;
DBG("%s",phsSocket->buffer);
}
if ( phsSocket->iDataLength < phsSocket->response.iContentLength ) {
return 0;
}
p=phsSocket->buffer + phsSocket->request.siHeaderSize + 4;
p=(unsigned char*)((unsigned long)p & (-4)); //keep 4-byte aligned
*p=0;
//keep request path
{
char *q;
int iPathLen;
for (q=phsSocket->request.pucPath;*q && *q!=' ';q++);
iPathLen=(int)q-(int)(phsSocket->request.pucPath);
if (iPathLen>=MAX_REQUEST_PATH_LEN) {
DBG("Request path too long and is stripped\n");
iPathLen=MAX_REQUEST_PATH_LEN-1;
}
if (iPathLen>0)
memcpy(p,phsSocket->request.pucPath,iPathLen);
*(p+iPathLen)=0;
phsSocket->request.pucPath=p;
p=(unsigned char*)(((unsigned long)(p+iPathLen+4+1))&(-4)); //keep 4-byte aligned
}
phsSocket->pucData=p; //free buffer space
phsSocket->response.iBufferSize=(HTTP_BUFFER_SIZE-(phsSocket->pucData-phsSocket->buffer)-1)&(-4);
SYSLOG(LOG_INFO,"[%d] request path: /%s\n",phsSocket->socket,phsSocket->request.pucPath);
hp->stats.reqCount++;
if (ISFLAGSET(phsSocket,FLAG_REQUEST_GET|FLAG_REQUEST_POST)) {
if (hp->pxUrlHandler) {
if (!_mwCheckUrlHandlers(hp,phsSocket))
SETFLAG(phsSocket,FLAG_DATA_FILE);
}
// set state to SENDING (actual sending will occur on next select)
CLRFLAG(phsSocket,FLAG_RECEIVING)
SETFLAG(phsSocket,FLAG_SENDING);
hp->stats.reqGetCount++;
if (ISFLAGSET(phsSocket,FLAG_DATA_FILE)) {
// send requested page
return _mwStartSendFile(hp,phsSocket);
} else if (ISFLAGSET(phsSocket,FLAG_DATA_RAW)) {
return _mwStartSendRawData(hp, phsSocket);
}
}
SYSLOG(LOG_INFO,"Error occurred (might be a bug)\n");
return -1;
} // end of _mwProcessReadSocket
////////////////////////////////////////////////////////////////////////////
// _mwProcessWriteSocket
// Process a socket (write)
////////////////////////////////////////////////////////////////////////////
int _mwProcessWriteSocket(HttpParam *hp, HttpSocket* phsSocket)
{
if (phsSocket->iDataLength<=0) {
SYSLOG(LOG_INFO,"[%d] Data sending completed (%d/%d)\n",phsSocket->socket,phsSocket->response.iSentBytes,phsSocket->response.iContentLength);
return 1;
}
SYSLOG(LOG_INFO,"[%d] sending data\n",phsSocket->socket);
if (ISFLAGSET(phsSocket,FLAG_DATA_RAW|FLAG_DATA_STREAM)) {
return _mwSendRawDataChunk(hp, phsSocket);
} else if (ISFLAGSET(phsSocket,FLAG_DATA_FILE)) {
return _mwSendFileChunk(hp, phsSocket);
} else {
SYSLOG(LOG_INFO,"Invalid content source\n");
return -1;
}
} // end of _mwProcessWriteSocket
////////////////////////////////////////////////////////////////////////////
// _mwCloseSocket
// Close an open connection
////////////////////////////////////////////////////////////////////////////
void _mwCloseSocket(HttpParam* hp, HttpSocket* phsSocket)
{
if (phsSocket->fd) {
close(phsSocket->fd);
phsSocket->fd = 0;
}
if (ISFLAGSET(phsSocket,FLAG_TO_FREE) && phsSocket->ptr) {
free(phsSocket->ptr);
phsSocket->ptr=NULL;
}
#ifdef HTTPPOST
if (phsSocket->request.pucPayload) {
free(phsSocket->request.pucPayload);
}
#endif
if (!ISFLAGSET(phsSocket,FLAG_CONN_CLOSE) && phsSocket->iRequestCount<hp->maxReqPerConn) {
_mwInitSocketData(phsSocket);
//reset flag bits
phsSocket->iRequestCount++;
phsSocket->tmExpirationTime=time(NULL)+HTTP_KEEPALIVE_TIME;
return;
}
if (phsSocket->socket != 0) {
closesocket(phsSocket->socket);
} else {
SYSLOG(LOG_INFO,"[%d] bug: socket=0 (structure: 0x%x \n",phsSocket->socket,phsSocket);
}
hp->stats.clientCount--;
phsSocket->iRequestCount=0;
SYSLOG(LOG_INFO,"[%d] socket closed after responded for %d requests\n",phsSocket->socket,phsSocket->iRequestCount);
SYSLOG(LOG_INFO,"Connected clients: %d\n",hp->stats.clientCount);
phsSocket->socket=0;
} // end of _mwCloseSocket
__inline int _mwStrCopy(char *dest, char *src)
{
int i;
for (i=0; src[i]; i++) {
dest[i]=src[i];
}
dest[i]=0;
return i;
}
int _mwListDirectory(HttpSocket* phsSocket, char* dir)
{
char cFileName[128];
char cFilePath[MAX_PATH];
char *p=phsSocket->pucData;
int ret;
char *pagebuf=phsSocket->pucData;
int bufsize=phsSocket->response.iBufferSize;
p+=sprintf(p,"<html><head><title>/%s</title></head><body><table border=0 cellpadding=0 cellspacing=0 width=100%%><h2>Directory of /%s</h2><hr>",
phsSocket->request.pucPath,phsSocket->request.pucPath);
if (!*dir) SETWORD(dir,DEFWORD('.',0));
DBG("Listing directory: %s\n",dir);
for (ret=ReadDir(dir,cFileName); !ret; ret=ReadDir(NULL,cFileName)) {
struct stat st;
char *s;
int bytes;
if (GETWORD(cFileName)==DEFWORD('.',0)) continue;
DBG("Checking %s ...\n",cFileName);
bytes=p-pagebuf;
if (bytes+384>bufsize) {
//need to expand buffer
bufsize+=2048;
if (!ISFLAGSET(phsSocket,FLAG_TO_FREE)) {
//first time expanding
SETFLAG(phsSocket,FLAG_TO_FREE);
pagebuf=malloc(bufsize);
memcpy(pagebuf,phsSocket->pucData,bytes);
} else {
pagebuf=realloc(pagebuf,bufsize);
}
p=pagebuf+bytes;
DBG("Buffer expanded to %d bytes\n",bufsize);
}
sprintf(cFilePath,"%s/%s",dir,cFileName);
if (stat(cFilePath,&st)) continue;
if (st.st_mode & S_IFDIR) {
p+=sprintf(p,"<tr><td width=35%%><a href='%s/'>%s</a></td><td width=15%%><dir></td><td width=15%%>",
cFileName,cFileName);
} else {
p+=sprintf(p,"<tr><td width=35%%><a href='%s'>%s</a></td><td width=15%%>%d bytes</td><td width=15%%>",
cFileName,cFileName,st.st_size);
s=strrchr(cFileName,'.');
if (s) {
int filetype=_mwGetContentType(++s);
if (filetype!=HTTPFILETYPE_OCTET)
p+=_mwStrCopy(p,contentTypeTable[filetype]);
else
p+=sprintf(p,"%s file",s);
}
}
p+=_mwStrCopy(p,"</td><td>");
p+=mwGetHttpDateTime(st.st_mtime,p);
p+=_mwStrCopy(p,"</td></tr>");
}
p+=sprintf(p,"</table><hr><i>Directory content generated by MiniWeb</i></body></html>");
ReadDir(NULL,NULL);
phsSocket->response.iContentLength=(phsSocket->iDataLength=p-pagebuf);
phsSocket->response.fileType=HTTPFILETYPE_HTML;
if (ISFLAGSET(phsSocket,FLAG_TO_FREE)) {
phsSocket->pucData=pagebuf;
phsSocket->ptr=pagebuf;
}
return 0;
}
void _mwSend404Page(HttpSocket* phsSocket)
{
int bytes,offset=0;
char *p=HTTP404_HEADER;
SYSLOG(LOG_INFO,"[%d] Http file not found\n",phsSocket->socket);
// send file not found header
do {
bytes=send(phsSocket->socket, p+offset,sizeof(HTTP404_HEADER)-1-offset,0);
if (bytes<=0) break;
offset+=bytes;
} while (offset<sizeof(HTTP404_HEADER)-1);
}
#ifdef WIN32
#define OPEN_FLAG O_RDONLY|0x8000
#else
#define OPEN_FLAG O_RDONLY
#endif
////////////////////////////////////////////////////////////////////////////
// _mwStartSendFile
// Setup for sending of a file
////////////////////////////////////////////////////////////////////////////
int _mwStartSendFile(HttpParam* hp, HttpSocket* phsSocket)
{
struct stat st;
HttpFilePath hfp;
#ifdef HTTPAUTH
// check if authenticated
if (FALSE == _mwCheckAuthentication(phsSocket)) {
// Not authenticated
if (phsSocket->response.fileType==HTTPFILETYPE_HTML) {
// send password page only
pchFilename=(char*)g_chPasswordPage;
}
}
#endif
hfp.pchRootPath=hp->pchWebPath;
// check type of file requested
if (!(phsSocket->flags & FLAG_DATA_FD)) {
hfp.pchHttpPath=phsSocket->request.pucPath;
mwGetLocalFileName(&hfp);
// open file
phsSocket->fd=open(hfp.cFilePath,OPEN_FLAG);
} else {
strcpy(hfp.cFilePath, phsSocket->request.pucPath);
hfp.pchExt = strrchr(hfp.cFilePath, '.');
if (hfp.pchExt) hfp.pchExt++;
}
if (phsSocket->fd <= 0) {
char *p;
int i;
if (stat(hfp.cFilePath,&st) < 0 || !(st.st_mode & S_IFDIR)) {
// file/dir not found
_mwSend404Page(phsSocket);
return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -