📄 cgiapp.cpp
字号:
/* * =========================================================================== * PRODUCTION $Log: cgiapp.cpp,v $ * PRODUCTION Revision 1000.2 2004/06/01 18:39:07 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.53 * PRODUCTION * =========================================================================== *//* $Id: cgiapp.cpp,v 1000.2 2004/06/01 18:39:07 gouriano Exp $* ===========================================================================** PUBLIC DOMAIN NOTICE* National Center for Biotechnology Information** This software/database is a "United States Government Work" under the* terms of the United States Copyright Act. It was written as part of* the author's official duties as a United States Government employee and* thus cannot be copyrighted. This software/database is freely available* to the public for use. The National Library of Medicine and the U.S.* Government have not placed any restriction on its use or reproduction.** Although all reasonable efforts have been taken to ensure the accuracy* and reliability of the software and data, the NLM and the U.S.* Government do not and cannot warrant the performance or results that* may be obtained by using this software or data. The NLM and the U.S.* Government disclaim all warranties, express or implied, including* warranties of performance, merchantability or fitness for any particular* purpose.** Please cite the author in any work or product based on this material.** ===========================================================================** Author: Eugene Vasilchenko, Denis Vakatov, Anatoliy Kuznetsov** File Description:* Definition CGI application class and its context class.*/#include <ncbi_pch.hpp>#include <corelib/ncbistd.hpp>#include <corelib/ncbienv.hpp>#include <corelib/ncbireg.hpp>#include <cgi/cgiapp.hpp>#include <cgi/cgictx.hpp>#ifdef NCBI_OS_UNIX# include <unistd.h>#endifBEGIN_NCBI_SCOPE///////////////////////////////////////////////////////// CCgiApplication//CCgiApplication* CCgiApplication::Instance(void){ return dynamic_cast<CCgiApplication*> (CParent::Instance());}int CCgiApplication::Run(void){ // Value to return from this method Run() int result; // Try to run as a Fast-CGI loop if ( x_RunFastCGI(&result) ) { return result; } /// Run as a plain CGI application // Make sure to restore old diagnostic state after the Run() CDiagRestorer diag_restorer; // Compose diagnostics prefix#if defined(NCBI_OS_UNIX) PushDiagPostPrefix(NStr::IntToString(getpid()).c_str());#endif PushDiagPostPrefix(GetEnvironment().Get(m_DiagPrefixEnv).c_str()); // Timing CTime start_time(CTime::eCurrent); // Logging for statistics bool is_stat_log = GetConfig().GetBool("CGI", "StatLog", false, CNcbiRegistry::eReturn); auto_ptr<CCgiStatistics> stat(is_stat_log ? CreateStat() : 0); // Logging ELogOpt logopt = GetLogOpt(); if (logopt == eLog) { x_LogPost("(CGI) CCgiApplication::Run ", 0, start_time, &GetEnvironment(), fBegin); } try { _TRACE("(CGI) CCgiApplication::Run: calling ProcessRequest"); m_Context.reset( CreateContext() ); ConfigureDiagnostics(*m_Context); x_AddLBCookie(); result = ProcessRequest(*m_Context); _TRACE("CCgiApplication::Run: flushing"); m_Context->GetResponse().Flush(); _TRACE("CCgiApplication::Run: return " << result); } catch (exception& e) { // Call the exception handler and set the CGI exit code result = OnException(e, NcbiCout); // Logging {{ string msg = "(CGI) CCgiApplication::ProcessRequest() failed: "; msg += e.what(); if (logopt != eNoLog) { x_LogPost(msg.c_str(), 0, start_time, 0, fBegin|fEnd); } else { ERR_POST(msg); // Post error notification even if no logging } if ( is_stat_log ) { stat->Reset(start_time, result, &e); msg = stat->Compose(); stat->Submit(msg); } }} // Exception reporting {{ CException* ex = dynamic_cast<CException*> (&e); if ( ex ) { NCBI_RETHROW_SAME((*ex), "(CGI) CCgiApplication::Run"); } }} } // Logging if (logopt == eLog) { x_LogPost("(plain CGI) CCgiApplication::Run ", 0, start_time, 0, fEnd); } if ( is_stat_log ) { stat->Reset(start_time, result); string msg = stat->Compose(); stat->Submit(msg); } return result;}CCgiContext& CCgiApplication::x_GetContext( void ) const{ if ( !m_Context.get() ) { ERR_POST("CCgiApplication::GetContext: no context set"); throw runtime_error("no context set"); } return *m_Context;}CNcbiResource& CCgiApplication::x_GetResource( void ) const{ if ( !m_Resource.get() ) { ERR_POST("CCgiApplication::GetResource: no resource set"); throw runtime_error("no resource set"); } return *m_Resource;}void CCgiApplication::Init(void){ // Disable background reporting by default CException::EnableBackgroundReporting(false); // Convert multi-line diagnostic messages into one-line ones by default SetDiagPostFlag(eDPF_PreMergeLines); SetDiagPostFlag(eDPF_MergeLines); CParent::Init(); m_Resource.reset(LoadResource()); m_DiagPrefixEnv = GetConfig().Get("CGI", "DiagPrefixEnv");}void CCgiApplication::Exit(void){ m_Resource.reset(0); CParent::Exit();}CNcbiResource* CCgiApplication::LoadResource(void){ return 0;}CCgiServerContext* CCgiApplication::LoadServerContext(CCgiContext& /*context*/){ return 0;}CCgiContext* CCgiApplication::CreateContext(CNcbiArguments* args, CNcbiEnvironment* env, CNcbiIstream* inp, CNcbiOstream* out, int ifd, int ofd){ int errbuf_size = GetConfig().GetInt("CGI", "RequestErrBufSize", 256, CNcbiRegistry::eReturn); return new CCgiContext(*this, args, env, inp, out, ifd, ofd, (errbuf_size >= 0) ? (size_t) errbuf_size : 256, m_RequestFlags);}void CCgiApplication::SetCafService(CCookieAffinity* caf){ m_Caf.reset(caf);}// Flexible diagnostics support//class CStderrDiagFactory : public CDiagFactory{public: virtual CDiagHandler* New(const string&) { return new CStreamDiagHandler(&NcbiCerr); }};class CAsBodyDiagFactory : public CDiagFactory{public: CAsBodyDiagFactory(CCgiApplication* app) : m_App(app) {} virtual CDiagHandler* New(const string&) { CCgiResponse& response = m_App->GetContext().GetResponse(); CDiagHandler* result = new CStreamDiagHandler(&response.out()); response.SetContentType("text/plain"); response.WriteHeader(); response.SetOutput(0); // suppress normal output return result; }private: CCgiApplication* m_App;};CCgiApplication::CCgiApplication(void) : m_HostIP(0), m_Iteration(0), m_RequestFlags(0){ DisableArgDescriptions(); RegisterDiagFactory("stderr", new CStderrDiagFactory); RegisterDiagFactory("asbody", new CAsBodyDiagFactory(this));}CCgiApplication::~CCgiApplication(void){ ITERATE (TDiagFactoryMap, it, m_DiagFactories) { delete it->second; } if ( m_HostIP ) free(m_HostIP);}int CCgiApplication::OnException(exception& e, CNcbiOstream& os){ os << "Status: 500 Error processing HTTP request" HTTP_EOL; os << "Content-Type: text/html" HTTP_EOL HTTP_EOL; os << e.what(); if ( !os.good() ) { ERR_POST("CCgiApplication::OnException() failed to send error page" " back to the client"); return -1; } return 0;}void CCgiApplication::RegisterDiagFactory(const string& key, CDiagFactory* fact){ m_DiagFactories[key] = fact;}CDiagFactory* CCgiApplication::FindDiagFactory(const string& key){ TDiagFactoryMap::const_iterator it = m_DiagFactories.find(key); if (it == m_DiagFactories.end()) return 0; return it->second;}void CCgiApplication::ConfigureDiagnostics(CCgiContext& context){ // Disable for production servers? ConfigureDiagDestination(context); ConfigureDiagThreshold(context); ConfigureDiagFormat(context);}void CCgiApplication::ConfigureDiagDestination(CCgiContext& context){ const CCgiRequest& request = context.GetRequest(); bool is_set; string dest = request.GetEntry("diag-destination", &is_set); if ( !is_set ) return; SIZE_TYPE colon = dest.find(':'); CDiagFactory* factory = FindDiagFactory(dest.substr(0, colon)); if ( factory ) { SetDiagHandler(factory->New(dest.substr(colon + 1))); }}void CCgiApplication::ConfigureDiagThreshold(CCgiContext& context){ const CCgiRequest& request = context.GetRequest(); bool is_set; string threshold = request.GetEntry("diag-threshold", &is_set); if ( !is_set ) return; if (threshold == "fatal") { SetDiagPostLevel(eDiag_Fatal); } else if (threshold == "critical") { SetDiagPostLevel(eDiag_Critical); } else if (threshold == "error") { SetDiagPostLevel(eDiag_Error); } else if (threshold == "warning") { SetDiagPostLevel(eDiag_Warning); } else if (threshold == "info") { SetDiagPostLevel(eDiag_Info); } else if (threshold == "trace") { SetDiagPostLevel(eDiag_Info); SetDiagTrace(eDT_Enable); }}void CCgiApplication::ConfigureDiagFormat(CCgiContext& context){ const CCgiRequest& request = context.GetRequest(); typedef map<string, TDiagPostFlags> TFlagMap; static TFlagMap s_FlagMap; TDiagPostFlags defaults = (eDPF_Prefix | eDPF_Severity | eDPF_ErrCode | eDPF_ErrSubCode); TDiagPostFlags new_flags = 0; bool is_set; string format = request.GetEntry("diag-format", &is_set); if ( !is_set ) return; if (s_FlagMap.empty()) { s_FlagMap["file"] = eDPF_File; s_FlagMap["path"] = eDPF_LongFilename; s_FlagMap["line"] = eDPF_Line; s_FlagMap["prefix"] = eDPF_Prefix; s_FlagMap["severity"] = eDPF_Severity; s_FlagMap["code"] = eDPF_ErrCode; s_FlagMap["subcode"] = eDPF_ErrSubCode; s_FlagMap["time"] = eDPF_DateTime; s_FlagMap["omitinfosev"] = eDPF_OmitInfoSev; s_FlagMap["all"] = eDPF_All; s_FlagMap["trace"] = eDPF_Trace; s_FlagMap["log"] = eDPF_Log; } list<string> flags; NStr::Split(format, " ", flags); ITERATE(list<string>, flag, flags) { TFlagMap::const_iterator it; if ((it = s_FlagMap.find(*flag)) != s_FlagMap.end()) { new_flags |= it->second; } else if ((*flag)[0] == '!' && ((it = s_FlagMap.find(flag->substr(1))) != s_FlagMap.end())) { new_flags &= ~(it->second); } else if (*flag == "default") { new_flags |= defaults; } } SetDiagPostAllFlags(new_flags);}CCgiApplication::ELogOpt CCgiApplication::GetLogOpt() const{ string log = GetConfig().Get("CGI", "Log"); CCgiApplication::ELogOpt logopt = eNoLog; if ((NStr::CompareNocase(log, "On") == 0) || (NStr::CompareNocase(log, "true") == 0)) { logopt = eLog; } else if (NStr::CompareNocase(log, "OnError") == 0) { logopt = eLogOnError; }#ifdef _DEBUG else if (NStr::CompareNocase(log, "OnDebug") == 0) { logopt = eLog; }#endif return logopt;}void CCgiApplication::x_LogPost(const char* msg_header, unsigned int iteration, const CTime& start_time, const CNcbiEnvironment* env, TLogPostFlags flags) const{ CNcbiOstrstream msg; const CNcbiRegistry& reg = GetConfig(); if ( msg_header ) { msg << msg_header << NcbiEndl; } if ( flags & fBegin ) { bool is_print_iter = reg.GetBool("FastCGI", "PrintIterNo", false, CNcbiRegistry::eErrPost); if ( is_print_iter ) { msg << " Iteration = " << iteration << NcbiEndl; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -