#include #ifndef WX_PRECOMP #include "wx/wx.h" #endif //WX_PRECOMP #include "BaseServ.h" #include //#include #include /////////////////////////////////////////////////////////// // TDataBase /////////////////////////////////////////////////////////// class TDataBase : public wxHashTable { wxDbConnectInf m_ci; wxDb* m_db; public: bool Open(const wxString& dsn, const wxString& user, const wxString& password, const wxString& path); bool IsOpen() const; void Close(); wxDb& DataBase() { return *m_db; } TDataBase(); virtual ~TDataBase(); }; bool TDataBase::Open(const wxString& dsn, const wxString& user, const wxString& password, const wxString& path) { Close(); m_ci.SetDsn(dsn); m_ci.SetUserID(user); m_ci.SetPassword(password); m_ci.SetDefaultDir(path); if (m_ci.AllocHenv()) { m_db = ::wxDbGetConnection(&m_ci, false); // Forward only? if (m_db == NULL) m_ci.FreeHenv(); else { const wxString strLog = GetServerApp().GetLogFileName(); if (!strLog.IsEmpty()) m_db->SetSqlLogging(sqlLogON, strLog, TRUE); } } return IsOpen(); } void TDataBase::Close() { if (m_db) { m_db->SetSqlLogging(sqlLogOFF); ::wxDbFreeConnection(m_db); m_db = NULL; m_ci.FreeHenv(); } } bool TDataBase::IsOpen() const { return m_db != NULL; } TDataBase::TDataBase() : wxHashTable(wxKEY_STRING), m_db(NULL) { m_ci.Henv = 0; DeleteContents(true); } TDataBase::~TDataBase() { Close(); } /////////////////////////////////////////////////////////// // TStudy /////////////////////////////////////////////////////////// class TStudy : public wxHashTable { wxString m_strName, m_strUser, m_strPass, m_strPath; public: TDataBase& DB(long firm); // 0 = COM TStudy(const char* strName, const char* strUser, const char* strPass, const char* strPath); }; TDataBase& TStudy::DB(long firm) { TDataBase* db = (TDataBase*)Get(firm); if (db == NULL) { wxString strDsn, strPath; if (firm > 0) { strDsn.sprintf("%s%ld", m_strName, firm); strPath.sprintf("%s/%05lda", m_strPath, firm); } else { strDsn = m_strName; strPath.sprintf("%s/com", m_strPath); } db = new TDataBase; db->Open(strDsn, m_strUser, m_strPass, strPath); Put(firm, db); } return *db; } TStudy::TStudy(const char* strName, const char* strUser, const char* strPass, const char* strBasePath) : wxHashTable(wxKEY_INTEGER), m_strName(strName), m_strUser(strUser), m_strPass(strPass) { m_strPath.sprintf("%s/%s", strBasePath, strName); DeleteContents(true); } /////////////////////////////////////////////////////////// // TDataBaseServer /////////////////////////////////////////////////////////// class TDataBaseServer : public TBaseServerApp { protected: virtual const wxChar* GetAppName() const; virtual void ProcessCommand(wxString cmd, wxSocketBase& outs); virtual bool Initialization(); virtual bool Deinitialization(); protected: void AddAsterisk(const wxString& strField, const wxString& strQuery, TDataBase& db, wxArrayString& arr); wxString ParseQuery(const wxString& strOriginalQuery, TDataBase& db, wxArrayString& arr); void WriteTable(const wxString& strDsn, const wxString& strUser, const wxString& strPass, const wxString& strOriginalQuery, wxFileOutputStream& out); wxString GetSoapParam(const TXmlItem& xmlMethod, const char* strParam); void SoapProcessQuery(const TXmlItem &xmlMethod, wxFileOutputStream& out); void SoapProcessMethod(const TXmlItem& xmlMethod, wxFileOutputStream& out); public: bool IsMagicName(wxString& strFilename) const; void ProcessFormQuery(const wxString& strFileName, THashTable& hashArgs); void ProcessFormCommand(wxString cmd, wxSocketBase& outs); void ProcessSoapCommand(wxString cmd, wxSocketBase& outs); void GenerateIndex(wxString& strFilename); void GenerateSql(wxString& strFilename); void GenerateFile(wxString& strFilename); }; // Implementare almeno queste due funzioni pure virtuali const wxChar* TDataBaseServer::GetAppName() const { return "DataBase"; } bool TDataBaseServer::IsMagicName(wxString& strFilename) const { wxString strName; wxSplitPath(strFilename, NULL, &strName, NULL); strName.MakeLower(); const int q = strName.Find('?'); if (q > 0) strName.Truncate(q); if (strName == "index" || strName == "sql") { strFilename = strName; return true; } if (strName == "log") { strFilename = GetLogFileName(); } return false; } void TDataBaseServer::GenerateIndex(wxString& strFilename) { TXmlItem html; TXmlItem& body = CreatePageBody(html).AddChild("center"); TXmlItem& table = body.AddChild("table"); table.SetAttr("border", "1"); table.SetAttr("width", "70%"); TXmlItem& tr0 = body.AddChild("tr"); TXmlItem& aq = tr0.AddChild("td").AddChild("a"); aq.SetAttr("href", "sql.htm"); aq << "SQL query"; tr0.AddChild("td") << "Perform any SQL query on the selected Data Source"; TXmlItem& tr1 = body.AddChild("tr"); TXmlItem& al = tr1.AddChild("td").AddChild("a"); al.SetAttr("href", "Log"); al << "Log File"; tr1.AddChild("td") << "Display current server log"; TXmlItem& tr2 = body.AddChild("tr"); TXmlItem& as = tr2.AddChild("td").AddChild("a"); as.SetAttr("href", "stop.cgi"); as << "Stop"; tr2.AddChild("td") << "Stop this database server"; strFilename = GetTempFilename(); html.Save(strFilename); } void TDataBaseServer::GenerateSql(wxString& strFilename) { TXmlItem html; TXmlItem& body = CreatePageBody(html).AddChild("center"); TXmlItem& form = body.AddChild("form"); form.SetAttr("method", "post"); form.SetAttr("action", "Query.cgi"); TXmlItem& table = form.AddChild("table").SetAttr("width", "70%"); TXmlItem& tr0 = table.AddChild("tr"); tr0.AddChild("td") << "Data Source Name"; TXmlItem& dsn = tr0.AddChild("td").AddChild("input"); dsn.SetAttr("type", "string"); dsn.SetAttr("name", "Dsn"); dsn.SetAttr("value", GetConfigString("Dsn")); TXmlItem& tr1 = table.AddChild("tr"); tr1.AddChild("td") << "User"; TXmlItem& user = tr1.AddChild("td").AddChild("input"); user.SetAttr("type", "string"); user.SetAttr("name", "User"); user.SetAttr("value", GetConfigString("User")); TXmlItem& tr2 = table.AddChild("tr"); tr2.AddChild("td") << "Password"; TXmlItem& pass = tr2.AddChild("td").AddChild("input"); pass.SetAttr("type", "password"); pass.SetAttr("name", "User"); form.AddChild("br"); form.AddChild("h3") << "SQL query:"; TXmlItem& q = form.AddChild("textarea"); q.SetAttr("name", "Query"); q.SetAttr("cols", "80"); q.SetAttr("rows", "10"); wxString query = GetConfigString("Query"); q << query; form.AddChild("br"); form.AddChild("br"); TXmlItem& sub = form.AddChild("input"); sub.SetAttr("type", "submit"); sub.SetAttr("value", "Execute"); AddLinkButton(body, "Return to main page", "/"); strFilename = GetTempFilename(); html.Save(strFilename); } void TDataBaseServer::GenerateFile(wxString& strFilename) { wxString strName, strArgs; wxSplitPath(strFilename, NULL, &strName, NULL); strName.MakeLower(); const int q = strFilename.Find('?'); if (q > 0) strArgs = strFilename.Mid(q+1); if (strName == "index") GenerateIndex(strFilename); else if (strName == "sql") GenerateSql(strFilename); else if (strName == "log") strFilename = GetLogFileName(); } void TDataBaseServer::AddAsterisk(const wxString& strField, const wxString& strQuery, TDataBase& db, wxArrayString& arr) { wxString strTable; const int nDot = strField.Find(".*"); if (nDot < 0) { const int nFrom = strQuery.Find("FROM "); if (nFrom > 0) strTable = strQuery.Mid(nFrom+5); const int nComma = strTable.Find(','); const int nSpace = strTable.Find(' '); int nTrunc = strTable.Length(); if (nComma > 0) nTrunc = nComma; if (nSpace > 0 && nSpace < nTrunc) nTrunc = nSpace; strTable.Truncate(nTrunc); } else strTable = strField.Left(nDot); strTable.Trim(false); strTable.Trim(true); UWORD numCols; wxDbColInf* dci = db.DataBase().GetColumns(strTable, &numCols); wxString strFieldName; for (UWORD i = 0; i < numCols; i++) { if (strField == "*") strFieldName = dci[i].colName; else { strFieldName = strTable; strFieldName += "."; strFieldName += dci[i].colName; } arr.Add(strFieldName); } } wxString TDataBaseServer::ParseQuery(const wxString& strOriginalQuery, TDataBase& db, wxArrayString& arr) { wxString strQuery; const int nSelect = strOriginalQuery.Find("SELECT "); const int nFrom = strOriginalQuery.Find("FROM "); if (nSelect >= 0 && nFrom > nSelect) { wxString strFields = strOriginalQuery.Mid(nSelect+7, nFrom-nSelect-7); strFields.Trim(false); strFields.Trim(true); while(!strFields.IsEmpty()) { const int nComma = strFields.Find(','); wxString strField = nComma < 0 ? strFields : strFields.Mid(0, nComma); strField.Trim(); strField.Trim(false); if (strField.Find("*") >= 0) AddAsterisk(strField, strOriginalQuery, db, arr); else arr.Add(strField); if (nComma > 0) strFields = strFields.Mid(nComma+1); else break; } strQuery = "SELECT "; for (size_t i = 0; i < arr.GetCount(); i++) { if (i > 0) strQuery << ","; strQuery << arr[i]; } strQuery << strOriginalQuery.Mid(nFrom-1); } else strQuery = strOriginalQuery; return strQuery; } void TDataBaseServer::WriteTable(const wxString& strDsn, const wxString& strUser, const wxString& strPass, const wxString& strOriginalQuery, wxFileOutputStream& out) { const clock_t tTotalStart = clock(); clock_t tQueryTime = 0; clock_t tRetrieveTime = 0; clock_t tTotalTime = 0; size_t nRecords = 0; out << "\n"; const wxString strBasePath = GetConfigString("DataPath"); TStudy s(strDsn, strUser, strPass, strBasePath); TDataBase& d = s.DB(0); // Ditta/COM if (d.IsOpen()) { wxArrayString arr; const wxString strQuery = ParseQuery(strOriginalQuery, d, arr); wxDb& db = d.DataBase(); const clock_t tQueryStart = clock(); db.ExecSql(strQuery); tQueryTime = clock() - tQueryStart; const int nColumns = arr.GetCount(); if (nColumns > 0) { out << " \n"; for (int i = 0; i < nColumns; i++) out << " \n"; out << " \n"; const int bufsize = 33000; wxChar* buffer = new wxChar[bufsize]; const clock_t tRetrieveStart = clock(); for (nRecords = 0; db.GetNext(); nRecords++) { out << " \n"; for (int c = 1; c <= nColumns; c++) { SDWORD cb; if (db.GetData(c, SQL_C_CHAR, buffer, bufsize, &cb)) { if (strcmp(buffer, "1899-12-30") == 0) *buffer = '\0'; out << " \n"; } else break; } out << " \n"; } delete buffer; tRetrieveTime = clock() - tRetrieveStart; } } out << "
" << arr[i] << "
" << buffer << "
\n"; tTotalTime = clock() - tTotalStart; WriteLog(wxString::Format("--- %u Records. Query:%u Retrieve:%u Total:%u", nRecords, tQueryTime, tRetrieveTime, tTotalTime)); } void TDataBaseServer::ProcessFormQuery(const wxString& strFileName, THashTable& hashArgs) { const wxString strDsn = hashArgs.Get("Dsn"); const wxString strUser = hashArgs.Get("User"); const wxString strPass = hashArgs.Get("Password"); const wxString strOriginalQuery = hashArgs.Get("Query"); SetConfigString("Dsn", strDsn); SetConfigString("User", strUser); wxString strQuery = strOriginalQuery; strQuery.Replace("\r\n", " "); SetConfigString("Query", strQuery); wxFileOutputStream out(strFileName); out << "\n"; out << "\n"; WriteTable(strDsn, strUser, strPass, strOriginalQuery, out); out << "\n"; out << "\n"; } void TDataBaseServer::ProcessFormCommand(wxString cmd, wxSocketBase& outs) { const int stop = cmd.Find(" HTTP"); wxString strFileName = cmd.Mid(5, stop-5).Trim(); wxString strName, args; wxSplitPath(strFileName, NULL, &strName, NULL); const int pos = cmd.Find("\r\n\r\n"); if (pos > 0) args = cmd.Mid(pos+4); THashTable hashArgs(13); ParseArguments(args, hashArgs); strFileName = GetTempFilename(); if (strName == "Query") ProcessFormQuery(strFileName, hashArgs); SendFile(strFileName, outs); } wxString TDataBaseServer::GetSoapParam(const TXmlItem &xmlMethod, const char* strParam) { wxString val; const TXmlItem* xml = xmlMethod.FindFirst(strParam); if (xml != NULL) val = xml->GetEnclosedText(); return val; } void TDataBaseServer::SoapProcessQuery(const TXmlItem &xmlMethod, wxFileOutputStream& out) { const wxString dsn = GetSoapParam(xmlMethod, "dsn"); const wxString usr = GetSoapParam(xmlMethod, "user"); const wxString pwd = GetSoapParam(xmlMethod, "password"); const wxString sql = GetSoapParam(xmlMethod, "sql"); WriteTable(dsn, usr, pwd, sql, out); } void TDataBaseServer::SoapProcessMethod(const TXmlItem &xmlMethod, wxFileOutputStream& out) { wxString str = xmlMethod.GetTag(); str << "Result"; out << "<" << str << ">\n"; if (xmlMethod.GetTag() == "m:query") SoapProcessQuery(xmlMethod, out); out << "\n"; } void TDataBaseServer::ProcessSoapCommand(wxString cmd, wxSocketBase& sock) { const wxString strFilename = GetTempFilename(); if (!strFilename.IsEmpty()) { wxFileOutputStream outf(strFilename); outf << "\n\n"; const int soapstart = cmd.Find(" 0) { const size_t soaplen = cmd.length() - soapstart; const char* buff = (const char*)cmd; buff += soapstart; wxMemoryInputStream input(buff, soaplen); TXmlItem query; if (query.Read(input)) { const TXmlItem* pxmlBody = query.FindFirst("SOAP-ENV:Body"); if (pxmlBody != NULL) for (int m = 0; ; m++) { const TXmlItem* pxmlMethod = pxmlBody->GetChild(m); if (pxmlMethod == NULL) break; if (pxmlMethod->GetTag().StartsWith("m:")) { SoapProcessMethod(*pxmlMethod, outf); } } } } outf << "\n\n"; } wxFileInputStream inf(strFilename); sock << "HTTP/1.1 200 OK\n"; sock << "Server: " << GetAppName() << "\n"; sock << "Host: " << wxGetFullHostName() << "\n"; sock << "Connection: keep-alive\n"; sock << "Content-Type: text/xml; charset=utf-8\n"; sock << "Content-Length: " << inf.GetSize() << "\n"; sock << "Date: " << wxDateTime::Now().Format("%#c") << "\n"; sock << "\n"; SendContent(inf, sock); } void TDataBaseServer::ProcessCommand(wxString cmd, wxSocketBase& outs) { if (cmd.StartsWith("GET ")) { const int stop = cmd.Find(" HTTP"); wxString str = cmd.Mid(4, stop-4).Trim(); if (str == "/") str += "index.htm"; wxString strFilename = GetDocumentRoot() + str; if (IsMagicName(strFilename)) GenerateFile(strFilename); else { const int ims = cmd.Find("If-Modified-Since: "); if (ims > 0) { const wxString strDate = cmd.Mid(ims+19, 24); wxDateTime tIms; if (tIms.ParseDateTime(strDate)) { const wxDateTime tFile = ::wxFileModificationTime(strFilename); if (tFile <= tIms) { SendNotModifiedFile(outs); return; } } } } SendFile(strFilename, outs); } else if (cmd.StartsWith("POST ")) { if (cmd.Find("SOAPAction") > 0) ProcessSoapCommand(cmd, outs); else ProcessFormCommand(cmd, outs); } } bool TDataBaseServer::Initialization() { return true; } bool TDataBaseServer::Deinitialization() { wxDbCloseConnections(); return true; } // Istanziare l'applicazione principale IMPLEMENT_APP(TDataBaseServer)