WebServer.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:18k
- #include "stdafx.h"
- #include "mplayerc.h"
- #include "resource.h"
- #include "MainFrm.h"
- #include <atlbase.h>
- #include <atlisapi.h>
- #include "WebServerSocket.h"
- #include "WebClientSocket.h"
- #include "WebServer.h"
- #include "....zlibzlib.h"
- CAtlMap<CString, CWebServer::RequestHandler, CStringElementTraits<CString> > CWebServer::m_internalpages;
- CAtlMap<CString, UINT, CStringElementTraits<CString> > CWebServer::m_downloads;
- CAtlMap<CStringA, CStringA, CStringElementTraits<CStringA> > CWebServer::m_mimes;
- CWebServer::CWebServer(CMainFrame* pMainFrame, int nPort)
- : m_pMainFrame(pMainFrame)
- , m_nPort(nPort)
- {
- if(m_internalpages.IsEmpty())
- {
- m_internalpages[_T("/")] = &CWebClientSocket::OnIndex;
- m_internalpages[_T("/index.html")] = &CWebClientSocket::OnIndex;
- m_internalpages[_T("/browser.html")] = &CWebClientSocket::OnBrowser;
- m_internalpages[_T("/controls.html")] = &CWebClientSocket::OnControls;
- m_internalpages[_T("/command.html")] = &CWebClientSocket::OnCommand;
- m_internalpages[_T("/status.html")] = &CWebClientSocket::OnStatus;
- m_internalpages[_T("/player.html")] = &CWebClientSocket::OnPlayer;
- m_internalpages[_T("/snapshot.jpg")] = &CWebClientSocket::OnSnapShotJpeg;
- m_internalpages[_T("/404.html")] = &CWebClientSocket::OnError404;
- m_internalpages[_T("/convres.html")] = &CWebClientSocket::OnConvRes;
- }
- if(m_downloads.IsEmpty())
- {
- m_downloads[_T("/default.css")] = IDF_DEFAULT_CSS;
- m_downloads[_T("/vbg.gif")] = IDF_VBR_GIF;
- m_downloads[_T("/vbs.gif")] = IDF_VBS_GIF;
- m_downloads[_T("/sliderbar.gif")] = IDF_SLIDERBAR_GIF;
- m_downloads[_T("/slidergrip.gif")] = IDF_SLIDERGRIP_GIF;
- m_downloads[_T("/sliderback.gif")] = IDF_SLIDERBACK_GIF;
- m_downloads[_T("/1pix.gif")] = IDF_1PIX_GIF;
- m_downloads[_T("/headericon.png")] = IDF_HEADERICON_PNG;
- m_downloads[_T("/headerback.png")] = IDF_HEADERBACK_PNG;
- m_downloads[_T("/headerclose.png")] = IDF_HEADERCLOSE_PNG;
- m_downloads[_T("/leftside.png")] = IDF_LEFTSIDE_PNG;
- m_downloads[_T("/rightside.png")] = IDF_RIGHTSIDE_PNG;
- m_downloads[_T("/bottomside.png")] = IDF_BOTTOMSIDE_PNG;
- m_downloads[_T("/leftbottomside.png")] = IDF_LEFTBOTTOMSIDE_PNG;
- m_downloads[_T("/rightbottomside.png")] = IDF_RIGHTBOTTOMSIDE_PNG;
- m_downloads[_T("/seekbarleft.png")] = IDF_SEEKBARLEFT_PNG;
- m_downloads[_T("/seekbarmid.png")] = IDF_SEEKBARMID_PNG;
- m_downloads[_T("/seekbarright.png")] = IDF_SEEKBARRIGHT_PNG;
- m_downloads[_T("/seekbargrip.png")] = IDF_SEEKBARGRIP_PNG;
- m_downloads[_T("/logo.png")] = IDF_LOGO_PNG;
- m_downloads[_T("/controlback.png")] = IDF_CONTROLBACK_PNG;
- m_downloads[_T("/controlbuttonplay.png")] = IDF_CONTROLBUTTONPLAY_PNG;
- m_downloads[_T("/controlbuttonpause.png")] = IDF_CONTROLBUTTONPAUSE_PNG;
- m_downloads[_T("/controlbuttonstop.png")] = IDF_CONTROLBUTTONSTOP_PNG;
- m_downloads[_T("/controlbuttonskipback.png")] = IDF_CONTROLBUTTONSKIPBACK_PNG;
- m_downloads[_T("/controlbuttondecrate.png")] = IDF_CONTROLBUTTONDECRATE_PNG;
- m_downloads[_T("/controlbuttonincrate.png")] = IDF_CONTROLBUTTONINCRATE_PNG;
- m_downloads[_T("/controlbuttonskipforward.png")] = IDF_CONTROLBUTTONSKIPFORWARD_PNG;
- m_downloads[_T("/controlbuttonstep.png")] = IDF_CONTROLBUTTONSTEP_PNG;
- m_downloads[_T("/controlvolumeon.png")] = IDF_CONTROLVOLUMEON_PNG;
- m_downloads[_T("/controlvolumeoff.png")] = IDF_CONTROLVOLUMEOFF_PNG;
- m_downloads[_T("/controlvolumebar.png")] = IDF_CONTROLVOLUMEBAR_PNG;
- m_downloads[_T("/controlvolumegrip.png")] = IDF_CONTROLVOLUMEGRIP_PNG;
- }
- CRegKey key;
- CString str(_T("MIME\Database\Content Type"));
- if(ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, str, KEY_READ))
- {
- TCHAR buff[256];
- DWORD len = countof(buff);
- for(int i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len); i++, len = countof(buff))
- {
- CRegKey mime;
- TCHAR ext[64];
- ULONG len = countof(ext);
- if(ERROR_SUCCESS == mime.Open(HKEY_CLASSES_ROOT, str + _T("\") + buff, KEY_READ)
- && ERROR_SUCCESS == mime.QueryStringValue(_T("Extension"), ext, &len))
- m_mimes[CStringA(ext).MakeLower()] = CStringA(buff).MakeLower();
- }
- }
- m_mimes[".html"] = "text/html";
- m_mimes[".txt"] = "text/plain";
- m_mimes[".css"] = "text/css";
- m_mimes[".gif"] = "image/gif";
- m_mimes[".jpeg"] = "image/jpeg";
- m_mimes[".jpg"] = "image/jpeg";
- m_mimes[".png"] = "image/png";
- GetModuleFileName(AfxGetInstanceHandle(), str.GetBuffer(MAX_PATH), MAX_PATH);
- str.ReleaseBuffer();
- m_webroot = CPath(str);
- m_webroot.RemoveFileSpec();
- CString WebRoot = AfxGetAppSettings().WebRoot;
- WebRoot.Replace('/', '\');
- WebRoot.Trim();
- CPath p(WebRoot);
- if(WebRoot.Find(_T(":\")) < 0 && WebRoot.Find(_T("\\")) < 0) m_webroot.Append(WebRoot);
- else m_webroot = p;
- m_webroot.Canonicalize();
- m_webroot.MakePretty();
- if(!m_webroot.IsDirectory()) m_webroot = CPath();
- CList<CString> sl;
- Explode(AfxGetAppSettings().WebServerCGI, sl, ';');
- POSITION pos = sl.GetHeadPosition();
- while(pos)
- {
- CList<CString> sl2;
- CString ext = Explode(sl.GetNext(pos), sl2, '=', 2);
- if(sl2.GetCount() < 2) continue;
- m_cgi[ext] = sl2.GetTail();
- }
- m_ThreadId = 0;
- m_hThread = ::CreateThread(NULL, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId);
- }
- CWebServer::~CWebServer()
- {
- if(m_hThread != NULL)
- {
- PostThreadMessage(m_ThreadId, WM_QUIT, 0, 0);
- WaitForSingleObject(m_hThread, 10000);
- EXECUTE_ASSERT(CloseHandle(m_hThread));
- }
- }
- DWORD WINAPI CWebServer::StaticThreadProc(LPVOID lpParam)
- {
- return ((CWebServer*)lpParam)->ThreadProc();
- }
- DWORD CWebServer::ThreadProc()
- {
- if(!AfxSocketInit(NULL))
- return -1;
- CWebServerSocket s(this, m_nPort);
- MSG msg;
- while((int)GetMessage(&msg, NULL, 0, 0) > 0)
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
- static void PutFileContents(LPCTSTR fn, const CStringA& data)
- {
- if(FILE* f = _tfopen(fn, _T("wb")))
- {
- fwrite((LPCSTR)data, 1, data.GetLength(), f);
- fclose(f);
- }
- }
- void CWebServer::Deploy(CString dir)
- {
- CStringA data;
- if(LoadResource(IDR_HTML_INDEX, data, RT_HTML)) PutFileContents(dir + _T("index.html"), data);
- if(LoadResource(IDR_HTML_BROWSER, data, RT_HTML)) PutFileContents(dir + _T("browser.html"), data);
- if(LoadResource(IDR_HTML_CONTROLS, data, RT_HTML)) PutFileContents(dir + _T("controls.html"), data);
- if(LoadResource(IDR_HTML_404, data, RT_HTML)) PutFileContents(dir + _T("404.html"), data);
- if(LoadResource(IDR_HTML_PLAYER, data, RT_HTML)) PutFileContents(dir + _T("player.html"), data);
- POSITION pos = m_downloads.GetStartPosition();
- while(pos)
- {
- CString fn;
- UINT id;
- m_downloads.GetNextAssoc(pos, fn, id);
- if(LoadResource(id, data, _T("FILE")))
- PutFileContents(dir + fn, data);
- }
- }
- bool CWebServer::ToLocalPath(CString& path, CString& redir)
- {
- if(!path.IsEmpty() && m_webroot.IsDirectory())
- {
- CString str = path;
- str.Replace('/', '\');
- str.TrimLeft('\');
- CPath p;
- p.Combine(m_webroot, str);
- p.Canonicalize();
- if(p.IsDirectory())
- {
- CList<CString> sl;
- Explode(AfxGetAppSettings().WebDefIndex, sl, ';');
- POSITION pos = sl.GetHeadPosition();
- while(pos)
- {
- str = sl.GetNext(pos);
- CPath p2 = p;
- p2.Append(str);
- if(p2.FileExists())
- {
- p = p2;
- redir = path;
- if(redir.GetAt(redir.GetLength()-1) != '/') redir += '/';
- redir += str;
- break;
- }
- }
- }
- if(_tcslen(p) > _tcslen(m_webroot) && p.FileExists())
- {
- path = (LPCTSTR)p;
- return true;
- }
- }
- return false;
- }
- bool CWebServer::LoadPage(UINT resid, CStringA& str, CString path)
- {
- CString redir;
- if(ToLocalPath(path, redir))
- {
- if(FILE* f = _tfopen(path, _T("rb")))
- {
- fseek(f, 0, 2);
- char* buff = str.GetBufferSetLength(ftell(f));
- fseek(f, 0, 0);
- int len = fread(buff, 1, str.GetLength(), f);
- fclose(f);
- return len == str.GetLength();
- }
- }
- return LoadResource(resid, str, RT_HTML);
- }
- void CWebServer::OnAccept(CWebServerSocket* pServer)
- {
- CAutoPtr<CWebClientSocket> p(new CWebClientSocket(this, m_pMainFrame));
- if(pServer->Accept(*p))
- {
- CString name;
- UINT port;
- if(AfxGetAppSettings().fWebServerLocalhostOnly && p->GetPeerName(name, port) && name != _T("127.0.0.1"))
- {
- p->Close();
- return;
- }
- m_clients.AddTail(p);
- }
- }
- void CWebServer::OnClose(CWebClientSocket* pClient)
- {
- POSITION pos = m_clients.GetHeadPosition();
- while(pos)
- {
- POSITION cur = pos;
- if(m_clients.GetNext(pos) == pClient)
- {
- m_clients.RemoveAt(cur);
- break;
- }
- }
- }
- void CWebServer::OnRequest(CWebClientSocket* pClient, CStringA& hdr, CStringA& body)
- {
- CPath p(pClient->m_path);
- CStringA ext = p.GetExtension().MakeLower();
- CStringA mime;
- if(ext.IsEmpty()) mime = "text/html";
- else m_mimes.Lookup(ext, mime);
- hdr = "HTTP/1.0 200 OKrn";
- bool fHandled = false, fCGI = false;
-
- if(!fHandled && m_webroot.IsDirectory())
- {
- CStringA tmphdr;
- fHandled = fCGI = CallCGI(pClient, tmphdr, body, mime);
- if(fHandled)
- {
- tmphdr.Replace("rn", "n");
- CList<CStringA> hdrlines;
- ExplodeMin(tmphdr, hdrlines, 'n');
- POSITION pos = hdrlines.GetHeadPosition();
- while(pos)
- {
- POSITION cur = pos;
- CList<CStringA> sl;
- CStringA key = Explode(hdrlines.GetNext(pos), sl, ':', 2);
- if(sl.GetCount() < 2) continue;
- key.Trim().MakeLower();
- if(key == "content-type") {mime = sl.GetTail().Trim(); hdrlines.RemoveAt(cur);}
- else if(key == "content-length") {hdrlines.RemoveAt(cur);}
- }
- tmphdr = Implode(hdrlines, 'n');
- tmphdr.Replace("n", "rn");
- hdr += tmphdr + "rn";
- }
- }
- RequestHandler rh = NULL;
- if(!fHandled && m_internalpages.Lookup(pClient->m_path, rh) && (pClient->*rh)(hdr, body, mime))
- {
- if(mime.IsEmpty()) mime = "text/html";
- CString redir;
- if(pClient->m_get.Lookup(_T("redir"), redir)
- || pClient->m_post.Lookup(_T("redir"), redir))
- {
- if(redir.IsEmpty()) redir = '/';
- hdr =
- "HTTP/1.0 302 Foundrn"
- "Location: " + CStringA(redir) + "rn";
- return;
- }
- fHandled = true;
- }
- if(!fHandled && m_webroot.IsDirectory())
- {
- fHandled = LoadPage(0, body, pClient->m_path);
- }
- UINT resid;
- CStringA res;
- if(!fHandled && m_downloads.Lookup(pClient->m_path, resid) && LoadResource(resid, res, _T("FILE")))
- {
- if(mime.IsEmpty()) mime = "application/octet-stream";
- memcpy(body.GetBufferSetLength(res.GetLength()), res.GetBuffer(), res.GetLength());
- fHandled = true;
- }
- if(!fHandled)
- {
- hdr = mime == "text/html"
- ? "HTTP/1.0 301 Moved Permanentlyrn" "Location: /404.htmlrn"
- : "HTTP/1.0 404 Not Foundrn";
- return;
- }
- if(mime == "text/html" && !fCGI)
- {
- hdr +=
- "Expires: Thu, 19 Nov 1981 08:52:00 GMTrn"
- "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0rn"
- "Pragma: no-cachern";
- CStringA debug;
- if(AfxGetAppSettings().fWebServerPrintDebugInfo)
- {
- debug += "<hr>rn";
- CString key, value;
- POSITION pos;
- pos = pClient->m_hdrlines.GetStartPosition();
- while(pos) {pClient->m_hdrlines.GetNextAssoc(pos, key, value); debug += "HEADER[" + key + "] = " + value + "<br>rn";}
- debug += "cmd: " + pClient->m_cmd + "<br>rn";
- debug += "path: " + pClient->m_path + "<br>rn";
- debug += "ver: " + pClient->m_ver + "<br>rn";
- pos = pClient->m_get.GetStartPosition();
- while(pos) {pClient->m_get.GetNextAssoc(pos, key, value); debug += "GET[" + key + "] = " + value + "<br>rn";}
- pos = pClient->m_post.GetStartPosition();
- while(pos) {pClient->m_post.GetNextAssoc(pos, key, value); debug += "POST[" + key + "] = " + value + "<br>rn";}
- pos = pClient->m_cookie.GetStartPosition();
- while(pos) {pClient->m_cookie.GetNextAssoc(pos, key, value); debug += "COOKIE[" + key + "] = " + value + "<br>rn";}
- pos = pClient->m_request.GetStartPosition();
- while(pos) {pClient->m_request.GetNextAssoc(pos, key, value); debug += "REQUEST[" + key + "] = " + value + "<br>rn";}
- }
- body.Replace("[path]", CStringA(pClient->m_path));
- body.Replace("[indexpath]", "/index.html");
- body.Replace("[commandpath]", "/command.html");
- body.Replace("[browserpath]", "/browser.html");
- body.Replace("[controlspath]", "/controls.html");
- body.Replace("[wmcname]", "wm_command");
- body.Replace("[setposcommand]", CMD_SETPOS);
- body.Replace("[setvolumecommand]", CMD_SETVOLUME);
- body.Replace("[debug]", debug);
- // TODO: add more general tags to replace
- }
- // gzip
- if(AfxGetAppSettings().fWebServerUseCompression && hdr.Find("Content-Encoding:") < 0)
- do
- {
- CString accept_encoding;
- pClient->m_hdrlines.Lookup(_T("accept-encoding"), accept_encoding);
- accept_encoding.MakeLower();
- CList<CString> sl;
- ExplodeMin(accept_encoding, sl, ',');
- if(!sl.Find(_T("gzip"))) break;;
- CHAR path[MAX_PATH], fn[MAX_PATH];
- if(!GetTempPathA(MAX_PATH, path) || !GetTempFileNameA(path, "mpc_gz", 0, fn))
- break;
- gzFile gf = gzopen(fn, "wb9");
- if(!gf || gzwrite(gf, (LPVOID)(LPCSTR)body, body.GetLength()) != body.GetLength())
- {
- if(gf) gzclose(gf);
- DeleteFileA(fn);
- break;
- }
- gzclose(gf);
- FILE* f = fopen(fn, "rb");
- if(!f) {DeleteFileA(fn); break;}
- fseek(f, 0, 2);
- CHAR* s = body.GetBufferSetLength(ftell(f));
- fseek(f, 0, 0);
- int len = fread(s, 1, body.GetLength(), f);
- ASSERT(len == body.GetLength());
- fclose(f);
- DeleteFileA(fn);
- hdr += "Content-Encoding: gziprn";
- }
- while(0);
- CStringA content;
- content.Format(
- "Content-Type: %srn"
- "Content-Length: %drn",
- mime, body.GetLength());
- hdr += content;
- }
- static DWORD WINAPI KillCGI(LPVOID lParam)
- {
- HANDLE hProcess = (HANDLE)lParam;
- if(WaitForSingleObject(hProcess, 30000) == WAIT_TIMEOUT)
- TerminateProcess(hProcess, 0);
- return 0;
- }
- bool CWebServer::CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime)
- {
- CString path = pClient->m_path, redir = path;
- if(!ToLocalPath(path, redir)) return false;
- CString ext = CPath(path).GetExtension().MakeLower();
- CPath dir(path);
- dir.RemoveFileSpec();
- CString cgi;
- if(!m_cgi.Lookup(ext, cgi) || !CPath(cgi).FileExists())
- return false;
- HANDLE hProcess = GetCurrentProcess();
- HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup = NULL;
- HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup = NULL;
- SECURITY_ATTRIBUTES saAttr;
- ZeroMemory(&saAttr, sizeof(saAttr));
- saAttr.nLength = sizeof(saAttr);
- saAttr.bInheritHandle = TRUE;
- if(CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
- {
- BOOL fSuccess = DuplicateHandle(hProcess, hChildStdoutRd, hProcess, &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
- CloseHandle(hChildStdoutRd);
- }
- if(CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
- {
- BOOL fSuccess = DuplicateHandle(hProcess, hChildStdinWr, hProcess, &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
- CloseHandle(hChildStdinWr);
- }
- STARTUPINFO siStartInfo;
- ZeroMemory(&siStartInfo, sizeof(siStartInfo));
- siStartInfo.cb = sizeof(siStartInfo);
- siStartInfo.hStdError = hChildStdoutWr;
- siStartInfo.hStdOutput = hChildStdoutWr;
- siStartInfo.hStdInput = hChildStdinRd;
- siStartInfo.dwFlags |= STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
- siStartInfo.wShowWindow = SW_HIDE;
- PROCESS_INFORMATION piProcInfo;
- ZeroMemory(&piProcInfo, sizeof(piProcInfo));
- CStringA envstr;
- if(LPVOID lpvEnv = GetEnvironmentStrings())
- {
- CString str;
- CList<CString> env;
- for(LPTSTR lpszVariable = (LPTSTR)lpvEnv; *lpszVariable; lpszVariable += _tcslen(lpszVariable)+1)
- if(lpszVariable != (LPTSTR)lpvEnv)
- env.AddTail(lpszVariable);
- env.AddTail(_T("GATEWAY_INTERFACE=CGI/1.1"));
- env.AddTail(_T("SERVER_SOFTWARE=Media Player Classic/6.4.x.y"));
- env.AddTail(_T("SERVER_PROTOCOL=") + pClient->m_ver);
- env.AddTail(_T("REQUEST_METHOD=") + pClient->m_cmd);
- env.AddTail(_T("PATH_INFO=") + redir);
- env.AddTail(_T("PATH_TRANSLATED=") + path);
- env.AddTail(_T("SCRIPT_NAME=") + redir);
- env.AddTail(_T("QUERY_STRING=") + pClient->m_query);
- if(pClient->m_hdrlines.Lookup(_T("content-type"), str))
- env.AddTail(_T("CONTENT_TYPE=") + str);
- if(pClient->m_hdrlines.Lookup(_T("content-length"), str))
- env.AddTail(_T("CONTENT_LENGTH=") + str);
- POSITION pos = pClient->m_hdrlines.GetStartPosition();
- while(pos)
- {
- CString key = pClient->m_hdrlines.GetKeyAt(pos);
- CString value = pClient->m_hdrlines.GetNextValue(pos);
- key.Replace(_T("-"), _T("_"));
- key.MakeUpper();
- env.AddTail(_T("HTTP_") + key + _T("=") + value);
- }
-
- CString name;
- UINT port;
- if(pClient->GetPeerName(name, port))
- {
- str.Format(_T("%d"), port);
- env.AddTail(_T("REMOTE_ADDR=")+name);
- env.AddTail(_T("REMOTE_HOST=")+name);
- env.AddTail(_T("REMOTE_PORT=")+str);
- }
- if(pClient->GetSockName(name, port))
- {
- str.Format(_T("%d"), port);
- env.AddTail(_T("SERVER_NAME=")+name);
- env.AddTail(_T("SERVER_PORT=")+str);
- }
- env.AddTail(_T("