//OpenSCADA module Protocol.HTTP file: http.cpp /*************************************************************************** * Copyright (C) 2003-2025 by Roman Savochenko, <roman@oscada.org> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include <tsys.h> #include <tmess.h> #include <tmodule.h> #include <tuis.h> #include "http.h" //************************************************* //* Modul info! * #define MOD_ID "HTTP" #define MOD_NAME trS("HTTP-realization") #define MOD_TYPE SPRT_ID #define VER_TYPE SPRT_VER #define MOD_VER "3.9.4" #define AUTHORS trS("Roman Savochenko") #define DESCRIPTION trS("Provides support for the HTTP protocol for WWW-based user interfaces.") #define LICENSE "GPL2" //************************************************* PrHTTP::TProt *PrHTTP::mod; extern "C" { #ifdef MOD_INCL TModule::SAt prot_HTTP_module( int n_mod ) #else TModule::SAt module( int n_mod ) #endif { if(n_mod == 0) return TModule::SAt(MOD_ID,MOD_TYPE,VER_TYPE); return TModule::SAt(""); } #ifdef MOD_INCL TModule *prot_HTTP_attach( const TModule::SAt &AtMod, const string &source ) #else TModule *attach( const TModule::SAt &AtMod, const string &source ) #endif { if(AtMod == TModule::SAt(MOD_ID,MOD_TYPE,VER_TYPE)) return new PrHTTP::TProt(source); return NULL; } } using namespace PrHTTP; //************************************************* //* TProt * //************************************************* TProt::TProt( string name ) : TProtocol(MOD_ID), cookieLab(dataRes()), mDeny(dataRes()), mAllow(dataRes()), mTmpl(dataRes()), mTmplMainPage(dataRes()), mAllowUsersAuth(dataRes()), mAuthSessDB(dataRes()), mTAuth(DEF_AuthTime), mSpaceUID(DEF_SpaceUID), lstSesChk(0) { mod = this; modInfoMainSet(MOD_NAME, MOD_TYPE, MOD_VER, AUTHORS, DESCRIPTION, LICENSE, name); cookieLab = "oscd_UID"; mAllow = DEF_Allow; //Structure of a table of the external authentication sessions elAuth.fldAdd(new TFld("ID","Identificator",TFld::Integer,TCfg::Key)); elAuth.fldAdd(new TFld("USER","User name",TFld::String,TFld::NoFlag,i2s(limObjID_SZ).c_str())); elAuth.fldAdd(new TFld("TIME","Time of the authentication and updating",TFld::Integer,TFld::NoFlag)); elAuth.fldAdd(new TFld("ADDR","User address",TFld::String,TFld::NoFlag,"256")); elAuth.fldAdd(new TFld("AGENT","User agent",TFld::String,TFld::NoFlag,"1000")); } TProt::~TProt( ) { } string TProt::optDescr( ) { return TSYS::strMess(_( "======================= Module <%s:%s> options =======================\n" "---- Parameters of the module section '%s' of the configuration file ----\n" "AuthTime <min> Life time of the authentication session, in minutes (default 10).\n\n"), MOD_TYPE,MOD_ID,nodePath().c_str()); } void TProt::load_( ) { //Load parameters from command line //Load parameters from config-file setDeny(TBDS::genPrmGet(nodePath()+"Deny",DEF_Deny)); setAllow(TBDS::genPrmGet(nodePath()+"Allow",DEF_Allow)); setTmpl(TBDS::genPrmGet(nodePath()+"Tmpl")); setTmplMainPage(TBDS::genPrmGet(nodePath()+"TmplMainPage")); setAuthSessDB(TBDS::genPrmGet(nodePath()+"AuthSessDB")); setSpaceUID(s2i(TBDS::genPrmGet(nodePath()+"SpaceUID",i2s(DEF_SpaceUID)))); setAllowUsersAuth(TBDS::genPrmGet(nodePath()+"AllowUsersAuth")); setAuthTime(s2i(TBDS::genPrmGet(nodePath()+"AuthTime",i2s(DEF_AuthTime)))); // Load auto-login config MtxAlloc res(authM, true); XMLNode aLogNd("aLog"); try { aLogNd.load(TBDS::genPrmGet(nodePath()+"AutoLogin")); for(unsigned iN = 0, iAL = 0; iN < aLogNd.childSize(); iN++) { SAutoLogin al(aLogNd.childGet(iN)->attr("addrs"),aLogNd.childGet(iN)->attr("user")); for(iAL = 0; iAL < mALog.size() && !(mALog[iAL]==al); ++iAL) ; if(iAL >= mALog.size()) mALog.push_back(al); } } catch(...) { } } void TProt::save_( ) { TBDS::genPrmSet(nodePath()+"Deny", deny()); TBDS::genPrmSet(nodePath()+"Allow", allow()); TBDS::genPrmSet(nodePath()+"Tmpl", tmpl()); TBDS::genPrmSet(nodePath()+"TmplMainPage", tmplMainPage()); TBDS::genPrmSet(nodePath()+"AuthSessDB", authSessDB()); TBDS::genPrmSet(nodePath()+"SpaceUID", i2s(spaceUID())); TBDS::genPrmSet(nodePath()+"AllowUsersAuth",allowUsersAuth()); TBDS::genPrmSet(nodePath()+"AuthTime", i2s(authTime())); //Save auto-login config MtxAlloc res(authM, true); XMLNode aLogNd("aLog"); for(unsigned iN = 0; iN < mALog.size(); iN++) aLogNd.childAdd("it")->setAttr("addrs", mALog[iN].addrs)->setAttr("user", mALog[iN].user); TBDS::genPrmSet(nodePath()+"AutoLogin", aLogNd.save()); } TVariant TProtIn::objFuncCall( const string &iid, vector<TVariant> &prms, const string &user_lang ) { //bool setUser( string user ) - Changing the user linked to the authentication session ID. // user - user to change. if(iid == "setUser" && prms.size()) { mod->sesCheck(sesId, prms[0]); return true; } //bool pgAccess( string URL ) - Checking for page access pointed by the <URL>. // URL - URL of the checking page. if(iid == "pgAccess" && prms.size()) { TRegExp re; string rules, rule; // Check for deny rules = ((TProt&)owner()).deny(); for(int off = 0; (rule=TSYS::strLine(rules,0,&off)).size(); ) { if(rule.size() > 2 && rule[0] == '/' && rule[rule.size()-1] == '/') re.setPattern(rule.substr(1,rule.size()-2)); else re.setPattern(rule, "p"); if(re.test(prms[0].getS())) return false; } // Check for allow rules = ((TProt&)owner()).allow(); for(int off = 0; (rule=TSYS::strLine(rules,0,&off)).size(); ) { if(rule.size() > 2 && rule[0] == '/' && rule[rule.size()-1] == '/') re.setPattern(rule.substr(1,rule.size()-2)); else re.setPattern(rule, "p"); if(re.test(prms[0].getS())) return true; } return false; } //string pgCreator( string cnt, string rcode = "", string httpattrs = "Content-Type: text/html;charset={SYS}", // string htmlHeadEls = "", string forceTmplFile = "" ) - // Forming page or resource from content <cnt>, wrapped to HTTP result <rcode>, with HTTP additional attributes <httpattrs>, // HTML additional head's element <htmlHeadEls> and forced template file <forceTmplFile>. // cnt - a page or a resource (images, XML, CSS, JavaScript, ...) content; // rcode - HTTP result code, like to "200 OK"; empty value there disables addition of the HTTP header; // httpattrs - additional HTTP-attributes, mostly this is "Content-Type" which by default sets to "text/html;charset={SYS}"; // only for "Content-Type: text/html" will do wrapping to internal/service or force <forceTmplFile> HTML-template; // htmlHeadEls - an additional HTML-header's tag, it's mostly META with "Refresh" to pointed URL; // forceTmplFile - force template file for override the internal/service template by the main-page template or other. if(iid == "pgCreator" && prms.size()) { size_t extPos; string forceTmpl = (prms.size() >= 5) ? prms[4].getS() : ""; string forceTmplExt; if((extPos=forceTmpl.rfind(".")) != string::npos) { forceTmplExt = forceTmpl.substr(extPos); forceTmpl = forceTmpl.substr(0, extPos); } //bool isForceTmpl = forceTmpl.getS().size(); string cTmpl = mod->tmpl(); string cTmplExt; if((extPos=cTmpl.rfind(".")) != string::npos) { cTmplExt = cTmpl.substr(extPos); cTmpl = cTmpl.substr(0, extPos); } string lang = TSYS::strLine(user_lang, 1); // HTTP header's attributes string httpattrs = (prms.size() >= 3) ? prms[2].getS() : ""; // Setting the content type if(httpattrs.find("Content-Type") == string::npos) httpattrs = "Content-Type: text/html;charset="+Mess->charset() + (httpattrs.size()?"\x0D\x0A":"") + httpattrs; // Processing the keep alive if(KeepAlive) httpattrs = "Keep-Alive: timeout="+i2s(srcTr().at().keepAliveTm())+", max="+i2s(srcTr().at().keepAliveReqs())+"\x0D\x0A"+ "Connection: Keep-Alive" + (httpattrs.size()?"\x0D\x0A":"") + httpattrs; // Disabling the cache httpattrs = string("Cache-Control: no-cache, no-store, must-revalidate\x0D\x0A" // HTTP 1.1 "Pragma: no-cache\x0D\x0A" // HTTP 1.0 "Expires: 0") + // Proxies (httpattrs.size()?"\x0D\x0A":"") + httpattrs; string answer; if(httpattrs.find("Content-Type: text/html") != string::npos) { int hd = -1; if(forceTmpl.size() && lang.size()) hd = ::open((forceTmpl+"_"+lang+forceTmplExt).c_str(), O_RDONLY); if(hd < 0 && forceTmpl.size()) hd = ::open((forceTmpl+forceTmplExt).c_str(), O_RDONLY); if(hd < 0 && cTmpl.size() && lang.size()) hd = ::open((cTmpl+"_"+lang+cTmplExt).c_str(), O_RDONLY); if(hd < 0 && cTmpl.size()) hd = ::open((cTmpl+cTmplExt).c_str(), O_RDONLY); if(hd >= 0) { char buf[prmStrBuf_SZ]; for(int len = 0; (len=read(hd,buf,sizeof(buf))) > 0; ) answer.append(buf, len); if(::close(hd) != 0) mess_warning(nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), hd, strerror(errno), errno); if(answer.find("#####CONTEXT#####") == string::npos && !forceTmpl.size()) answer.clear(); else { try { XMLNode tree(""); tree.load(answer, true); if(prms.size() >= 4 && prms[3].getS().size()) { XMLNode *headEl = tree.childGet("head", 0, true); if(!headEl) headEl = tree.childGet("HEAD", 0, true); if(headEl) { try { headEl->childAdd("META")->load(prms[3].getS()); answer = tree.save(XMLNode::XHTMLHeader); } catch(TError &err) { mess_err(nodePath().c_str(), _("Error loading the META header '%s': %s"), err.mess.c_str(), prms[3].getS().c_str()); throw; } } else answer.clear(); } } catch(TError &err) { mess_err(nodePath().c_str(), _("Error loading the HTML template '%s' for the language '%s': %s"), (forceTmpl.size()?(forceTmpl+forceTmplExt):(cTmpl+cTmplExt)).c_str(), lang.c_str(), err.mess.c_str()); answer.clear(); } } } if(answer.empty()) { string icoNm = TSYS::pathLevEnd(SYS->ico(NULL,true), 0); answer = "<?xml version='1.0' ?>\n" "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>\n" "<html xmlns='http://www.w3.org/1999/xhtml'>\n" " <head>\n" " <meta http-equiv='Content-Type' content='text/html; charset=" + Mess->charset() + "'/>\n" + ((prms.size() >= 4) ? prms[3].getS() : "" ) + " <title>" PACKAGE_NAME ": " + trD_L(SYS->name(),lang) + " (" + SYS->id() + ")</title>\n" + (icoNm.size()?" <link rel='shortcut icon' href='/"+TSYS::strEncode(icoNm,TSYS::HttpURL)+"' type='image' />\n":"") + // " <title>" PACKAGE_NAME "!</title>\n" // " <link rel='shortcut icon' href='/" SPRT_ID "." MOD_ID ".png' type='image' />\n" " <style type='text/css'>\n" " hr { width: 95%; }\n" " p { margin: 0px; text-indent: 15px; margin-bottom: 5px; }\n" " body { background-color: #818181; margin: 0px; }\n" " div.error { width: 60%; border: 4px outset #B0B0B0; color: red; background-color: #B0B0B0; font-size: 200%; padding: 10px; }\n" " h1.head { text-align: center; color: #ffff00; }\n" " h2.title { text-align: center; font-style: italic; margin: 0px; padding: 0px; border-width: 0px; }\n" " table.work { background-color: #9999ff; border: 3px ridge #a9a9a9; padding: 2px; }\n" " table.work td { background-color:#cccccc; text-align: left; }\n" " table.work td.content { padding: 5px; padding-bottom: 20px; }\n" " table.work td.content img { vertical-align: middle; }\n" " table.work ul { list-style-image: none; list-style-type: none; margin: 0px; padding: 0px; padding-left: 20px; }\n" " </style>\n" " </head>\n" " <body>\n" " <h1 class='head'>" PACKAGE_NAME ": " + trD_L(SYS->name(),lang) + " (" + SYS->id() + ")</h1>\n" " <hr/><br/>\n" "<center>\n" CtxTmplMark "</center>\n" " <hr/>\n" " </body>\n" "</html>\n"; } size_t tmplPos = answer.find(CtxTmplMark); if(tmplPos != string::npos) answer = answer.replace(tmplPos, strlen(CtxTmplMark), prms[0].getS()); } else answer = prms[0].getS(); if(prms.size() < 2 || !prms[1].getS().size()) return answer; return "HTTP/1.1 " + prms[1].getS() + "\x0D\x0A" "Server: " + PACKAGE_STRING + "\x0D\x0A" "Accept-Ranges: bytes\x0D\x0A" "Content-Length: " + i2s(answer.size()) + "\x0D\x0A" + httpattrs + "\x0D\x0A\x0D\x0A" + answer; } return TCntrNode::objFuncCall(iid, prms, user_lang); } TProtocolIn *TProt::in_open( const string &name ) { return new TProtIn(name); } int TProt::sesOpen( const string &name, const string &srcAddr, const string &userAgent ) { int sess_id; MtxAlloc res(authM, true); //Get free identifier do{ sess_id = 1e6*((authSessTbl().size()?spaceUID():0) + (float)rand()/RAND_MAX); } while(sess_id == 0 || mAuth.find(sess_id) != mAuth.end()); //Add new session authentification mAuth[sess_id] = SAuth(name, time(NULL), srcAddr, userAgent); //Appending to the table of the external authentication sessions if(authSessTbl().size()) try { TConfig cEl(&elAuth); cEl.cfg("ID").setI(sess_id); cEl.cfg("USER").setS(name); cEl.cfg("TIME").setI(time(NULL)); cEl.cfg("ADDR").setS(srcAddr); cEl.cfg("AGENT").setS(userAgent); TBDS::dataSet(authSessTbl(), mod->nodePath()+"AuthSessions/", cEl, TBDS::NoException); } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); } return sess_id; } void TProt::sesClose( int sid ) { MtxAlloc res(authM, true); map<int,SAuth>::iterator authEl = mAuth.find(sid); if(authEl != mAuth.end()) { mess_info(nodePath().c_str(), _("Exiting the authentication for the user '%s'."), authEl->second.name.c_str()); mAuth.erase(authEl); } //Removing from the table of the external authentication sessions if(authSessTbl().size()) try { TConfig cEl(&elAuth); cEl.cfg("ID").setI(sid); TBDS::dataDel(authSessTbl(), mod->nodePath()+"AuthSessions/", cEl, TBDS::UseAllKeys|TBDS::NoException); } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); } } string TProt::sesCheck( int sid, const string &chUser ) { time_t cur_tm = time(NULL); //Checking to close of old sessions MtxAlloc res(authM, true); map<int,SAuth>::iterator authEl = mAuth.find(sid); if(cur_tm > lstSesChk+10 || (authEl == mAuth.end() && cur_tm > lstSesChk)) { // Loading all sessions into the table of the external authentication sessions if(authSessTbl().size()) try { TConfig cEl(&elAuth); for(int fldCnt = 0; TBDS::dataSeek(authSessTbl(),mod->nodePath()+"AuthSessions/",fldCnt++,cEl); ) { authEl = mAuth.find(cEl.cfg("ID").getI()); // Appending entries of the external authentication sessions if(authEl == mAuth.end() && SYS->security().at().usrPresent(cEl.cfg("USER").getS())) mAuth[cEl.cfg("ID").getI()] = SAuth(cEl.cfg("USER").getS(), cEl.cfg("TIME").getI(), cEl.cfg("ADDR").getS(), cEl.cfg("AGENT").getS()); // Removing for inconsistent duples for re-login else if(authEl != mAuth.end() && cEl.cfg("USER").getS() != authEl->second.name) { if(!TBDS::dataDel(authSessTbl(),mod->nodePath()+"AuthSessions/",cEl,TBDS::UseAllKeys|TBDS::NoException)) break; fldCnt--; } // Updating for the authentication session time else if(authEl != mAuth.end() && cEl.cfg("TIME").getI() > authEl->second.tAuth) authEl->second.tAuth = cEl.cfg("TIME").getI(); } } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); } // Checking for the time limit and closing for(authEl = mAuth.begin(); authEl != mAuth.end(); ) if(cur_tm > authEl->second.tAuth+authTime()*60) { if(authSessTbl().size()) try { TConfig cEl(&elAuth); cEl.cfg("ID").setI(authEl->first); TBDS::dataDel(authSessTbl(), mod->nodePath()+"AuthSessions/", cEl, TBDS::UseAllKeys|TBDS::NoException); } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); } mess_debug(nodePath().c_str(), _("The authentication session for the user '%s' is expired. Host: %s."), authEl->second.name.c_str(), authEl->second.addr.c_str()); mAuth.erase(authEl++); } else authEl++; lstSesChk = cur_tm; } //Checking for the session authEl = mAuth.find(sid); if(authEl != mAuth.end()) { if(chUser.size()) authEl->second.name = chUser; if(authSessTbl().size() && (cur_tm=(cur_tm/10)*10) > authEl->second.tAuth) try { TConfig cEl(&elAuth); //cEl.cfgViewAll(false); cEl.cfg("ID").setI(sid); cEl.cfg("TIME").setI(cur_tm); cEl.cfg("USER").setS(authEl->second.name); cEl.cfg("ADDR").setS(authEl->second.addr); cEl.cfg("AGENT").setS(authEl->second.agent); TBDS::dataSet(authSessTbl(), mod->nodePath()+"AuthSessions/", cEl, TBDS::NoException); } catch(TError &err) { mess_err(err.cat.c_str(), "%s", err.mess.c_str()); } authEl->second.tAuth = cur_tm; return authEl->second.name; } return ""; } string TProt::autoLogGet( const string &sender ) { string addr; MtxAlloc res(authM, true); for(unsigned iA = 0; sender.size() && iA < mALog.size(); iA++) for(int aoff = 0; (addr=TSYS::strParse(mALog[iA].addrs,0,";",&aoff)).size(); ) if(TRegExp(addr, "p").test(sender)) return mALog[iA].user; return ""; } void TProt::setAuthSessDB( const string &vl ) { mAuthSessDB = vl; modif(); cookieLab = "oscd_UID"; if(authSessTbl().empty()) cookieLab = cookieLab.getVal() + "_" + SYS->prjNm(); else if(mSpaceUID == 0) mSpaceUID = 100*(float)rand()/RAND_MAX; } void TProt::outMess( XMLNode &io, TTransportOut &tro ) { string req, resp, hostTr, tw, cnt; char buf[1000]; string host = io.attr("Host"); string uri = io.attr("URI"); bool onlyHeader = s2i(io.attr("onlyHeader")); if(uri.empty()) uri = "/"; XMLNode *nd; MtxAlloc resN(tro.reqRes(), true); try { //Getting the host address from the transport hostTr = tro.addr(); //Setting for new address if(!host.empty() && host != hostTr) { tro.stop(); tro.setAddr(host); hostTr = host; } host = hostTr; //Prepare request if(io.name() == "GET") ; else if(io.name() == "POST") { //Content process bool isCnt = false; for(unsigned cnt_c = 0; cnt_c < io.childSize(); cnt_c++) { if(io.childGet(cnt_c)->name() != "cnt") continue; cnt += "--" cntBnd "\x0D\x0A"; cnt += "Content-Disposition: form-data; name=\""+io.childGet(cnt_c)->attr("name")+"\""+ (io.childGet(cnt_c)->attr("filename").size()?"; filename=\""+io.childGet(cnt_c)->attr("filename")+"\"":"") + "\x0D\x0A"; // Place appended content properties for(unsigned ch_c = 0; ch_c < io.childGet(cnt_c)->childSize(); ch_c++) if(io.childGet(cnt_c)->childGet(ch_c)->name() == "prm") cnt += io.childGet(cnt_c)->childGet(ch_c)->attr("id")+": "+ io.childGet(cnt_c)->childGet(ch_c)->text()+"\x0D\x0A"; cnt += "\x0D\x0A"+io.childGet(cnt_c)->text()+"\x0D\x0A"; isCnt = true; } if(isCnt) { cnt += "--" cntBnd "--\x0D\x0A"; io.childAdd("prm")->setAttr("id","Content-Type")->setText("multipart/form-data; boundary=" cntBnd); } else cnt = io.text(); io.childAdd("prm")->setAttr("id","Content-Length")->setText(i2s(cnt.size())); } else throw TError(nodePath(), i2s(TError::Tr_ErrResponse)+":"+TSYS::strMess(_("Error or not supported the HTTP method '%s'."), io.name().c_str())); //Place HTTP head req = TSYS::strMess("%s %s HTTP/1.1\x0D\x0A",io.name().c_str(),uri.c_str()); // Place main HTTP properties req += TSYS::strMess("Host: %s\x0D\x0A",host.c_str()); req += "User-Agent: " PACKAGE_NAME " v" VERSION "\x0D\x0A"; // Place appended HTTP-properties for(unsigned ch_c = 0; ch_c < io.childSize(); ch_c++) if(io.childGet(ch_c)->name() == "prm") req += io.childGet(ch_c)->attr("id")+": "+io.childGet(ch_c)->text()+"\x0D\x0A"; req += "\x0D\x0A"+cnt; io.childClear(); //Start transport if(!tro.startStat()) tro.start(); //Put request int resp_len = tro.messIO(req.c_str(), req.size(), buf, sizeof(buf)); resp.assign(buf,resp_len); //Process response io.setText(""); // Parse first record int pos = 0; tw = TSYS::strLine(resp,0,&pos); string protocol = TSYS::strParse(tw, 0, " "); string rcod = TSYS::strParse(tw, 1, " "); string rstr = TSYS::strParse(tw, 2, " "); if((protocol != "HTTP/1.0" && protocol != "HTTP/1.1") || rcod.empty() || rstr.empty()) throw TError(nodePath(), i2s(TError::Tr_ErrResponse)+":"+_("Error the HTTP response")); io.setAttr("Protocol",protocol)->setAttr("RezCod",rcod)->setAttr("RezStr",rstr); //Parse parameters int c_lng = -1, ch_ln = 0; while(true) { tw = TSYS::strLine(resp, 0, &pos); if(tw.empty()) break; size_t sepPos = tw.find(":", 0); if(sepPos == 0 || sepPos == string::npos) continue; nd = io.childAdd("prm")->setAttr("id",tw.substr(0,sepPos))->setText(sTrm(tw.substr(sepPos+1))); if(c_lng == -1 && strcasecmp(nd->attr("id").c_str(),"content-length") == 0) c_lng = s2i(nd->text()); if(c_lng != -2 && strcasecmp(nd->attr("id").c_str(),"transfer-encoding") == 0 && nd->text() == "chunked") c_lng = -2; } if(onlyHeader) { tro.stop(); return; } next_ch: // Get chunk size if(c_lng == -2) { if(ch_ln) pos += ch_ln+2; tw = TSYS::strLine(resp,0,&pos); ch_ln = strtol(tw.c_str(),NULL,16); }else ch_ln = c_lng; // Wait tail while(ch_ln > 0 && ((int)(resp.size()-pos) < ch_ln || (c_lng == -2 && ((int)(resp.size()-pos) < (ch_ln+5) || resp.find("\x0D\x0A",pos+ch_ln+2) == string::npos)))) { resp_len = tro.messIO(NULL, 0, buf, sizeof(buf)); if(!resp_len) throw TError(nodePath(), i2s(TError::Tr_ErrResponse)+":"+_("Not full response.")); resp.append(buf, resp_len); } // Put body io.setText(io.text()+resp.substr(pos,ch_ln)); // Next chunk process if(c_lng == -2 && ch_ln != 0) goto next_ch; } catch(TError &err) { if(!s2i(err.mess)) err.mess = i2s(TError::Tr_ErrDevice)+":"+_("Host error: ")+err.mess; io.setAttr("err", err.mess); throw TError(nodePath(), err.mess); } io.setAttr("err",""); } void TProt::cntrCmdProc( XMLNode *opt ) { //Get page info if(opt->name() == "info") { TProtocol::cntrCmdProc(opt); if(ctrMkNode("area",opt,0,"/prm",_("Protocol"))) { if(ctrMkNode("area",opt,1,"/prm/st",_("State"))) ctrMkNode("list",opt,-1,"/prm/st/auths",_("Active authentication sessions"),R_R_R_,"root",SPRT_ID); if(ctrMkNode("area",opt,1,"/prm/cfg",_("Module options"))) { ctrMkNode("fld",opt,-1,"/prm/cfg/deny",_("Deny"),RWRWR_,"root",SPRT_ID,2, "tp","str", "rows","2"); ctrMkNode("fld",opt,-1,"/prm/cfg/allow",_("Allow"),RWRWR_,"root",SPRT_ID,2, "tp","str", "rows","2"); ctrMkNode("fld",opt,-1,"/prm/cfg/tmpl",_("HTML template"),RWRWR_,"root",SPRT_ID,3, "tp","str", "dest","sel_ed", "select","/prm/cfg/tmplList"); ctrMkNode("fld",opt,-1,"/prm/cfg/tmplMainPage",_("HTML template of the main page"),RWRWR_,"root",SPRT_ID,3, "tp","str", "dest","sel_ed", "select","/prm/cfg/tmplMainPageList"); ctrMkNode("fld",opt,-1,"/prm/cfg/authSesDB",_("DB of the active authentication sessions"),RWRWR_,"root",SPRT_ID,4, "tp","str", "dest","select", "select","/db/list:onlydb", "help",(TMess::labStor()+"\n"+ _("Set to empty to disable using the external table of the active authentication sessions.")).c_str()); if(authSessTbl().size()) ctrMkNode("fld",opt,-1,"/prm/cfg/spaceUID",_("Authentication UID generation space"),RWRWR_,"root",SPRT_ID,3,"tp","dec", "min","0", "max","100"); ctrMkNode("fld",opt,-1,"/prm/cfg/lf_tm",_("Life time of the authentication, minutes"),RWRWR_,"root",SPRT_ID,1,"tp","dec"); ctrMkNode("fld",opt,-1,"/prm/cfg/aUsers",_("List of users allowed for authentication, separated by ';'"),RWRWR_,"root",SPRT_ID,1,"tp","str"); if(ctrMkNode("table",opt,-1,"/prm/cfg/alog",_("Auto login"),RWRWR_,"root",SPRT_ID,3, "s_com","add,ins,del", "rows","3", "help",_("A list of address templates can be used for the address field, for example \"192.168.1.*;192.168.2.*\"."))) { ctrMkNode("list",opt,-1,"/prm/cfg/alog/addrs",_("Address"),RWRWR_,"root",SPRT_ID,1,"tp","str"); ctrMkNode("list",opt,-1,"/prm/cfg/alog/user",_("User"),RWRWR_,"root",SPRT_ID,3, "tp","str", "dest","select", "select","/prm/cfg/usr_ls"); } } } return; } //Process command to page string a_path = opt->attr("path"); if(a_path == "/prm/st/auths" && ctrChkNode(opt)) { MtxAlloc res(authM, true); for(map<int,SAuth>::iterator authEl = mAuth.begin(); authEl != mAuth.end(); ++authEl) opt->childAdd("el")->setText(TSYS::strMess(_("%s %s(%s), by \"%s\""), atm2s(authEl->second.tAuth).c_str(),authEl->second.name.c_str(),authEl->second.addr.c_str(),authEl->second.agent.c_str())); } else if(a_path == "/prm/cfg/deny") { if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) opt->setText(deny()); if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR)) setDeny(opt->text()); } else if(a_path == "/prm/cfg/allow") { if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) opt->setText(allow()); if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR)) setAllow(opt->text()); } else if(a_path == "/prm/cfg/tmpl") { if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) opt->setText(tmpl()); if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR)) setTmpl(opt->text()); } else if(a_path == "/prm/cfg/tmplList" && ctrChkNode(opt)) TSYS::ctrListFS(opt, tmpl(), "html;xhtml;xml;"); else if(a_path == "/prm/cfg/tmplMainPage") { if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) opt->setText(tmplMainPage()); if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR)) setTmplMainPage(opt->text()); } else if(a_path == "/prm/cfg/tmplMainPageList" && ctrChkNode(opt)) TSYS::ctrListFS(opt, tmplMainPage(), "html;xhtml;xml;"); else if(a_path == "/prm/cfg/authSesDB") { if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) opt->setText(authSessDB()); if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR)) setAuthSessDB(opt->text()); } else if(a_path == "/prm/cfg/spaceUID") { if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) opt->setText(i2s(spaceUID())); if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR)) setSpaceUID(s2i(opt->text())); } else if(a_path == "/db/list" && ctrChkNode(opt)) { TProtocol::cntrCmdProc(opt); opt->childAdd("el")->setText(""); } else if(a_path == "/prm/cfg/lf_tm") { if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) opt->setText(i2s(authTime())); if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR)) setAuthTime(s2i(opt->text())); } else if(a_path == "/prm/cfg/aUsers") { if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) opt->setText(allowUsersAuth()); if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR)) setAllowUsersAuth(opt->text()); } else if(a_path == "/prm/cfg/alog") { int idrow = s2i(opt->attr("row")); string idcol = opt->attr("col"); if(ctrChkNode(opt,"get",RWRWR_,"root",SPRT_ID,SEC_RD)) { XMLNode *n_addrs = ctrMkNode("list",opt,-1,"/prm/cfg/alog/addrs","",RWRWR_,"root",SPRT_ID); XMLNode *n_user = ctrMkNode("list",opt,-1,"/prm/cfg/alog/user","",RWRWR_,"root",SPRT_ID); MtxAlloc res(authM, true); for(unsigned iA = 0; iA < mALog.size(); iA++) { if(n_addrs) n_addrs->childAdd("el")->setText(mALog[iA].addrs); if(n_user) n_user->childAdd("el")->setText(mALog[iA].user); } return; } MtxAlloc res(authM, true); modif(); if(ctrChkNode(opt,"add",RWRWR_,"root",SPRT_ID,SEC_WR)) mALog.push_back(SAutoLogin()); else if(ctrChkNode(opt,"ins",RWRWR_,"root",SPRT_ID,SEC_WR) && (idrow >= 0 || idrow < (int)mALog.size())) mALog.insert(mALog.begin()+idrow, SAutoLogin()); else if(ctrChkNode(opt,"del",RWRWR_,"root",SPRT_ID,SEC_WR) && (idrow >= 0 || idrow < (int)mALog.size())) mALog.erase(mALog.begin()+idrow); else if(ctrChkNode(opt,"set",RWRWR_,"root",SPRT_ID,SEC_WR) && (idrow >= 0 || idrow < (int)mALog.size())) { if(idcol == "addrs")mALog[idrow].addrs = opt->text(); if(idcol == "user") mALog[idrow].user = opt->text(); } } else if(a_path == "/prm/cfg/usr_ls" && ctrChkNode(opt)) { vector<string> ls; SYS->security().at().usrList(ls); for(unsigned iL = 0; iL < ls.size(); iL++) opt->childAdd("el")->setText(ls[iL]); } else TProtocol::cntrCmdProc(opt); } //************************************************* //* TProtIn * //************************************************* #undef _ #define _(mess) mod->I18N(mess, lang().c_str()).c_str() TProtIn::TProtIn( string name ) : TProtocolIn(name), mNotFull(false), KeepAlive(false), sesId(0) { } TProtIn::~TProtIn( ) { } string TProtIn::pgCreator( const string &cnt, const string &rcode, const string &httpattrs, const string &htmlHeadEls, const string &forceTmplFile ) { vector<TVariant> prms; prms.push_back(cnt); prms.push_back(rcode); prms.push_back(httpattrs); prms.push_back(htmlHeadEls); prms.push_back(forceTmplFile); return objFuncCall("pgCreator", prms, "root\n"+lang()).getS(); } bool TProtIn::pgAccess( const string &URL ) { vector<TVariant> prms; prms.push_back(URL); return objFuncCall("pgAccess", prms, "root").getB(); } bool TProtIn::mess( const string &reqst, string &answer ) { KeepAlive = false; string req, sel, userAgent; vector<string> vars; string sender = TSYS::strLine(srcAddr(), 0); //Continue for full reqst if(mNotFull) { mBuf.append(reqst); mNotFull = false; } else mBuf = reqst; //Save request to buffer string request = mBuf; answer = ""; if(request.size() > 0) { int pos = 0; if(mess_lev() == TMess::Debug) mess_debug(nodePath().c_str(), _("Content: %d:\n%s"), request.size(), request.c_str()); //Parse first record req = TSYS::strLine(request, 0, &pos); if(req == request) { mNotFull = true; return mNotFull; } //HTTP header is not full string method = TSYS::strSepParse(req, 0, ' '); string uris = TSYS::strSepParse(req, 1, ' '); string protocol = TSYS::strSepParse(req, 2, ' '); string uri; if(!pgAccess(sender+uris)) { answer = pgCreator(TSYS::strMess("<div class='error'>Access for the URL '%s' is forbidden.</div>\n",(sender+uris).c_str()), "403 Forbidden"); return mNotFull || KeepAlive; } prms = user = brLang = prmLang = ""; //Parse parameters int c_lng = -1; while(true) { req = TSYS::strLine(request, 0, &pos); if(req.empty()) break; size_t sepPos = req.find(":", 0); if(sepPos == 0 || sepPos == string::npos) break; string var = req.substr(0, sepPos); string val = req.substr(sepPos+1); vars.push_back(req); if(strcasecmp(var.c_str(),"content-length") == 0) c_lng = s2i(val); else if(strcasecmp(var.c_str(),"user-agent") == 0) userAgent = sTrm(val); else if(strcasecmp(var.c_str(),"connection") == 0) { for(int off = 0; (sel=TSYS::strSepParse(val,0,',',&off)).size(); ) if(strcasecmp(sTrm(sel).c_str(),"keep-alive") == 0) { KeepAlive = true; break; } } else if(strcasecmp(var.c_str(),"cookie") == 0) { size_t vpos = val.find(mod->cookieLab.getVal()+"=", 0); if(vpos != string::npos) { val = val.substr(vpos+mod->cookieLab.size()+1); user = mod->sesCheck((sesId=s2i(val))); if(user.size()) userPrev = TSYS::strParse(val, 1, "-"); } } else if(strcasecmp(var.c_str(),"accept-language") == 0 && (brLang=TSYS::strTrim(TSYS::strParse(val,0,","))).size() > 2) brLang = TSYS::strParse(brLang, 0, "-"); else if(strcasecmp(var.c_str(),"oscd_lang") == 0) vars.pop_back(); } //Check content length if((c_lng >= 0 && c_lng > (int)(request.size()-pos)) || (c_lng < 0 && method == "POST")) mNotFull = true; if(mNotFull) return mNotFull; //Check protocol version if(protocol != "HTTP/1.0" && protocol != "HTTP/1.1") { answer = pgCreator("<div class='error'>Bad Request<br/>This server doesn't undersand your request.</div>\n", "400 Bad Request"); return mNotFull || KeepAlive; } //URL parameters parse size_t prmSep = uris.find("?"); if(prmSep != string::npos) { prms = uris.substr(prmSep); uris = uris.substr(0, prmSep); string sprm; for(int iprm = 1; (sprm=TSYS::strParse(prms,0,"&",&iprm)).size(); ) { prmSep = sprm.find("="); if(prmSep != string::npos && sprm.substr(0,prmSep) == "lang") prmLang = sprm.substr(prmSep+1); } } int uri_pos = 0; string name_mod = TSYS::pathLev(uris, 0, false, NULL, &uri_pos); uri = "/" + uris.substr(uri_pos); //Process the internal commands // Login if(name_mod == "login") { if(method == "GET") { answer = getAuth(uri); return mNotFull || KeepAlive; } else if(method == "POST") { map<string,string> cnt; map<string,string>::iterator cntEl; getCnt(vars, request.substr(pos), cnt); bool allowUser = true; if(cnt.find("auth_enter") != cnt.end()) { string pass; if((cntEl=cnt.find("user")) != cnt.end()) user = cntEl->second; if((cntEl=cnt.find("pass")) != cnt.end()) pass = cntEl->second; if(mod->autoLogGet(sender) == user || ((!mod->allowUsersAuth().size() || (allowUser=TRegExp("(^|;)"+user+"(;|$)").test(mod->allowUsersAuth()))) && SYS->security().at().usrPresent(user) && SYS->security().at().usrAt(user).at().auth(pass))) { string prevUser; if(sesId) { prevUser = mod->sesCheck(sesId); mod->sesClose(sesId); } if(prevUser.size() && prevUser != user) { mess_info(owner().nodePath().c_str(),_("Successful user change from '%s' to '%s'. Host: %s. User agent: %s."), prevUser.c_str(), user.c_str(), sender.c_str(), userAgent.c_str()); } else mess_info(owner().nodePath().c_str(),_("Successful authentication for the user '%s'. Host: %s. User agent: %s."), user.c_str(), sender.c_str(), userAgent.c_str()); answer = pgCreator("<h2 class='title'>"+TSYS::strMess(_("Going to the page: <b>%s</b>"),(uri+prms).c_str())+"</h2>\n", "200 OK", "Set-Cookie: "+mod->cookieLab.getVal()+"="+i2s(mod->sesOpen(user,sender,userAgent))+(prevUser.size()?"-"+prevUser:"")+"; path=/;", "<META HTTP-EQUIV='Refresh' CONTENT='0; URL="+uri+prms+"'/>"); return mNotFull || KeepAlive; } } mess_warning(owner().nodePath().c_str(), (allowUser?_("Wrong authentication of the user '%s'. Host: %s. User agent: %s."): _("The try to auth from the not allowed user '%s'. Host: %s. User agent: %s.")), user.c_str(), sender.c_str(), userAgent.c_str()); answer = getAuth(uri, _("<p style='color: #CF8122;'>Wrong authentication! Retry please.</p>")); return mNotFull || KeepAlive; } } // Logut else if(name_mod == "logout" && method == "GET") { if(sesId) mod->sesClose(sesId); answer = pgCreator("<h2 class='title'>"+TSYS::strMess(_("Going to the page: <b>%s</b>"),"/")+"</h2>\n", "200 OK", "Set-Cookie: "+mod->cookieLab.getVal()+"=0; path=/;", "<META HTTP-EQUIV='Refresh' CONTENT='0; URL=/'/>"); return mNotFull || KeepAlive; } // robots.txt else if(name_mod == "robots.txt" && method == "GET") { answer = pgCreator("User-Agent: *\nDisallow: /", "200 OK", "Content-Type: text/plain;charset=us-ascii"); return mNotFull || KeepAlive; } //Send request to the module try { AutoHD<TModule> wwwmod = SYS->ui().at().modAt(name_mod); if(wwwmod.at().modInfo("SubType") != "WWW") throw TError(nodePath(), _("No WWW subtype module found!")); if(s2i(wwwmod.at().modInfo("Auth")) && user.empty()) { // Check for auto-login user = mod->autoLogGet(sender); if(!user.empty()) { mess_info(owner().nodePath().c_str(), _("Successful automatic authentication for the user '%s'. Host: %s. User agent: %s."), user.c_str(), sender.c_str(), userAgent.c_str()); answer = pgCreator("<h2 class='title'>"+TSYS::strMess(_("Going to the page: <b>%s</b>"),(uri+prms).c_str())+"</h2>\n", "200 OK", "Set-Cookie: "+mod->cookieLab.getVal()+"="+i2s(mod->sesOpen(user,sender,userAgent))+"; path=/;", "<META HTTP-EQUIV='Refresh' CONTENT='0; URL="+uris+prms+"'/>"); } else answer = pgCreator("<h2 class='title'>"+TSYS::strMess(_("Going to the page: <b>%s</b>"),("/login/"+name_mod+uri+prms).c_str())+"</h2>\n", "200 OK", "", "<META HTTP-EQUIV='Refresh' CONTENT='0; URL=/login/"+(name_mod+uri+prms)+"'/>"); return mNotFull || KeepAlive; } vars.push_back("oscd_lang: "+lang()); // Generic request if(pos < request.size()) answer = request.substr(pos); void(TModule::*HTTP)(const string &meth, const string &uri, string &page, vector<string> &vars, const string &user, TProtocolIn *iprt); if(wwwmod.at().modFunc("void HTTP(const string&,const string&,string&,vector<string>&,const string&,TProtocolIn*);", (void (TModule::**)()) &HTTP, true)) { ((&wwwmod.at())->*HTTP)(method, uri+prms, answer, vars, user+(userPrev.size()?"\n"+userPrev:""), this); if(mess_lev() == TMess::Debug) mess_debug(nodePath().c_str(), "Request:\n%s", request.c_str()); } // Checking the metods else if(method == "GET") { void(TModule::*HttpGet)(const string &uri, string &page, const string &sender, vector<string> &vars, const string &user); //????[v1.0] Remove void(TModule::*HTTP_GET)(const string &uri, string &page, vector<string> &vars, const string &user, TProtocolIn *iprt); if(wwwmod.at().modFunc("void HTTP_GET(const string&,string&,vector<string>&,const string&,TProtocolIn*);", (void (TModule::**)()) &HTTP_GET,true)) ((&wwwmod.at())->*HTTP_GET)(uri+prms, answer, vars, user+(userPrev.size()?"\n"+userPrev:""), this); else if(wwwmod.at().modFunc("void HttpGet(const string&,string&,const string&,vector<string>&,const string&);", //????[v1.0] Remove (void (TModule::**)()) &HttpGet,true)) ((&wwwmod.at())->*HttpGet)(uri+prms, answer, sender, vars, user+(userPrev.size()?"\n"+userPrev:"")); else throw TError(nodePath().c_str(), _("No HTTP GET function in the module '%s'!"), name_mod.c_str()); if(mess_lev() == TMess::Debug) mess_debug(nodePath().c_str(), "Get content:\n%s", request.c_str()); } else if(method == "POST") { void(TModule::*HttpPost)(const string &uri, string &page, const string &sender, vector<string> &vars, const string &user); //????[v1.0] Remove void(TModule::*HTTP_POST)(const string &uri, string &page, vector<string> &vars, const string &user, TProtocolIn *iprt); if(wwwmod.at().modFunc("void HTTP_POST(const string&,string&,vector<string>&,const string&,TProtocolIn*);", (void (TModule::**)()) &HTTP_POST,true)) ((&wwwmod.at())->*HTTP_POST)(uri+prms, answer, vars, user+(userPrev.size()?"\n"+userPrev:""), this); else if(wwwmod.at().modFunc("void HttpPost(const string&,string&,const string&,vector<string>&,const string&);", //????[v1.0] Remove (void (TModule::**)()) &HttpPost,true)) ((&wwwmod.at())->*HttpPost)(uri+prms, answer, sender, vars, user+(userPrev.size()?"\n"+userPrev:"")); else throw TError(nodePath().c_str(), _("No HTTP POST function in the module '%s'!"), name_mod.c_str()); if(mess_lev() == TMess::Debug) mess_debug(nodePath().c_str(), "Post Content:\n%s", request.c_str()); } else answer = pgCreator("<div class='error'>"+TSYS::strMess(_("Method '%s' is not implemented by this server!"),method.c_str())+"</div>\n", "501 Method Not Implemented"); } catch(TError &err) { //Check to direct file request for template if(method == "GET" && mod->tmpl().size() && uris != "/") { int hd = -1; //Open file size_t tmplDirPos = mod->tmpl().rfind("/"); if((tmplDirPos != string::npos && (hd=open((mod->tmpl().substr(0,tmplDirPos)+uris).c_str(),O_RDONLY)) >= 0) || (hd=open(("./"+uris).c_str(),O_RDONLY)) >= 0) { //From current folder answer.clear(); char buf[prmStrBuf_SZ]; for(int len = 0; (len=read(hd,buf,sizeof(buf))) > 0; ) answer.append(buf,len); if(close(hd) != 0) mess_warning(nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), hd, strerror(errno), errno); //Extension process size_t ext_pos = uris.rfind("."); string fext = (ext_pos != string::npos) ? uris.substr(ext_pos+1) : ""; if(fext == "png" || fext == "jpg" || fext == "ico") answer = pgCreator(answer, "200 OK", "Content-Type: image/"+fext); else if(fext == "css" || fext == "html" || fext == "xml") answer = pgCreator(answer, "200 OK", "Content-Type: text/"+fext); else if(fext == "js") answer = pgCreator(answer, "200 OK", "Content-Type: text/javascript"); //Maybe application/javascript else answer = pgCreator("<div class='error'>Bad Request!<br/>This server doesn't undersand your request.</div>\n", "400 Bad Request"); return mNotFull || KeepAlive; } } //Check for module's icon and other images in the folder "icons/" if(method == "GET" && name_mod.rfind(".") != string::npos) { string icoTp, ico = TUIS::icoGet(TSYS::strDecode(name_mod.substr(0,name_mod.rfind(".")),TSYS::HttpURL), &icoTp); if(ico.size()) { answer = pgCreator(ico, "200 OK", "Content-Type: "+TUIS::mimeGet(name_mod,ico,"image/"+icoTp)); return mNotFull || KeepAlive; } } answer = getIndex(user, sender); } } return mNotFull || KeepAlive; } string TProtIn::lang( ) { string rez = prmLang; if(rez.empty() && user.size()) try { rez = SYS->security().at().usrAt(user).at().lang(); } catch(...) { } if(rez.empty()) rez = brLang; return rez; } string TProtIn::getIndex( const string &user, const string &sender ) { TrCtxAlloc trCtx; if(Mess->translDyn()) trCtx.hold(user+"\n"+lang()); string answer = string("<table class='work' width='50%'>\n")+ "<tr><th>"+_("Login")+"</th></tr>" "<tr><td class='content'>"; // "<p>"+_("Welcome to the Web-interfaces of OpenSCADA.")+"</p>"; if(!user.empty()) answer = answer + "<p style='color: green;'>"+TSYS::strMess(_("You are logged in as \"<b>%s</b>\"."),user.c_str())+"</p>" "<p>"+TSYS::strMess(_("Select the necessary Web-module from the list below, <a href='%s'>logout</a> or <a href='%s'>login as an another user</a>."),("/logout"+prms).c_str(),("/login"+prms).c_str())+"</p>"; else { answer = answer + "<p style='color: #CF8122;'>"+_("You are not logged in!")+"</p>" "<p>"+TSYS::strMess(_("To use some modules you must be logged in. <a href='%s'>Login now</a>."),("/login"+prms).c_str())+"</p>"; string a_log = mod->autoLogGet(sender); if(!a_log.empty()) answer += "<p>"+TSYS::strMess(_("You can auto-login from the user \"<b>%s</b>\" just selecting the module."),a_log.c_str())+"</p>"; } answer += "</td></tr>"; answer = answer + "<tr><th>"+_("Accessible web modules")+"</th></tr>\n" "<tr><td class='content'><ul>\n"; vector<string> list; owner().owner().owner().ui().at().modList(list); for(unsigned iL = 0; iL < list.size(); iL++) { AutoHD<TModule> mod = owner().owner().owner().ui().at().modAt(list[iL]); if(mod.at().modInfo("SubType") == "WWW" && pgAccess(sender+"/"+list[iL]+"/")) { string mIcoTp; TUIS::icoGet("UI."+list[iL], &mIcoTp, true); answer = answer+"<li>"+(mIcoTp.size()?"<img src='/UI."+list[iL]+"."+mIcoTp+"' height='32' width='32'/> ":"")+ "<a href='/"+list[iL]+"/"+prms+"'><span title='"+mod.at().modInfo("Description")+"'>"+mod.at().modInfo("Name")+"</span></a></li>\n"; } } return pgCreator(answer+"</ul></td></tr></table>\n", "200 OK", "", "", mod->tmplMainPage()); } string TProtIn::getAuth( const string& uri, const string &mess ) { return pgCreator(string("<table class='work'>") + "<tr><th>" + _("Login to the system") + "</th></tr>\n" "<tr><td>\n" "<form method='post' action='/login" + uri + prms + "' enctype='multipart/form-data'>\n" "<table cellpadding='3px'>\n" "<tr><td><b>" + _("User name") + "</b></td><td><input type='text' name='user' size='20'/></td></tr>\n" "<tr><td><b>" + _("Password") + "</b></td><td><input type='password' name='pass' size='20'/></td></tr>\n" "<tr><td colspan='2' style='text-align: center'><input type='submit' name='auth_enter' value='" + _("Enter") + "'/> " "<input type='reset' name='clean' value='" + _("Clean") + "'/></td></tr>" "</table>\n</form>\n" "</td></tr>" "<tr><td>" + mess + "</td></tr>" "</table>\n", "200 OK"); } void TProtIn::getCnt( const vector<string> &vars, const string &content, map<string,string> &cnt ) { //Content parse string boundary; const char *c_bound = "boundary="; const char *c_term = "\x0D\x0A"; const char *c_end = "--"; const char *c_fd = "Content-Disposition"; const char *c_name = "name=\""; for(size_t iVr = 0, pos = 0; iVr < vars.size() && boundary.empty(); iVr++) if(vars[iVr].compare(0,vars[iVr].find(":",0),"Content-Type") == 0 && (pos=vars[iVr].find(c_bound,0)) != string::npos) { pos += strlen(c_bound); boundary = vars[iVr].substr(pos,vars[iVr].size()-pos); } if(boundary.empty()) return; for(size_t pos = 0, spos = 0, i_bnd = 0; true; ) { pos = content.find(boundary, pos); if(pos == string::npos || content.compare(pos+boundary.size(),2,c_end) == 0) break; pos += boundary.size()+strlen(c_term); // Process properties and get name string p_name; while(pos < content.size()) { string c_head = content.substr(pos, content.find(c_term,pos)-pos); pos += c_head.size()+strlen(c_term); if(c_head.empty()) break; if((spos=c_head.find(":")) == string::npos) return; if(c_head.compare(0,spos,c_fd) == 0 && (i_bnd=c_head.find(c_name,spos)) != string::npos) { i_bnd += strlen(c_name); p_name = c_head.substr(i_bnd,c_head.find("\"",i_bnd)-i_bnd); } } if(pos >= content.size()) return; if(!p_name.empty()) cnt[p_name] = content.substr(pos,content.find(string(c_term)+c_end+boundary,pos)-pos); } }