📄 http.c
字号:
// clear state vars hp->bKillWebserver=FALSE; hp->bWebserverRunning=FALSE; return NULL;} // end of _mwHttpThread////////////////////////////////////////////////////////////////////////////// _mwAcceptSocket// Accept an incoming connection////////////////////////////////////////////////////////////////////////////SOCKET _mwAcceptSocket(HttpParam* hp,struct sockaddr_in *sinaddr){ SOCKET socket; int namelen=sizeof(struct sockaddr); socket=accept(hp->listenSocket, (struct sockaddr*)sinaddr,&namelen); if ((int)socket<=0) { DEBUG("Error accepting socket\n"); return 0; } SYSLOG(LOG_INFO,"[%d] connection accepted @ %s\n",socket,GetTimeString());#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->siSocketRcvBufSize) { int iSocketBufSize=hp->siSocketRcvBufSize<<10; setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (const char*)&iSocketBufSize, sizeof(int)); } return socket;} // end of _mwAcceptSocketint _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->siMaxReqPerConn, 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 _mwCheckUrlHandlers(HttpParam* hp, HttpSocket* phsSocket){ UrlHandler* puh; UrlHandlerParam up; int ret=0; up.pxVars=NULL; up.iVarCount=-1; 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 up.hp=hp; up.iDataBytes=phsSocket->response.iBufferSize; up.pucRequest=phsSocket->request.pucPath+iPrefixLen; up.pucHeader=phsSocket->buffer; up.request=&phsSocket->request; up.pucBuffer=phsSocket->pucData; up.pucBuffer[0]=0; up.iContentBytes=0; up.iSentBytes=0; phsSocket->ptr=(void*)puh->pfnUrlHandler; if (up.iVarCount==-1) { //parsing variables in URL char *p,*s=NULL; up.iVarCount=0; if (ISFLAGSET(phsSocket,FLAG_REQUEST_GET)) { s = strchr(up.pucRequest,'?'); if (s) { *(s++) = 0; }#ifdef HTTPPOST } else { s = phsSocket->request.pucPayload;#endif } if (s) { int i=0; //get number of variables for (p = s; *p ; ) { if (*(p++)=='=') up.iVarCount++; } if (up.iVarCount) { up.pxVars=malloc(up.iVarCount*sizeof(HttpVariables)+sizeof(char*)); //store variable name and value for (p=s; *p && i<up.iVarCount; p++) { if (*p=='=') { *p=0; (up.pxVars+i)->name=s; s=p+1; } else if (*p=='&') { *p=0; (up.pxVars+i)->value=s; s=p+1; i++; } } (up.pxVars+i)->value=s; (up.pxVars+up.iVarCount)->name=NULL; } } } ret=(*(PFNURLCALLBACK)phsSocket->ptr)(&up); if (ret & (FLAG_DATA_RAW | FLAG_DATA_FILE)) { 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; DEBUG("URL handler acted (raw data)\n"); } else { phsSocket->flags|=FLAG_DATA_FILE; if (up.pucBuffer[0]) phsSocket->request.pucPath=up.pucBuffer; DEBUG("URL handler acted (file)\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; DEBUG("[%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; DEBUG("%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) { DEBUG("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 (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->siRequestCount<hp->siMaxReqPerConn) { _mwInitSocketData(phsSocket); //reset flag bits phsSocket->siRequestCount++; 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->siRequestCount=0; SYSLOG(LOG_INFO,"[%d] socket closed after responded for %d requests\n",phsSocket->socket,phsSocket->siRequestCount); 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)); DEBUG("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; DEBUG("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; DEBUG("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; hfp.pchHttpPath=phsSocket->request.pucPath; // check type of file requested mwGetLocalFileName(&hfp); if (stat(hfp.cFilePath,&st)<0) { // file/dir not found _mwSend404Page(phsSocket); return -1; } if (st.st_mode & S_IFDIR) { char *p=hfp.cFilePath; while (*p) p++; {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -