废话不多说,先上效果图:
启动web server:
浏览器截图:
下载使用(暂时只有Windows版,Linux版有时间的话补上):miniweb.rar
下面直接贴出主要实现代码:
Http类主要负责接收、解析客户端请求,然后通过WebAction类响应并发送相应的数据
Http.h
#ifndef _HTTP_H #define _HTTP_H #include <WinSock2.h> #include <iostream> #include "zfqstring.h" class Http { public: Http(SOCKET m_socket, zfqstring id, zfqstring pwd); virtual ~Http(void); public: int Send(char* data, UINT len); int Recv(char* data, UINT len); int RecvByLine(char* data, UINT len); BOOL HttpRequestResponse(); BOOL Parse(char* data); BOOL Query(); protected: // zfqstring m_hostaddr; unsigned short m_hostport; // zfqstring m_id; zfqstring m_pwd; // zfqstring m_loginid; zfqstring m_loginpwd; // zfqstring m_postdata; zfqstring m_page; DWORD m_method; DWORD m_contentlength; // SOCKET m_socket; }; #endif
Http.cpp
#include "StdAfx.h" #include "Http.h" #include "Constant.h" #include "Base64.h" #include "FtpWebAction.h" Http::Http(SOCKET m_socket, zfqstring id, zfqstring pwd) { this->m_socket = m_socket; m_id = id; m_pwd = pwd; } Http::~Http(void) { if(m_socket) closesocket(m_socket); } int Http::Send(char* data, UINT len ) { long already_time = 0; struct fd_set fdset; struct timeval timeout; timeout.tv_sec = SELECT_WAIT_TIME; timeout.tv_usec = 0; size_t nSend = 0; size_t tLen = 0; while(1) { FD_ZERO(&fdset); FD_SET(m_socket, &fdset); int ret = select(m_socket + 1, NULL, &fdset, NULL, &timeout); switch(ret) { case 1: already_time = 0; tLen = send(m_socket, data, len - nSend, 0); nSend += tLen; if(nSend == len) return SOCKET_SENDRECV_OK; break; case 0: already_time += SELECT_WAIT_TIME; if(already_time >= MAX_WAIT_TIME_FOR_SENDRECV) { closesocket(m_socket); return SOCKET_SENDRECV_TIMEOUT; } break; default: return SOCKET_SENDRECV_ERROR; } } } int Http::Recv(char* data, UINT len ) { long already_time = 0; struct fd_set fdset; struct timeval timeout; timeout.tv_sec = SELECT_WAIT_TIME; timeout.tv_usec = 0; size_t nRecv = 0; size_t tLen = 0; while(1) { FD_ZERO(&fdset); FD_SET(m_socket, &fdset); int ret = select(m_socket + 1, &fdset, NULL, NULL, &timeout); switch(ret) { case 1: already_time = 0; tLen = recv(m_socket, data + nRecv, len - nRecv, 0); if(tLen <= 0) return nRecv; nRecv += tLen; if(nRecv == len) return nRecv; break; case 0: already_time += SELECT_WAIT_TIME; if(already_time >= MAX_WAIT_TIME_FOR_SENDRECV) { closesocket(m_socket); return SOCKET_SENDRECV_TIMEOUT; } break; default: return SOCKET_SENDRECV_ERROR; } } } int Http::RecvByLine(char* data, UINT len) { long already_time = 0; struct fd_set fdset; struct timeval timeout; timeout.tv_sec = SELECT_WAIT_TIME; timeout.tv_usec = 0; size_t nRecv = 0; size_t tLen = 0; while(1) { if(nRecv >= len - 1) { data[nRecv] = '/0'; char tempbuff[2]; while(1) { recv(m_socket, tempbuff, 1, 0); if(tempbuff[0] == '/n') break; } return SOCKET_SENDRECV_TOOLONG; } // FD_ZERO(&fdset); FD_SET(m_socket, &fdset); int ret = select(m_socket + 1, &fdset, NULL, NULL, &timeout); switch(ret) { case 1: already_time = 0; tLen = recv(m_socket, data + nRecv, 1, 0); if(tLen <= 0) { data[nRecv] = '/0'; return SOCKET_SENDRECV_ERROR; } nRecv += tLen; if(data[nRecv - 1] == '/n') goto L1; case 0: already_time += SELECT_WAIT_TIME; if(already_time >= MAX_WAIT_TIME_FOR_SENDRECV) { closesocket(m_socket); return SOCKET_SENDRECV_TIMEOUT; } break; default: return SOCKET_SENDRECV_ERROR; } } L1: if(data[nRecv - 2] == '/r') { data[nRecv - 2] = '/0'; } else if(data[nRecv - 1] == '/n') { data[nRecv - 1] = '/0'; } return SOCKET_SENDRECV_OK; } BOOL Http::Parse( char* data ) { if(strncmp(data, "GET ", 4) == 0) { m_method = HTTP_METHOD_GET; m_page = data; m_page.Cutout("GET /", " "); m_page.Cutout(NULL, "?"); m_postdata = data; m_postdata.Cutout("?", " "); m_postdata += "&"; } else if(strncmp(data, "POST ", 5) == 0) { m_method = HTTP_METHOD_POST; m_page = data; m_page.Cutout("POST /", " "); } else if(strncmp(data, "PUT ", 4) == 0) { m_method = HTTP_METHOD_PUT; m_page = data; m_page.Cutout("PUT /", " "); } else if(strncmp(data, "Content-Length:", 15) == 0) { sscanf(data, "Content-Length: %d", &m_contentlength); } else if(strncmp(data, "Host:", 5) == 0) { zfqstring tempstr; tempstr = data; tempstr.Cutout("Host: ", NULL); m_hostaddr = tempstr; m_hostaddr.Cutout(NULL, ":"); tempstr.Cutout(":", NULL); m_hostport = atoi(tempstr.GetString()); } else if(strncmp(data, "Authorization:", 14) == 0) { zfqstring tempstr; tempstr = data; tempstr.Cutout("Authorization: Basic ", NULL); tempstr = Base64::Decode(tempstr); m_loginid = tempstr; m_loginpwd = tempstr; m_loginid.Cutout(NULL, ":"); m_loginpwd.Cutout(":", NULL); } else if(strcmp(data, "") == 0) { if(m_method == HTTP_METHOD_POST) { char* post_data = (char*)malloc(m_contentlength + 1); memset(post_data, 0, m_contentlength + 1); Recv(post_data, m_contentlength); m_postdata += post_data; free(post_data); } HttpRequestResponse(); return FALSE; } return TRUE; } BOOL Http::Query() { char command[1024]; memset(command, 0, 1024); int ret = RecvByLine(command, 1024 - 1); if(ret == SOCKET_SENDRECV_OK) { if(!Parse(command)) { return FALSE; } } else if(ret == SOCKET_SENDRECV_ERROR) { return FALSE; } return TRUE; } BOOL Http::HttpRequestResponse() { WebAction* webaction = new FtpWebAction(m_socket, m_id, m_pwd, m_hostaddr, m_hostport, m_postdata, m_page, m_loginid, m_loginpwd); webaction->Response(); delete webaction; return TRUE; }
HttpSession类主要负责服务器端轮询,并借助于Http完成对客户端的响应
HttpSession.h
#ifndef _HTTPSESSION_H #define _HTTPSESSION_H #include "Http.h" class HttpSession { public: HttpSession(SOCKET socket, zfqstring id, zfqstring pwd); virtual ~HttpSession(void); public: void LoopResponse(); protected: Http* m_http; }; #endif
HttpSession.cpp
#include "StdAfx.h" #include "HttpSession.h" HttpSession::HttpSession(SOCKET socket, zfqstring id, zfqstring pwd) { m_http = new Http(socket, id, pwd); } HttpSession::~HttpSession(void) { if(NULL != m_http) delete m_http; m_http = NULL; } void HttpSession::LoopResponse() { if(m_http) { while(1) { if(!m_http->Query()) break; } } }
WebAction类是服务器和客户端进行cgi交互的基类
WebAction.h
#ifndef _WEBACTION_H #define _WEBACTION_H #include "zfqstring.h" #include "Constant.h" #include <WinSock2.h> class WebAction { public: WebAction(); virtual ~WebAction(void); public: virtual const char* Body(){return m_body.GetString();} virtual void Response(); virtual int Send(const char* data, size_t len); protected: // zfqstring m_hostaddr; unsigned short m_hostport; // zfqstring m_id; zfqstring m_pwd; // zfqstring m_loginid; zfqstring m_loginpwd; // zfqstring m_postdata; zfqstring m_page; // zfqstring m_body; // SOCKET m_socket; }; #endif
WebAction.cpp
#include "StdAfx.h" #include "WebAction.h" WebAction::WebAction() { } WebAction::~WebAction(void) { } int WebAction::Send(const char* data, size_t len ) { long already_time = 0; struct fd_set fdset; struct timeval timeout; timeout.tv_sec = SELECT_WAIT_TIME; timeout.tv_usec = 0; size_t nSend = 0; size_t tLen = 0; while(1) { FD_ZERO(&fdset); FD_SET(m_socket, &fdset); int ret = select(m_socket + 1, NULL, &fdset, NULL, &timeout); switch(ret) { case 1: already_time = 0; tLen = send(m_socket, data, len - nSend, 0); nSend += tLen; if(nSend == len) return SOCKET_SENDRECV_OK; break; case 0: already_time += SELECT_WAIT_TIME; if(already_time >= MAX_WAIT_TIME_FOR_SENDRECV) { closesocket(m_socket); return SOCKET_SENDRECV_TIMEOUT; } break; default: return SOCKET_SENDRECV_ERROR; } } } void WebAction::Response() { }
FtpWebAction类继承自WebAction,专门用于传输文件
FtpWebAction.h
#ifndef _FTPWEBACTION_H #define _FTPWEBACTION_H #include "webaction.h" class FtpWebAction : public WebAction { public: FtpWebAction(SOCKET m_socket, zfqstring m_id, zfqstring m_pwd, zfqstring m_hostaddr, unsigned m_hostport, zfqstring m_postdata, zfqstring m_page, zfqstring m_loginid, zfqstring m_loginpwd); virtual ~FtpWebAction(void); public: void Response(); private: void _handle_specialstr(char* str); int _parse_parameter(const char* postdata, const char* keyname, char* htmlStr); void _format_okheader(const char* result, const char* type, int len, char* htmlStr); void _format_okheader(const char* result, const char* type, const char* len, const char* filename, char* htmlStr); }; #endif
FtpWebAction.cpp
#include "StdAfx.h" #include "FtpWebAction.h" #include "PathUtil.h" #include "IoUtil.h" #include "imgrc.h" #define MAX_PATH_LENGTH 256 #define AUTHORIZATION_HTML_401 / "HTTP/1.1 401 Unauthorized/r/n"/ "WWW-Authenticate: Basic Realm=/"Mini Webserver For Ftp Login/"/r/n"/ "Server: MiniWebserver/r/n"/ "Content-Type: text/html/r/n"/ "/r/n"/ "<html><head><title>401 Unauthorized</title></head><body><h1>401 Unauthorized</h1><hr>Sorry, you are unauthorized.</body></html>/r/n"/ "/r/n" #define VERSIONINFO_HTML / "<hr><br>Mini Webserver For Ftp<br>"/ "Copyright (C) 2009 Yysdsyl <a href="/" mce_href="/""mailto:[email protected]/">[email protected]</a>" #define ERRORINFO_HTML_404 / "HTTP/1.1 404 Error/r/n"/ "Server: MiniWebserver/r/n"/ "Content-Type: text/html/r/n"/ "/r/n"/ "<html><head><title>404 Error</title></head><body><h1>404 Error</h1><hr>Not Found the Web.</body></html>/r/n"/ "/r/n" #define ERRORINFO_HTML_500 / "HTTP/1.1 500 OK/r/n"/ "Server: MiniWebserver/r/n"/ "Content-Type: text/html/r/n"/ "/r/n"/ "<html><head><title>500 Error</title></head><body><h1>500 Error</h1><hr>Server Error. Please Reload.</body></html>/r/n"/ "/r/n" #define OKHEADER_HTML_200 / "HTTP/1.1 %s/r/n"/ "pragma: no-cache/r/n"/ "Connection: Keep-Alive/r/n"/ "Server: MiniWebserver/r/n"/ "Content-Type: text/html/r/n"/ "/r/n" #define OKHEADER_DOWNLOAD_200 / "HTTP/1.1 200 OK/r/n"/ "pragma: no-cache/r/n"/ "Connection: Keep-Alive/r/n"/ "Server: MiniWebserver/r/n"/ "Content-Disposition: attachment;filename=test.dat/r/n"/ "Content-Type: application/octet-stream/r/n"/ "/r/n" #define HEADERMASK_HTML / "HTTP/1.1 %s/r/n"/ "pragma: no-cache/r/n"/ "Connection: Keep-Alive/r/n"/ "Server: MiniWebserver/r/n"/ "Content-Type: %s/r/n"/ "Content-Length: %ld/r/n"/ "/r/n" #define HEADERMASK_SPECIAL_HTML / "HTTP/1.1 %s/r/n"/ "pragma: no-cache/r/n"/ "Connection: Keep-Alive/r/n"/ "Server: MiniWebserver/r/n"/ "Content-Type: %s/r/n"/ "Content-Disposition: attachment;filename=%s/r/n"/ "Content-Length: %s/r/n"/ "/r/n" FtpWebAction::FtpWebAction(SOCKET m_socket, zfqstring m_id, zfqstring m_pwd, zfqstring m_hostaddr, unsigned m_hostport, zfqstring m_postdata, zfqstring m_page, zfqstring m_loginid, zfqstring m_loginpwd) { this->m_socket = m_socket; this->m_id = m_id; this->m_pwd = m_pwd; this->m_hostaddr = m_hostaddr; this->m_hostport = m_hostport; this->m_postdata = m_postdata; this->m_page = m_page; this->m_loginid = m_loginid; this->m_loginpwd = m_loginpwd; } FtpWebAction::~FtpWebAction(void) { } void FtpWebAction::Response() { char htmlStr[1024]; memset(htmlStr, 0, 1024); if(m_id == m_loginid && m_pwd == m_loginpwd) { if((m_page == "") || (m_page == "list.html")) { zfqstring fileListHtml = ""; char ftpPath[MAX_PATH_LENGTH]; memset(ftpPath, 0, MAX_PATH_LENGTH); _parse_parameter(m_postdata.GetString(), "path", ftpPath); char szDir[MAX_PATH_LENGTH]; GetCurrentDirectory(MAX_PATH_LENGTH, szDir); zfqstring szHomeDir = szDir; PathUtil pathutil(ftpPath); if(pathutil.m_existflag == 0) { zfqstring fullpath = szHomeDir; fullpath += "/"; fullpath += pathutil.GetFullPath(); IoUtil ioutil(fullpath.GetString()); FILELIST_VECTOR lv; ioutil.Dir(lv); char tmpHeader[1024]; sprintf(tmpHeader, "<h2>Index Of %s/</h2>", ftpPath); fileListHtml += tmpHeader; fileListHtml += "<hr>"; fileListHtml += "<table>"; fileListHtml += "<tr><td></td><td><font color=/"red/">Name</font></td><td align=/"right/"><font color=/"red/"> Size </font></td><td><font color=/"red/">Last Modified Time</font></td></tr>"; for(size_t i = 0; i < lv.size(); i++) { zfqstring tmpStr = ftpPath; tmpStr += "/"; tmpStr += lv[i].filename; PathUtil tmpPathUtil(tmpStr.GetString(), FMT_UNIX); zfqstring urlencodepath = ""; const char* tmpChar = tmpPathUtil.GetFullPath(); for(size_t j = 0; j < strlen(tmpChar); j++) { char urlencodestr[4]; unsigned char cc = tmpChar[j]; sprintf(urlencodestr, "%%%02X", cc); urlencodepath += urlencodestr; } char tableHtml[1024]; if(strcmp(lv[i].attribute, "DIR") == 0) { if(strcmp(lv[i].filename, "..") == 0) { sprintf(tableHtml, "<tr><td colspan=/"4/"><a href="/" mce_href="/""list.html?path=%s/"><img src="/" mce_src="/""up.gif/" border=/"0/">Parent Directory</a></td></tr>", urlencodepath.GetString()); } else if(strcmp(lv[i].filename, ".") == 0) { sprintf(tableHtml, "%s", ""); } else { sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""forder.gif/"></td><td><a href="/" mce_href="/""list.html?path=%s/"><b>%s/</b></a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, "-", lv[i].lastmodifiedtime); } } else { zfqstring tmpFileName = lv[i].filename; if(tmpFileName.EndWith(".avi") || tmpFileName.EndWith(".AVI")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""avi.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".bat") || tmpFileName.EndWith(".BAT") || tmpFileName.EndWith(".cmd") || tmpFileName.EndWith(".CMD")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""cmd.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".bmp") || tmpFileName.EndWith(".BMP")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""bmp.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".chm") || tmpFileName.EndWith(".CHM")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""chm.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".dll") || tmpFileName.EndWith(".DLL")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""dll.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".doc") || tmpFileName.EndWith(".DOC")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""doc.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".exe") || tmpFileName.EndWith(".EXE")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""exe.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".html") || tmpFileName.EndWith(".HTML") || tmpFileName.EndWith(".htm") || tmpFileName.EndWith(".HTM")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""html.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".iso") || tmpFileName.EndWith(".ISO")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""iso.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".jpg") || tmpFileName.EndWith(".JPG") || tmpFileName.EndWith(".jpeg") || tmpFileName.EndWith(".JPEG")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""jpg.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".mp3") || tmpFileName.EndWith(".MP3")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""mp3.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".pdf") || tmpFileName.EndWith(".PDF")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""pdf.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".png") || tmpFileName.EndWith(".PNG") || tmpFileName.EndWith(".gif") || tmpFileName.EndWith(".GIF")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""png.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".ppt") || tmpFileName.EndWith(".PPT")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""ppt.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".rar") || tmpFileName.EndWith(".RAR") || tmpFileName.EndWith(".zip") || tmpFileName.EndWith(".ZIP")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""rar.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".rm") || tmpFileName.EndWith(".RM") || tmpFileName.EndWith(".rmvb") || tmpFileName.EndWith(".RMVB")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""rm.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".txt") || tmpFileName.EndWith(".TXT")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""txt.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".wmv") || tmpFileName.EndWith(".WMV")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""wmv.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".xls") || tmpFileName.EndWith(".XLS")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""xls.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else if(tmpFileName.EndWith(".xml") || tmpFileName.EndWith(".XML")) sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""xml.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); else sprintf(tableHtml, "<tr><td><img src="/" mce_src="/""unknown.gif/"></td><td><a href="/" mce_href="/""download.html?path=%s/">%s</a></td><td align=/"right/"> %s </td><td>%s</td></tr>", urlencodepath.GetString(), lv[i].filename, lv[i].filesize, lv[i].lastmodifiedtime); } fileListHtml += tableHtml; } fileListHtml += "</table>"; m_body = OKHEADER_HTML_200; m_body += "<html><head><title>Mini Webserver For Ftp</title></head><body><h1><font color=/"red/">Mini Webserver For Ftp - </font><font color=/"green/">"; m_body += m_id; m_body += "</font><hr>"; m_body += fileListHtml; m_body += VERSIONINFO_HTML"</body></html>/r/n/r/n"; } else { m_body = AUTHORIZATION_HTML_401; } } else if(m_page == (zfqstring)"up.gif") { _format_okheader("200 OK","image/gif", sizeof(UP_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)UP_ICONDATA, sizeof(UP_ICONDATA)); return; } else if(m_page == (zfqstring)"forder.gif") { _format_okheader("200 OK","image/gif", sizeof(FOLDER_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)FOLDER_ICONDATA, sizeof(FOLDER_ICONDATA)); return; } else if(m_page == (zfqstring)"unknown.gif") { _format_okheader("200 OK","image/gif", sizeof(UNKNOWN_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)UNKNOWN_ICONDATA, sizeof(UNKNOWN_ICONDATA)); return; } else if(m_page == (zfqstring)"avi.gif") { _format_okheader("200 OK","image/gif", sizeof(AVI_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)AVI_ICONDATA, sizeof(AVI_ICONDATA)); return; } else if(m_page == (zfqstring)"bat.gif") { _format_okheader("200 OK","image/gif", sizeof(BAT_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)BAT_ICONDATA, sizeof(BAT_ICONDATA)); return; } else if(m_page == (zfqstring)"bmp.gif") { _format_okheader("200 OK","image/gif", sizeof(BMP_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)BMP_ICONDATA, sizeof(BMP_ICONDATA)); return; } else if(m_page == (zfqstring)"chm.gif") { _format_okheader("200 OK","image/gif", sizeof(CHM_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)CHM_ICONDATA, sizeof(CHM_ICONDATA)); return; } else if(m_page == (zfqstring)"dll.gif") { _format_okheader("200 OK","image/gif", sizeof(DLL_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)DLL_ICONDATA, sizeof(DLL_ICONDATA)); return; } else if(m_page == (zfqstring)"doc.gif") { _format_okheader("200 OK","image/gif", sizeof(DOC_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)DOC_ICONDATA, sizeof(DOC_ICONDATA)); return; } else if(m_page == (zfqstring)"exe.gif") { _format_okheader("200 OK","image/gif", sizeof(EXE_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)EXE_ICONDATA, sizeof(EXE_ICONDATA)); return; } else if(m_page == (zfqstring)"html.gif") { _format_okheader("200 OK","image/gif", sizeof(HTML_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)HTML_ICONDATA, sizeof(HTML_ICONDATA)); return; } else if(m_page == (zfqstring)"up.gif") { _format_okheader("200 OK","image/gif", sizeof(UP_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)UP_ICONDATA, sizeof(UP_ICONDATA)); return; } else if(m_page == (zfqstring)"iso.gif") { _format_okheader("200 OK","image/gif", sizeof(ISO_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)ISO_ICONDATA, sizeof(ISO_ICONDATA)); return; } else if(m_page == (zfqstring)"jpg.gif") { _format_okheader("200 OK","image/gif", sizeof(JPG_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)JPG_ICONDATA, sizeof(JPG_ICONDATA)); return; } else if(m_page == (zfqstring)"mp3.gif") { _format_okheader("200 OK","image/gif", sizeof(MP3_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)MP3_ICONDATA, sizeof(MP3_ICONDATA)); return; } else if(m_page == (zfqstring)"pdf.gif") { _format_okheader("200 OK","image/gif", sizeof(PDF_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)PDF_ICONDATA, sizeof(PDF_ICONDATA)); return; } else if(m_page == (zfqstring)"png.gif") { _format_okheader("200 OK","image/gif", sizeof(PNG_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)PNG_ICONDATA, sizeof(PNG_ICONDATA)); return; } else if(m_page == (zfqstring)"ppt.gif") { _format_okheader("200 OK","image/gif", sizeof(PPT_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)PPT_ICONDATA, sizeof(PPT_ICONDATA)); return; } else if(m_page == (zfqstring)"rar.gif") { _format_okheader("200 OK","image/gif", sizeof(RAR_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)RAR_ICONDATA, sizeof(RAR_ICONDATA)); return; } else if(m_page == (zfqstring)"rm.gif") { _format_okheader("200 OK","image/gif", sizeof(RM_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)RM_ICONDATA, sizeof(RM_ICONDATA)); return; } else if(m_page == (zfqstring)"txt.gif") { _format_okheader("200 OK","image/gif", sizeof(TXT_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)TXT_ICONDATA, sizeof(TXT_ICONDATA)); return; } else if(m_page == (zfqstring)"wmv.gif") { _format_okheader("200 OK","image/gif", sizeof(WMV_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)WMV_ICONDATA, sizeof(WMV_ICONDATA)); return; } else if(m_page == (zfqstring)"xls.gif") { _format_okheader("200 OK","image/gif", sizeof(XLS_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)XLS_ICONDATA, sizeof(XLS_ICONDATA)); return; } else if(m_page == (zfqstring)"xml.gif") { _format_okheader("200 OK","image/gif", sizeof(XML_ICONDATA),htmlStr); Send(htmlStr, strlen(htmlStr)); Send((char*)XML_ICONDATA, sizeof(XML_ICONDATA)); return; } else if(m_page == (zfqstring)"download.html") { char ftpPath[MAX_PATH_LENGTH]; memset(ftpPath,0,MAX_PATH_LENGTH); _parse_parameter(m_postdata.GetString(), "path", ftpPath); char szDir[MAX_PATH_LENGTH]; GetCurrentDirectory(MAX_PATH_LENGTH, szDir); zfqstring szHomeDir = szDir; PathUtil pathutil(ftpPath); if(pathutil.m_existflag == 0) { zfqstring fullpath = szHomeDir; fullpath += "/"; fullpath += pathutil.GetFullPath(); IoUtil ioutil(fullpath.GetString()); char filesizeStr[32]; memset(filesizeStr, 0, 32); ioutil.GetFileSize(filesizeStr); zfqstring downloaditem = ftpPath; downloaditem.ShiftLowCase(); char savename[MAX_PATH_LENGTH]; strcpy(savename, pathutil.GetLastElement()); _format_okheader("200 OK", "application/octet-stream", filesizeStr, savename, htmlStr); // if(downloaditem.EndWith(".asf")) // _format_okheader("200 OK", "video/x-ms-asf", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".avi")) // _format_okheader("200 OK", "video/x-msvideo", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".asp")) // _format_okheader("200 OK", "text/asp", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".bmp")) // _format_okheader("200 OK", "application/x-bmp", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".css")) // _format_okheader("200 OK", "text/css", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".dll")) // _format_okheader("200 OK", "application/x-msdownload", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".doc")) // _format_okheader("200 OK", "application/msword", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".exe")) // _format_okheader("200 OK", "application/x-msdownload", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".ico")) // _format_okheader("200 OK", "image/x-icon", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".jpg") || downloaditem.EndWith(".jpeg")) // _format_okheader("200 OK", "image/jpeg", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".js")) // _format_okheader("200 OK", "application/x-javascript", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".mdb")) // _format_okheader("200 OK", "application/x-mdb", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".mp3")) // _format_okheader("200 OK", "audio/mp3", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".mp4")) // _format_okheader("200 OK", "video/mpeg4", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".mpg") || downloaditem.EndWith(".mpeg")) // _format_okheader("200 OK", "video/mpg", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".pdf")) // _format_okheader("200 OK", "application/pdf", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".png")) // _format_okheader("200 OK", "image/png", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".ppm")) // _format_okheader("200 OK", "application/x-ppm", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".ppt")) // _format_okheader("200 OK", "application/vnd.ms-powerpoint", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".rm") || downloaditem.EndWith(".rmvb")) // _format_okheader("200 OK", "application/vnd.rn-realmedia", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".tif") || downloaditem.EndWith(".tiff")) // _format_okheader("200 OK", "image/tiff", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".txt") || downloaditem.EndWith(".c") || downloaditem.EndWith(".h") || // downloaditem.EndWith(".cpp") || downloaditem.EndWith(".py") || downloaditem.EndWith(".php")) // _format_okheader("200 OK", "text/plain", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".wav")) // _format_okheader("200 OK", "audio/wav", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".wmv")) // _format_okheader("200 OK", "video/x-ms-wmv", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".xls")) // _format_okheader("200 OK", "application/vnd.ms-excel", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".gif")) // _format_okheader("200 OK", "image/gif", filesizeStr, savename, htmlStr); // else if(downloaditem.EndWith(".htm") || downloaditem.EndWith(".html")) // _format_okheader("200 OK", "text/html", filesizeStr, savename, htmlStr); // else // _format_okheader("200 OK", "application/octet-stream", filesizeStr, savename, htmlStr); Send(htmlStr, strlen(htmlStr)); ioutil.SendFile(m_socket, 0); return; } else { m_body = AUTHORIZATION_HTML_401; } } else { m_body = ERRORINFO_HTML_404; } } else { m_body = AUTHORIZATION_HTML_401; } char a[1024]; _parse_parameter("&id=10&pwd=中文", "pwd", a); Send(m_body.GetString(), m_body.GetLength()); } void FtpWebAction::_handle_specialstr(char* str ) { //// int len = strlen(str) + 1; for(int i = 0; i< len; i++) { if(str[i] == '+') { str[i] = ' '; } else if(str[i] == '%') { char temp[5]; memset(temp, 0, 5); unsigned char c; sprintf(temp, "%c%c", str[i + 1], str[i + 2]); c = strtol(temp, NULL, 16); str[i] = c; for(int j = i + 3; j < len; j++) { str[j - 2] = str[j]; } len -= 2; } } } int FtpWebAction::_parse_parameter(const char* postdata,const char* keyname, char* htmlStr) { size_t i; char* p = NULL; size_t key_len = strlen(keyname); size_t postdata_len = strlen(postdata); char* szTemp = (char*)malloc(postdata_len + 1); memset(szTemp, 0, postdata_len + 1); p = (char*)strstr(postdata, keyname); if(p != NULL) { if(postdata[p - postdata + key_len] != '=') { free(szTemp); return -1; } i = 0; while(1) { if((postdata[p - postdata + key_len + i + 1] != '&') && (postdata[p - postdata + key_len + i + 1] != '/0')) { szTemp[i] = postdata[p - postdata + key_len + i + 1]; i++; } else { break; } } szTemp[i] = '/0'; } else { free(szTemp); return -1; } if((htmlStr != NULL)) { _handle_specialstr(szTemp); strcpy(htmlStr, szTemp); } else { free(szTemp); return -1; } free(szTemp); return 0; } void FtpWebAction::_format_okheader(const char* result, const char* type, int len, char* htmlStr ) { sprintf(htmlStr, HEADERMASK_HTML, result, type, len); } void FtpWebAction::_format_okheader(const char* result, const char* type, const char* len, const char* filename, char* htmlStr ) { sprintf(htmlStr, HEADERMASK_SPECIAL_HTML, result, type, filename, len); }
MiniWebserver类主要负责启动webserver
MiniWebserver.h
#ifndef _MINIWEBSERVER_H #define _MINIWEBSERVER_H #include <WinSock2.h> #include "zfqstring.h" class MiniWebserver { public: MiniWebserver(void); virtual ~MiniWebserver(void); public: void Run(unsigned short listenport, zfqstring id = "anonymous", zfqstring pwd = ""); void Stop(); protected: SOCKET m_listen; HANDLE m_stopevent; }; typedef struct { SOCKET m_sessionsocket; char m_id[30]; char m_pwd[30]; }HttpSessionHandleParam; #endif
MiniWebserver.cpp
#include "StdAfx.h" #include "MiniWebserver.h" #include "HttpSession.h" #include <process.h> static unsigned __stdcall HttpSessionHandleThread(void* lParam) { HttpSessionHandleParam* hsParam = (HttpSessionHandleParam*)lParam; HttpSession* pHS = new HttpSession(hsParam->m_sessionsocket, (zfqstring)hsParam->m_id, (zfqstring)hsParam->m_pwd); pHS->LoopResponse(); delete pHS; delete hsParam; return 0; } MiniWebserver::MiniWebserver(void):m_listen(-1),m_stopevent(0) { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); } MiniWebserver::~MiniWebserver(void) { if(m_listen) closesocket(m_listen); m_listen = -1; WSACleanup(); } void MiniWebserver::Run(unsigned short listenport, zfqstring id, zfqstring pwd) { // HANDLE m_hMutex = CreateMutex(NULL, FALSE, "MUTEX_MINIWEBSERVER"); if(GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(m_hMutex); m_hMutex = NULL; return; } // m_stopevent = CreateEvent(NULL, FALSE, FALSE,"EVENT_STOPMINIWEBSERVER"); if(!m_stopevent) return; // unsigned long flag = 1; sockaddr_in server_addr; m_listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(m_listen == INVALID_SOCKET) { return; } memset(&server_addr, 0, sizeof(sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(listenport); server_addr.sin_addr.s_addr = INADDR_ANY; if(bind(m_listen, (sockaddr*)&server_addr, sizeof(sockaddr_in)) == SOCKET_ERROR) { m_listen = -1; return; } ioctlsocket(m_listen, FIONBIO, &flag); if(listen(m_listen, 5) == SOCKET_ERROR) { closesocket(m_listen); m_listen = -1; return; } // struct fd_set fdset; struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 50000; while(WaitForSingleObject(m_stopevent, 10) != WAIT_OBJECT_0 ) { // FD_ZERO(&fdset); FD_SET(m_listen, &fdset); int ret = select(m_listen + 1, &fdset, NULL, NULL, &timeout); if( ret == 1) { if(FD_ISSET(m_listen, &fdset)) { HttpSessionHandleParam* pSH = new HttpSessionHandleParam(); pSH->m_sessionsocket = accept(m_listen, NULL, NULL); strcpy(pSH->m_id, id.GetString()); strcpy(pSH->m_pwd, pwd.GetString()); HANDLE handle; unsigned threadID; handle = (HANDLE)_beginthreadex(NULL, 0, HttpSessionHandleThread, pSH, 0, &threadID); if(handle) CloseHandle(handle); } } else if(ret < 0) break; } closesocket(m_listen); m_listen = -1; if(m_stopevent) CloseHandle(m_stopevent); return; } void MiniWebserver::Stop() { if(m_stopevent) SetEvent(m_stopevent); }
main.cpp
// miniweb.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "zfqstring.h" #include "getopt.h" #include "MiniWebserver.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { unsigned int port = 8888; zfqstring id = "anonymous"; zfqstring pwd = ""; unsigned char c; char* param = NULL; if(argc >= 2) { while((c = GetOption(argc, argv, "hi:u:p:", ¶m)) != 0) { switch(c) { case 'h': case -1: case 1: printf("User Commands:/n/ -h : For command help/n/ -i : Assign the web server port number/n/ -u : Assign the user name/n/ -p : Assign the password/n/ ----------------/n/ default port : 8888/n/ default user/pwd : anonymous//n"); return -1; case 'i': if(NULL == param) { printf("Please input the web server port number you want!/n"); return -1; } port = atoi(param); break; case 'u': if(NULL == param) { printf("Please input the user name you want!/n"); return -1; } id = param; break; case 'p': if(NULL == param) { printf("Please input the password you want!/n"); return -1; } pwd = param; break; } } } printf("Mini WebServer For Ftp is Running/n/ on port : %d/n/ user : %s/n/ pwd : %s/n", port, id.GetString(), pwd.GetString()); MiniWebserver web; web.Run(port, id, pwd); return 0; }
另外在网上找了个类似于Linux下的getopt功能的函数,在此分享
getopt.h
/////////////////////////////////////////////////////////////////////////////// // // FILE: getopt.h // // Header for the GetOption function // // COMMENTS: // /////////////////////////////////////////////////////////////////////////////// // function prototypes int GetOption (int argc, char** argv, char* pszValidOpts, char** ppszParam);
getopt.cpp
/////////////////////////////////////////////////////////////////////////////// // // FILE: getopt.cpp // // GetOption function // // FUNCTIONS: // // GetOption() - Get next command line option and parameter // // COMMENTS: // /////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include <stddef.h> #include <ctype.h> #include <string.h> #include "getopt.h" /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: GetOption() // // Get next command line option and parameter // // PARAMETERS: // // argc - count of command line arguments // argv - array of command line argument strings // pszValidOpts - string of valid, case-sensitive option characters, // a colon ':' following a given character means that // option can take a parameter // ppszParam - pointer to a pointer to a string for output // // RETURNS: // // If valid option is found, the character value of that option // is returned, and *ppszParam points to the parameter if given, // or is NULL if no param // If standalone parameter (with no option) is found, 1 is returned, // and *ppszParam points to the standalone parameter // If option is found, but it is not in the list of valid options, // -1 is returned, and *ppszParam points to the invalid argument // When end of argument list is reached, 0 is returned, and // *ppszParam is NULL // // COMMENTS: // /////////////////////////////////////////////////////////////////////////////// int GetOption ( int argc, char** argv, char* pszValidOpts, char** ppszParam) { static int iArg = 1; char chOpt; char* psz = NULL; char* pszParam = NULL; if (iArg < argc) { psz = &(argv[iArg][0]); if (*psz == '-' || *psz == '/') { // we have an option specifier chOpt = argv[iArg][1]; if (isalnum(chOpt) || ispunct(chOpt)) { // we have an option character psz = strchr(pszValidOpts, chOpt); if (psz != NULL) { // option is valid, we want to return chOpt if (psz[1] == ':') { // option can have a parameter psz = &(argv[iArg][2]); if (*psz == '/0') { // must look at next argv for param if (iArg+1 < argc) { psz = &(argv[iArg+1][0]); if (*psz == '-' || *psz == '/') { // next argv is a new option, so param // not given for current option } else { // next argv is the param iArg++; pszParam = psz; } } else { // reached end of args looking for param } } else { // param is attached to option pszParam = psz; } } else { // option is alone, has no parameter } } else { // option specified is not in list of valid options chOpt = -1; pszParam = &(argv[iArg][0]); } } else { // though option specifier was given, option character // is not alpha or was was not specified chOpt = -1; pszParam = &(argv[iArg][0]); } } else { // standalone arg given with no option specifier chOpt = 1; pszParam = &(argv[iArg][0]); } } else { // end of argument list chOpt = 0; } iArg++; *ppszParam = pszParam; return (chOpt); }
其用法注释说的很详细。