- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# WebServer.cpp

    00001 #include "stdafx.h"
    00002 #include "mplayerc.h"
    00003 #include "resource.h"
    00004 #include "MainFrm.h"
    00005 #include <atlbase.h>
    00006 #include <atlisapi.h>
    00007 #include "WebServerSocket.h"
    00008 #include "WebClientSocket.h"
    00009 #include "WebServer.h"
    00010 #include "..\..\zlib\zlib.h"
    00011
    00012 CAtlMap<CString, CWebServer::RequestHandler, CStringElementTraits<CString> > CWebServer::m_internalpages;
    00013 CAtlMap<CString, UINT, CStringElementTraits<CString> > CWebServer::m_downloads;
    00014 CAtlMap<CStringA, CStringA, CStringElementTraits<CStringA> > CWebServer::m_mimes;
    00015
    00016 CWebServer::CWebServer(CMainFrame* pMainFrame, int nPort)
    00017         : m_pMainFrame(pMainFrame)
    00018         , m_nPort(nPort)
    00019 {
    00020         if(m_internalpages.IsEmpty())
    00021         {
    00022                 m_internalpages[_T("/")] = &CWebClientSocket::OnIndex;
    00023                 m_internalpages[_T("/index.html")] = &CWebClientSocket::OnIndex;
    00024                 m_internalpages[_T("/browser.html")] = &CWebClientSocket::OnBrowser;
    00025                 m_internalpages[_T("/controls.html")] = &CWebClientSocket::OnControls;
    00026                 m_internalpages[_T("/command.html")] = &CWebClientSocket::OnCommand;
    00027                 m_internalpages[_T("/status.html")] = &CWebClientSocket::OnStatus;
    00028                 m_internalpages[_T("/player.html")] = &CWebClientSocket::OnPlayer;
    00029                 m_internalpages[_T("/snapshot.jpg")] = &CWebClientSocket::OnSnapShotJpeg;
    00030                 m_internalpages[_T("/404.html")] = &CWebClientSocket::OnError404;
    00031                 m_internalpages[_T("/convres.html")] = &CWebClientSocket::OnConvRes;
    00032         }
    00033
    00034         if(m_downloads.IsEmpty())
    00035         {
    00036                 m_downloads[_T("/default.css")] = IDF_DEFAULT_CSS;
    00037                 m_downloads[_T("/vbg.gif")] = IDF_VBR_GIF;
    00038                 m_downloads[_T("/vbs.gif")] = IDF_VBS_GIF;
    00039                 m_downloads[_T("/sliderbar.gif")] = IDF_SLIDERBAR_GIF;
    00040                 m_downloads[_T("/slidergrip.gif")] = IDF_SLIDERGRIP_GIF;
    00041                 m_downloads[_T("/sliderback.gif")] = IDF_SLIDERBACK_GIF;
    00042                 m_downloads[_T("/1pix.gif")] = IDF_1PIX_GIF;
    00043                 m_downloads[_T("/headericon.png")] = IDF_HEADERICON_PNG;
    00044                 m_downloads[_T("/headerback.png")] = IDF_HEADERBACK_PNG;
    00045                 m_downloads[_T("/headerclose.png")] = IDF_HEADERCLOSE_PNG;
    00046                 m_downloads[_T("/leftside.png")] = IDF_LEFTSIDE_PNG;
    00047                 m_downloads[_T("/rightside.png")] = IDF_RIGHTSIDE_PNG;
    00048                 m_downloads[_T("/bottomside.png")] = IDF_BOTTOMSIDE_PNG;
    00049                 m_downloads[_T("/leftbottomside.png")] = IDF_LEFTBOTTOMSIDE_PNG;
    00050                 m_downloads[_T("/rightbottomside.png")] = IDF_RIGHTBOTTOMSIDE_PNG;
    00051                 m_downloads[_T("/seekbarleft.png")] = IDF_SEEKBARLEFT_PNG;
    00052                 m_downloads[_T("/seekbarmid.png")] = IDF_SEEKBARMID_PNG;
    00053                 m_downloads[_T("/seekbarright.png")] = IDF_SEEKBARRIGHT_PNG;
    00054                 m_downloads[_T("/seekbargrip.png")] = IDF_SEEKBARGRIP_PNG;
    00055                 m_downloads[_T("/logo.png")] = IDF_LOGO_PNG;
    00056                 m_downloads[_T("/controlback.png")] = IDF_CONTROLBACK_PNG;
    00057                 m_downloads[_T("/controlbuttonplay.png")] = IDF_CONTROLBUTTONPLAY_PNG;
    00058                 m_downloads[_T("/controlbuttonpause.png")] = IDF_CONTROLBUTTONPAUSE_PNG;
    00059                 m_downloads[_T("/controlbuttonstop.png")] = IDF_CONTROLBUTTONSTOP_PNG;
    00060                 m_downloads[_T("/controlbuttonskipback.png")] = IDF_CONTROLBUTTONSKIPBACK_PNG;
    00061                 m_downloads[_T("/controlbuttondecrate.png")] = IDF_CONTROLBUTTONDECRATE_PNG;
    00062                 m_downloads[_T("/controlbuttonincrate.png")] = IDF_CONTROLBUTTONINCRATE_PNG;
    00063                 m_downloads[_T("/controlbuttonskipforward.png")] = IDF_CONTROLBUTTONSKIPFORWARD_PNG;
    00064                 m_downloads[_T("/controlbuttonstep.png")] = IDF_CONTROLBUTTONSTEP_PNG;
    00065                 m_downloads[_T("/controlvolumeon.png")] = IDF_CONTROLVOLUMEON_PNG;
    00066                 m_downloads[_T("/controlvolumeoff.png")] = IDF_CONTROLVOLUMEOFF_PNG;
    00067                 m_downloads[_T("/controlvolumebar.png")] = IDF_CONTROLVOLUMEBAR_PNG;
    00068                 m_downloads[_T("/controlvolumegrip.png")] = IDF_CONTROLVOLUMEGRIP_PNG;
    00069         }
    00070
    00071         CRegKey key;
    00072         CString str(_T("MIME\\Database\\Content Type"));
    00073         if(ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, str, KEY_READ))
    00074         {
    00075                 TCHAR buff[256];
    00076                 DWORD len = countof(buff);
    00077                 for(int i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len); i++, len = countof(buff))
    00078                 {
    00079                         CRegKey mime;
    00080                         TCHAR ext[64];
    00081                         ULONG len = countof(ext);
    00082                         if(ERROR_SUCCESS == mime.Open(HKEY_CLASSES_ROOT, str + _T("\\") + buff, KEY_READ)
    00083                         && ERROR_SUCCESS == mime.QueryStringValue(_T("Extension"), ext, &len))
    00084                                 m_mimes[CStringA(ext).MakeLower()] = CStringA(buff).MakeLower();
    00085                 }
    00086         }
    00087
    00088         m_mimes[".html"] = "text/html";
    00089         m_mimes[".txt"] = "text/plain";
    00090         m_mimes[".css"] = "text/css";
    00091         m_mimes[".gif"] = "image/gif";
    00092         m_mimes[".jpeg"] = "image/jpeg";
    00093         m_mimes[".jpg"] = "image/jpeg";
    00094         m_mimes[".png"] = "image/png";
    00095
    00096         GetModuleFileName(AfxGetInstanceHandle(), str.GetBuffer(MAX_PATH), MAX_PATH);
    00097         str.ReleaseBuffer();
    00098         m_webroot = CPath(str);
    00099         m_webroot.RemoveFileSpec();
    00100
    00101         CString WebRoot = AfxGetAppSettings().WebRoot;
    00102         WebRoot.Replace('/', '\\');
    00103         WebRoot.Trim();
    00104         CPath p(WebRoot);
    00105         if(WebRoot.Find(_T(":\\")) < 0 && WebRoot.Find(_T("\\\\")) < 0) m_webroot.Append(WebRoot);
    00106         else m_webroot = p;
    00107         m_webroot.Canonicalize();
    00108         m_webroot.MakePretty();
    00109         if(!m_webroot.IsDirectory()) m_webroot = CPath();
    00110
    00111         CList<CString> sl;
    00112         Explode(AfxGetAppSettings().WebServerCGI, sl, ';');
    00113         POSITION pos = sl.GetHeadPosition();
    00114         while(pos)
    00115         {
    00116                 CList<CString> sl2;
    00117                 CString ext = Explode(sl.GetNext(pos), sl2, '=', 2);
    00118                 if(sl2.GetCount() < 2) continue;
    00119                 m_cgi[ext] = sl2.GetTail();
    00120         }
    00121
    00122         m_ThreadId = 0;
    00123     m_hThread = ::CreateThread(NULL, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId);
    00124 }
    00125
    00126 CWebServer::~CWebServer()
    00127 {
    00128     if(m_hThread != NULL)
    00129         {
    00130                 PostThreadMessage(m_ThreadId, WM_QUIT, 0, 0);
    00131         WaitForSingleObject(m_hThread, 10000);
    00132         EXECUTE_ASSERT(CloseHandle(m_hThread));
    00133     }
    00134 }
    00135
    00136 DWORD WINAPI CWebServer::StaticThreadProc(LPVOID lpParam)
    00137 {
    00138         return ((CWebServer*)lpParam)->ThreadProc();
    00139 }
    00140
    00141 DWORD CWebServer::ThreadProc()
    00142 {
    00143         if(!AfxSocketInit(NULL))
    00144                 return -1;
    00145
    00146         CWebServerSocket s(this, m_nPort);
    00147
    00148         MSG msg;
    00149         while((int)GetMessage(&msg, NULL, 0, 0) > 0)
    00150         {
    00151                 TranslateMessage(&msg);
    00152                 DispatchMessage(&msg);
    00153         }
    00154
    00155         return 0;
    00156 }
    00157
    00158 static void PutFileContents(LPCTSTR fn, const CStringA& data)
    00159 {
    00160         if(FILE* f = _tfopen(fn, _T("wb")))
    00161         {
    00162                 fwrite((LPCSTR)data, 1, data.GetLength(), f);
    00163                 fclose(f);
    00164         }
    00165 }
    00166
    00167 void CWebServer::Deploy(CString dir)
    00168 {
    00169         CStringA data;
    00170         if(LoadResource(IDR_HTML_INDEX, data, RT_HTML)) PutFileContents(dir + _T("index.html"), data);
    00171         if(LoadResource(IDR_HTML_BROWSER, data, RT_HTML)) PutFileContents(dir + _T("browser.html"), data);
    00172         if(LoadResource(IDR_HTML_CONTROLS, data, RT_HTML)) PutFileContents(dir + _T("controls.html"), data);
    00173         if(LoadResource(IDR_HTML_404, data, RT_HTML)) PutFileContents(dir + _T("404.html"), data);
    00174         if(LoadResource(IDR_HTML_PLAYER, data, RT_HTML)) PutFileContents(dir + _T("player.html"), data);
    00175
    00176         POSITION pos = m_downloads.GetStartPosition();
    00177         while(pos)
    00178         {
    00179                 CString fn;
    00180                 UINT id;
    00181                 m_downloads.GetNextAssoc(pos, fn, id);
    00182                 if(LoadResource(id, data, _T("FILE")))
    00183                         PutFileContents(dir + fn, data);
    00184         }
    00185 }
    00186
    00187 bool CWebServer::ToLocalPath(CString& path, CString& redir)
    00188 {
    00189         if(!path.IsEmpty() && m_webroot.IsDirectory())
    00190         {
    00191                 CString str = path;
    00192                 str.Replace('/', '\\');
    00193                 str.TrimLeft('\\');
    00194
    00195                 CPath p;
    00196                 p.Combine(m_webroot, str);
    00197                 p.Canonicalize();
    00198
    00199                 if(p.IsDirectory())
    00200                 {
    00201                         CList<CString> sl;
    00202                         Explode(AfxGetAppSettings().WebDefIndex, sl, ';');
    00203                         POSITION pos = sl.GetHeadPosition();
    00204                         while(pos)
    00205                         {
    00206                                 str = sl.GetNext(pos);
    00207                                 CPath p2 = p;
    00208                                 p2.Append(str);
    00209                                 if(p2.FileExists())
    00210                                 {
    00211                                         p = p2;
    00212                                         redir = path;
    00213                                         if(redir.GetAt(redir.GetLength()-1) != '/') redir += '/';
    00214                                         redir += str;
    00215                                         break;
    00216                                 }
    00217                         }
    00218                 }
    00219
    00220                 if(_tcslen(p) > _tcslen(m_webroot) && p.FileExists())
    00221                 {
    00222                         path = (LPCTSTR)p;
    00223                         return true;
    00224                 }
    00225         }
    00226
    00227         return false;
    00228 }
    00229
    00230 bool CWebServer::LoadPage(UINT resid, CStringA& str, CString path)
    00231 {
    00232         CString redir;
    00233         if(ToLocalPath(path, redir))
    00234         {
    00235                 if(FILE* f = _tfopen(path, _T("rb")))
    00236                 {
    00237                         fseek(f, 0, 2);
    00238                         char* buff = str.GetBufferSetLength(ftell(f));
    00239                         fseek(f, 0, 0);
    00240                         int len = fread(buff, 1, str.GetLength(), f);
    00241                         fclose(f);
    00242                         return len == str.GetLength();
    00243                 }
    00244         }
    00245
    00246         return LoadResource(resid, str, RT_HTML);
    00247 }
    00248
    00249 void CWebServer::OnAccept(CWebServerSocket* pServer)
    00250 {
    00251         CAutoPtr<CWebClientSocket> p(new CWebClientSocket(this, m_pMainFrame));
    00252         if(pServer->Accept(*p))
    00253         {
    00254                 CString name;
    00255                 UINT port;
    00256                 if(AfxGetAppSettings().fWebServerLocalhostOnly && p->GetPeerName(name, port) && name != _T("127.0.0.1"))
    00257                 {
    00258                         p->Close();
    00259                         return;
    00260                 }
    00261
    00262                 m_clients.AddTail(p);
    00263         }
    00264 }
    00265
    00266 void CWebServer::OnClose(CWebClientSocket* pClient)
    00267 {
    00268         POSITION pos = m_clients.GetHeadPosition();
    00269         while(pos)
    00270         {
    00271                 POSITION cur = pos;
    00272                 if(m_clients.GetNext(pos) == pClient)
    00273                 {
    00274                         m_clients.RemoveAt(cur);
    00275                         break;
    00276                 }
    00277         }
    00278 }
    00279
    00280 void CWebServer::OnRequest(CWebClientSocket* pClient, CStringA& hdr, CStringA& body)
    00281 {
    00282         CPath p(pClient->m_path);
    00283         CStringA ext = p.GetExtension().MakeLower();
    00284         CStringA mime;
    00285         if(ext.IsEmpty()) mime = "text/html";
    00286         else m_mimes.Lookup(ext, mime);
    00287
    00288         hdr = "HTTP/1.0 200 OK\r\n";
    00289
    00290         bool fHandled = false, fCGI = false;
    00291
    00292         if(!fHandled && m_webroot.IsDirectory())
    00293         {
    00294                 CStringA tmphdr;
    00295                 fHandled = fCGI = CallCGI(pClient, tmphdr, body, mime);
    00296
    00297                 if(fHandled)
    00298                 {
    00299                         tmphdr.Replace("\r\n", "\n");
    00300                         CList<CStringA> hdrlines;
    00301                         ExplodeMin(tmphdr, hdrlines, '\n');
    00302                         POSITION pos = hdrlines.GetHeadPosition();
    00303                         while(pos)
    00304                         {
    00305                                 POSITION cur = pos;
    00306                                 CList<CStringA> sl;
    00307                                 CStringA key = Explode(hdrlines.GetNext(pos), sl, ':', 2);
    00308                                 if(sl.GetCount() < 2) continue;
    00309                                 key.Trim().MakeLower();
    00310                                 if(key == "content-type") {mime = sl.GetTail().Trim(); hdrlines.RemoveAt(cur);}
    00311                                 else if(key == "content-length") {hdrlines.RemoveAt(cur);}
    00312                         }
    00313                         tmphdr = Implode(hdrlines, '\n');
    00314                         tmphdr.Replace("\n", "\r\n");
    00315                         hdr += tmphdr + "\r\n";
    00316                 }
    00317         }
    00318
    00319         RequestHandler rh = NULL;
    00320         if(!fHandled && m_internalpages.Lookup(pClient->m_path, rh) && (pClient->*rh)(hdr, body, mime))
    00321         {
    00322                 if(mime.IsEmpty()) mime = "text/html";
    00323
    00324                 CString redir;
    00325                 if(pClient->m_get.Lookup(_T("redir"), redir)
    00326                 || pClient->m_post.Lookup(_T("redir"), redir))
    00327                 {
    00328                         if(redir.IsEmpty()) redir = '/';
    00329
    00330                         hdr =
    00331                                 "HTTP/1.0 302 Found\r\n"
    00332                                 "Location: " + CStringA(redir) + "\r\n";
    00333                         return;
    00334                 }
    00335
    00336                 fHandled = true;
    00337         }
    00338
    00339         if(!fHandled && m_webroot.IsDirectory())
    00340         {
    00341                 fHandled = LoadPage(0, body, pClient->m_path);
    00342         }
    00343
    00344         UINT resid;
    00345         CStringA res;
    00346         if(!fHandled && m_downloads.Lookup(pClient->m_path, resid) && LoadResource(resid, res, _T("FILE")))
    00347         {
    00348                 if(mime.IsEmpty()) mime = "application/octet-stream";
    00349                 memcpy(body.GetBufferSetLength(res.GetLength()), res.GetBuffer(), res.GetLength());
    00350                 fHandled = true;
    00351         }
    00352
    00353         if(!fHandled)
    00354         {
    00355                 hdr = mime == "text/html"
    00356                         ? "HTTP/1.0 301 Moved Permanently\r\n" "Location: /404.html\r\n"
    00357                         : "HTTP/1.0 404 Not Found\r\n";
    00358                 return;
    00359         }
    00360
    00361         if(mime == "text/html" && !fCGI)
    00362         {
    00363                 hdr +=
    00364                         "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n"
    00365                         "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n"
    00366                         "Pragma: no-cache\r\n";
    00367
    00368                 CStringA debug;
    00369                 if(AfxGetAppSettings().fWebServerPrintDebugInfo)
    00370                 {
    00371                         debug += "<hr>\r\n";
    00372                         CString key, value;
    00373                         POSITION pos;
    00374                         pos = pClient->m_hdrlines.GetStartPosition();
    00375                         while(pos) {pClient->m_hdrlines.GetNextAssoc(pos, key, value); debug += "HEADER[" + key + "] = " + value + "<br>\r\n";}
    00376                         debug += "cmd: " + pClient->m_cmd + "<br>\r\n";
    00377                         debug += "path: " + pClient->m_path + "<br>\r\n";
    00378                         debug += "ver: " + pClient->m_ver + "<br>\r\n";
    00379                         pos = pClient->m_get.GetStartPosition();
    00380                         while(pos) {pClient->m_get.GetNextAssoc(pos, key, value); debug += "GET[" + key + "] = " + value + "<br>\r\n";}
    00381                         pos = pClient->m_post.GetStartPosition();
    00382                         while(pos) {pClient->m_post.GetNextAssoc(pos, key, value); debug += "POST[" + key + "] = " + value + "<br>\r\n";}
    00383                         pos = pClient->m_cookie.GetStartPosition();
    00384                         while(pos) {pClient->m_cookie.GetNextAssoc(pos, key, value); debug += "COOKIE[" + key + "] = " + value + "<br>\r\n";}
    00385                         pos = pClient->m_request.GetStartPosition();
    00386                         while(pos) {pClient->m_request.GetNextAssoc(pos, key, value); debug += "REQUEST[" + key + "] = " + value + "<br>\r\n";}
    00387                 }
    00388
    00389                 body.Replace("[path]", CStringA(pClient->m_path));
    00390                 body.Replace("[indexpath]", "/index.html");
    00391                 body.Replace("[commandpath]", "/command.html");
    00392                 body.Replace("[browserpath]", "/browser.html");
    00393                 body.Replace("[controlspath]", "/controls.html");
    00394                 body.Replace("[wmcname]", "wm_command");
    00395                 body.Replace("[setposcommand]", CMD_SETPOS);
    00396                 body.Replace("[setvolumecommand]", CMD_SETVOLUME);
    00397                 body.Replace("[debug]", debug);
    00398                 // TODO: add more general tags to replace
    00399         }
    00400
    00401         // gzip
    00402         if(AfxGetAppSettings().fWebServerUseCompression && hdr.Find("Content-Encoding:") < 0)
    00403         do
    00404         {
    00405                 CString accept_encoding;
    00406                 pClient->m_hdrlines.Lookup(_T("accept-encoding"), accept_encoding);
    00407                 accept_encoding.MakeLower();
    00408                 CList<CString> sl;
    00409                 ExplodeMin(accept_encoding, sl, ',');
    00410                 if(!sl.Find(_T("gzip"))) break;;
    00411
    00412                 CHAR path[MAX_PATH], fn[MAX_PATH];
    00413                 if(!GetTempPathA(MAX_PATH, path) || !GetTempFileNameA(path, "mpc_gz", 0, fn))
    00414                         break;
    00415
    00416                 gzFile gf = gzopen(fn, "wb9");
    00417                 if(!gf || gzwrite(gf, (LPVOID)(LPCSTR)body, body.GetLength()) != body.GetLength())
    00418                 {
    00419                         if(gf) gzclose(gf);
    00420                         DeleteFileA(fn);
    00421                         break;
    00422                 }
    00423                 gzclose(gf);
    00424
    00425                 FILE* f = fopen(fn, "rb");
    00426                 if(!f) {DeleteFileA(fn); break;}
    00427                 fseek(f, 0, 2);
    00428                 CHAR* s = body.GetBufferSetLength(ftell(f));
    00429                 fseek(f, 0, 0);
    00430                 int len = fread(s, 1, body.GetLength(), f);
    00431                 ASSERT(len == body.GetLength());
    00432                 fclose(f);
    00433                 DeleteFileA(fn);
    00434
    00435                 hdr += "Content-Encoding: gzip\r\n";
    00436         }
    00437         while(0);
    00438
    00439         CStringA content;
    00440         content.Format(
    00441                 "Content-Type: %s\r\n"
    00442                 "Content-Length: %d\r\n",
    00443                 mime, body.GetLength());
    00444         hdr += content;
    00445 }
    00446
    00447 static DWORD WINAPI KillCGI(LPVOID lParam)
    00448 {
    00449         HANDLE hProcess = (HANDLE)lParam;
    00450         if(WaitForSingleObject(hProcess, 30000) == WAIT_TIMEOUT)
    00451                 TerminateProcess(hProcess, 0);
    00452         return 0;
    00453 }
    00454
    00455 bool CWebServer::CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime)
    00456 {
    00457         CString path = pClient->m_path, redir = path;
    00458         if(!ToLocalPath(path, redir)) return false;
    00459         CString ext = CPath(path).GetExtension().MakeLower();
    00460         CPath dir(path);
    00461         dir.RemoveFileSpec();
    00462
    00463         CString cgi;
    00464         if(!m_cgi.Lookup(ext, cgi) || !CPath(cgi).FileExists())
    00465                 return false;
    00466
    00467         HANDLE hProcess = GetCurrentProcess();
    00468         HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup = NULL;
    00469         HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup = NULL;
    00470
    00471         SECURITY_ATTRIBUTES saAttr;
    00472         ZeroMemory(&saAttr, sizeof(saAttr));
    00473         saAttr.nLength = sizeof(saAttr);
    00474         saAttr.bInheritHandle = TRUE;
    00475
    00476         if(CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
    00477         {
    00478                 BOOL fSuccess = DuplicateHandle(hProcess, hChildStdoutRd, hProcess, &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
    00479                 CloseHandle(hChildStdoutRd);
    00480         }
    00481
    00482         if(CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
    00483         {
    00484                 BOOL fSuccess = DuplicateHandle(hProcess, hChildStdinWr, hProcess, &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
    00485                 CloseHandle(hChildStdinWr);
    00486         }
    00487
    00488         STARTUPINFO siStartInfo;
    00489         ZeroMemory(&siStartInfo, sizeof(siStartInfo));
    00490         siStartInfo.cb = sizeof(siStartInfo);
    00491         siStartInfo.hStdError = hChildStdoutWr;
    00492         siStartInfo.hStdOutput = hChildStdoutWr;
    00493         siStartInfo.hStdInput = hChildStdinRd;
    00494         siStartInfo.dwFlags |= STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
    00495         siStartInfo.wShowWindow = SW_HIDE;
    00496
    00497         PROCESS_INFORMATION piProcInfo;
    00498         ZeroMemory(&piProcInfo, sizeof(piProcInfo));
    00499
    00500         CStringA envstr;
    00501
    00502         if(LPVOID lpvEnv = GetEnvironmentStrings())
    00503         {
    00504                 CString str;
    00505
    00506                 CList<CString> env;
    00507                 for(LPTSTR lpszVariable = (LPTSTR)lpvEnv; *lpszVariable; lpszVariable += _tcslen(lpszVariable)+1)
    00508                         if(lpszVariable != (LPTSTR)lpvEnv)
    00509                                 env.AddTail(lpszVariable);
    00510
    00511                 env.AddTail(_T("GATEWAY_INTERFACE=CGI/1.1"));
    00512                 env.AddTail(_T("SERVER_SOFTWARE=Media Player Classic/6.4.x.y"));
    00513                 env.AddTail(_T("SERVER_PROTOCOL=") + pClient->m_ver);
    00514                 env.AddTail(_T("REQUEST_METHOD=") + pClient->m_cmd);
    00515                 env.AddTail(_T("PATH_INFO=") + redir);
    00516                 env.AddTail(_T("PATH_TRANSLATED=") + path);
    00517                 env.AddTail(_T("SCRIPT_NAME=") + redir);
    00518                 env.AddTail(_T("QUERY_STRING=") + pClient->m_query);
    00519
    00520                 if(pClient->m_hdrlines.Lookup(_T("content-type"), str))
    00521                         env.AddTail(_T("CONTENT_TYPE=") + str);
    00522                 if(pClient->m_hdrlines.Lookup(_T("content-length"), str))
    00523                         env.AddTail(_T("CONTENT_LENGTH=") + str);
    00524
    00525                 POSITION pos = pClient->m_hdrlines.GetStartPosition();
    00526                 while(pos)
    00527                 {
    00528                         CString key = pClient->m_hdrlines.GetKeyAt(pos);
    00529                         CString value = pClient->m_hdrlines.GetNextValue(pos);
    00530                         key.Replace(_T("-"), _T("_"));
    00531                         key.MakeUpper();
    00532                         env.AddTail(_T("HTTP_") + key + _T("=") + value);
    00533                 }
    00534
    00535                 CString name;
    00536                 UINT port;
    00537
    00538                 if(pClient->GetPeerName(name, port))
    00539                 {
    00540                         str.Format(_T("%d"), port);
    00541                         env.AddTail(_T("REMOTE_ADDR=")+name);
    00542                         env.AddTail(_T("REMOTE_HOST=")+name);
    00543                         env.AddTail(_T("REMOTE_PORT=")+str);
    00544                 }
    00545
    00546                 if(pClient->GetSockName(name, port))
    00547                 {
    00548                         str.Format(_T("%d"), port);
    00549                         env.AddTail(_T("SERVER_NAME=")+name);
    00550                         env.AddTail(_T("SERVER_PORT=")+str);
    00551                 }
    00552
    00553                 env.AddTail(_T("\0"));
    00554
    00555                 str = Implode(env, '\0');
    00556                 envstr = CStringA(str, str.GetLength());
    00557
    00558                 FreeEnvironmentStrings((LPTSTR)lpvEnv);
    00559         }
    00560
    00561         TCHAR* cmdln = new TCHAR[32768];
    00562         _sntprintf(cmdln, 32768, _T("\"%s\" \"%s\""), cgi, path);
    00563
    00564         if(hChildStdinRd && hChildStdoutWr)
    00565         if(CreateProcess(
    00566                 NULL, cmdln, NULL, NULL, TRUE, 0,
    00567                 envstr.GetLength() ? (LPVOID)(LPCSTR)envstr : NULL,
    00568                 dir, &siStartInfo, &piProcInfo))
    00569         {
    00570                 DWORD ThreadId;
    00571                 CreateThread(NULL, 0, KillCGI, (LPVOID)piProcInfo.hProcess, 0, &ThreadId);
    00572
    00573                 static const int BUFFSIZE = 1024;
    00574                 DWORD dwRead, dwWritten = 0;
    00575
    00576                 int i = 0, len = pClient->m_data.GetLength();
    00577                 for(; i < len; i += dwWritten)
    00578                         if(!WriteFile(hChildStdinWrDup, (LPCSTR)pClient->m_data + i, min(len - i, BUFFSIZE), &dwWritten, NULL))
    00579                                 break;
    00580
    00581                 CloseHandle(hChildStdinWrDup);
    00582                 CloseHandle(hChildStdoutWr);
    00583
    00584                 body.Empty();
    00585
    00586                 CStringA buff;
    00587                 while(i == len && ReadFile(hChildStdoutRdDup, buff.GetBuffer(BUFFSIZE), BUFFSIZE, &dwRead, NULL) && dwRead)
    00588                 {
    00589                         buff.ReleaseBufferSetLength(dwRead);
    00590                         body += buff;
    00591                 }
    00592
    00593                 int hdrend = body.Find("\r\n\r\n");
    00594                 if(hdrend >= 0)
    00595                 {
    00596                         hdr = body.Left(hdrend+2);
    00597                         body = body.Mid(hdrend+4);
    00598                 }
    00599
    00600                 CloseHandle(hChildStdinRd);
    00601                 CloseHandle(hChildStdoutRdDup);
    00602
    00603                 CloseHandle(piProcInfo.hProcess);
    00604                 CloseHandle(piProcInfo.hThread);
    00605         }
    00606         else
    00607         {
    00608                 body = _T("CGI Error");
    00609         }
    00610
    00611         delete [] cmdln;
    00612
    00613         return true;
    00614 }