cgiapp.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:26k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: cgiapp.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 18:39:07  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.53
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: cgiapp.cpp,v 1000.2 2004/06/01 18:39:07 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Author: Eugene Vasilchenko, Denis Vakatov, Anatoliy Kuznetsov
  35. *
  36. * File Description:
  37. *   Definition CGI application class and its context class.
  38. */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbistd.hpp>
  41. #include <corelib/ncbienv.hpp>
  42. #include <corelib/ncbireg.hpp>
  43. #include <cgi/cgiapp.hpp>
  44. #include <cgi/cgictx.hpp>
  45. #ifdef NCBI_OS_UNIX
  46. #  include <unistd.h>
  47. #endif
  48. BEGIN_NCBI_SCOPE
  49. ///////////////////////////////////////////////////////
  50. // CCgiApplication
  51. //
  52. CCgiApplication* CCgiApplication::Instance(void)
  53. {
  54.     return dynamic_cast<CCgiApplication*> (CParent::Instance());
  55. }
  56. int CCgiApplication::Run(void)
  57. {
  58.     // Value to return from this method Run()
  59.     int result;
  60.     // Try to run as a Fast-CGI loop
  61.     if ( x_RunFastCGI(&result) ) {
  62.         return result;
  63.     }
  64.     /// Run as a plain CGI application
  65.     // Make sure to restore old diagnostic state after the Run()
  66.     CDiagRestorer diag_restorer;
  67.     // Compose diagnostics prefix
  68. #if defined(NCBI_OS_UNIX)
  69.     PushDiagPostPrefix(NStr::IntToString(getpid()).c_str());
  70. #endif
  71.     PushDiagPostPrefix(GetEnvironment().Get(m_DiagPrefixEnv).c_str());
  72.     // Timing
  73.     CTime start_time(CTime::eCurrent);
  74.     // Logging for statistics
  75.     bool is_stat_log =
  76.         GetConfig().GetBool("CGI", "StatLog", false, CNcbiRegistry::eReturn);
  77.     auto_ptr<CCgiStatistics> stat(is_stat_log ? CreateStat() : 0);
  78.     // Logging
  79.     ELogOpt logopt = GetLogOpt();
  80.     if (logopt == eLog) {
  81.         x_LogPost("(CGI) CCgiApplication::Run ",
  82.                   0, start_time, &GetEnvironment(), fBegin);
  83.     }
  84.     try {
  85.         _TRACE("(CGI) CCgiApplication::Run: calling ProcessRequest");
  86.         m_Context.reset( CreateContext() );
  87.         ConfigureDiagnostics(*m_Context);
  88.         x_AddLBCookie();
  89.         result = ProcessRequest(*m_Context);
  90.         _TRACE("CCgiApplication::Run: flushing");
  91.         m_Context->GetResponse().Flush();
  92.         _TRACE("CCgiApplication::Run: return " << result);
  93.     }
  94.     catch (exception& e) {
  95.         // Call the exception handler and set the CGI exit code
  96.         result = OnException(e, NcbiCout);
  97.         // Logging
  98.         {{
  99.             string msg = "(CGI) CCgiApplication::ProcessRequest() failed: ";
  100.             msg += e.what();
  101.             if (logopt != eNoLog) {
  102.                 x_LogPost(msg.c_str(), 0, start_time, 0, fBegin|fEnd);
  103.             } else {
  104.                 ERR_POST(msg);  // Post error notification even if no logging
  105.             }
  106.             if ( is_stat_log ) {
  107.                 stat->Reset(start_time, result, &e);
  108.                 msg = stat->Compose();
  109.                 stat->Submit(msg);
  110.             }
  111.         }}
  112.         // Exception reporting
  113.         {{
  114.             CException* ex = dynamic_cast<CException*> (&e);
  115.             if ( ex ) {
  116.                 NCBI_RETHROW_SAME((*ex), "(CGI) CCgiApplication::Run");
  117.             }
  118.         }}
  119.     }
  120.     // Logging
  121.     if (logopt == eLog) {
  122.         x_LogPost("(plain CGI) CCgiApplication::Run ",
  123.                   0, start_time, 0, fEnd);
  124.     }
  125.     if ( is_stat_log ) {
  126.         stat->Reset(start_time, result);
  127.         string msg = stat->Compose();
  128.         stat->Submit(msg);
  129.     }
  130.     return result;
  131. }
  132. CCgiContext& CCgiApplication::x_GetContext( void ) const
  133. {
  134.     if ( !m_Context.get() ) {
  135.         ERR_POST("CCgiApplication::GetContext: no context set");
  136.         throw runtime_error("no context set");
  137.     }
  138.     return *m_Context;
  139. }
  140. CNcbiResource& CCgiApplication::x_GetResource( void ) const
  141. {
  142.     if ( !m_Resource.get() ) {
  143.         ERR_POST("CCgiApplication::GetResource: no resource set");
  144.         throw runtime_error("no resource set");
  145.     }
  146.     return *m_Resource;
  147. }
  148. void CCgiApplication::Init(void)
  149. {
  150.     // Disable background reporting by default
  151.     CException::EnableBackgroundReporting(false);
  152.     // Convert multi-line diagnostic messages into one-line ones by default
  153.     SetDiagPostFlag(eDPF_PreMergeLines);
  154.     SetDiagPostFlag(eDPF_MergeLines);
  155.     CParent::Init();
  156.     m_Resource.reset(LoadResource());
  157.     m_DiagPrefixEnv = GetConfig().Get("CGI", "DiagPrefixEnv");
  158. }
  159. void CCgiApplication::Exit(void)
  160. {
  161.     m_Resource.reset(0);
  162.     CParent::Exit();
  163. }
  164. CNcbiResource* CCgiApplication::LoadResource(void)
  165. {
  166.     return 0;
  167. }
  168. CCgiServerContext* CCgiApplication::LoadServerContext(CCgiContext& /*context*/)
  169. {
  170.     return 0;
  171. }
  172. CCgiContext* CCgiApplication::CreateContext
  173. (CNcbiArguments*   args,
  174.  CNcbiEnvironment* env,
  175.  CNcbiIstream*     inp,
  176.  CNcbiOstream*     out,
  177.  int               ifd,
  178.  int               ofd)
  179. {
  180.     int errbuf_size =
  181.         GetConfig().GetInt("CGI", "RequestErrBufSize", 256,
  182.                            CNcbiRegistry::eReturn);
  183.     return 
  184.       new CCgiContext(*this, args, env, inp, out, ifd, ofd,
  185.                      (errbuf_size >= 0) ? (size_t) errbuf_size : 256,
  186.                      m_RequestFlags);
  187. }
  188. void CCgiApplication::SetCafService(CCookieAffinity* caf)
  189. {
  190.     m_Caf.reset(caf);
  191. }
  192. // Flexible diagnostics support
  193. //
  194. class CStderrDiagFactory : public CDiagFactory
  195. {
  196. public:
  197.     virtual CDiagHandler* New(const string&) {
  198.         return new CStreamDiagHandler(&NcbiCerr);
  199.     }
  200. };
  201. class CAsBodyDiagFactory : public CDiagFactory
  202. {
  203. public:
  204.     CAsBodyDiagFactory(CCgiApplication* app) : m_App(app) {}
  205.     virtual CDiagHandler* New(const string&) {
  206.         CCgiResponse& response = m_App->GetContext().GetResponse();
  207.         CDiagHandler* result   = new CStreamDiagHandler(&response.out());
  208.         response.SetContentType("text/plain");
  209.         response.WriteHeader();
  210.         response.SetOutput(0); // suppress normal output
  211.         return result;
  212.     }
  213. private:
  214.     CCgiApplication* m_App;
  215. };
  216. CCgiApplication::CCgiApplication(void) 
  217.  : m_HostIP(0), 
  218.    m_Iteration(0),
  219.    m_RequestFlags(0)
  220. {
  221.     DisableArgDescriptions();
  222.     RegisterDiagFactory("stderr", new CStderrDiagFactory);
  223.     RegisterDiagFactory("asbody", new CAsBodyDiagFactory(this));
  224. }
  225. CCgiApplication::~CCgiApplication(void)
  226. {
  227.     ITERATE (TDiagFactoryMap, it, m_DiagFactories) {
  228.         delete it->second;
  229.     }
  230.     if ( m_HostIP )
  231.         free(m_HostIP);
  232. }
  233. int CCgiApplication::OnException(exception& e, CNcbiOstream& os)
  234. {
  235.     os << "Status: 500 Error processing HTTP request" HTTP_EOL;
  236.     os << "Content-Type: text/html" HTTP_EOL HTTP_EOL;
  237.     os << e.what();
  238.     if ( !os.good() ) {
  239.         ERR_POST("CCgiApplication::OnException() failed to send error page"
  240.                  " back to the client");
  241.         return -1;
  242.     }
  243.     return 0;
  244. }
  245. void CCgiApplication::RegisterDiagFactory(const string& key,
  246.                                           CDiagFactory* fact)
  247. {
  248.     m_DiagFactories[key] = fact;
  249. }
  250. CDiagFactory* CCgiApplication::FindDiagFactory(const string& key)
  251. {
  252.     TDiagFactoryMap::const_iterator it = m_DiagFactories.find(key);
  253.     if (it == m_DiagFactories.end())
  254.         return 0;
  255.     return it->second;
  256. }
  257. void CCgiApplication::ConfigureDiagnostics(CCgiContext& context)
  258. {
  259.     // Disable for production servers?
  260.     ConfigureDiagDestination(context);
  261.     ConfigureDiagThreshold(context);
  262.     ConfigureDiagFormat(context);
  263. }
  264. void CCgiApplication::ConfigureDiagDestination(CCgiContext& context)
  265. {
  266.     const CCgiRequest& request = context.GetRequest();
  267.     bool   is_set;
  268.     string dest   = request.GetEntry("diag-destination", &is_set);
  269.     if ( !is_set )
  270.         return;
  271.     SIZE_TYPE colon = dest.find(':');
  272.     CDiagFactory* factory = FindDiagFactory(dest.substr(0, colon));
  273.     if ( factory ) {
  274.         SetDiagHandler(factory->New(dest.substr(colon + 1)));
  275.     }
  276. }
  277. void CCgiApplication::ConfigureDiagThreshold(CCgiContext& context)
  278. {
  279.     const CCgiRequest& request = context.GetRequest();
  280.     bool   is_set;
  281.     string threshold = request.GetEntry("diag-threshold", &is_set);
  282.     if ( !is_set )
  283.         return;
  284.     if (threshold == "fatal") {
  285.         SetDiagPostLevel(eDiag_Fatal);
  286.     } else if (threshold == "critical") {
  287.         SetDiagPostLevel(eDiag_Critical);
  288.     } else if (threshold == "error") {
  289.         SetDiagPostLevel(eDiag_Error);
  290.     } else if (threshold == "warning") {
  291.         SetDiagPostLevel(eDiag_Warning);
  292.     } else if (threshold == "info") {
  293.         SetDiagPostLevel(eDiag_Info);
  294.     } else if (threshold == "trace") {
  295.         SetDiagPostLevel(eDiag_Info);
  296.         SetDiagTrace(eDT_Enable);
  297.     }
  298. }
  299. void CCgiApplication::ConfigureDiagFormat(CCgiContext& context)
  300. {
  301.     const CCgiRequest& request = context.GetRequest();
  302.     typedef map<string, TDiagPostFlags> TFlagMap;
  303.     static TFlagMap s_FlagMap;
  304.     TDiagPostFlags defaults = (eDPF_Prefix | eDPF_Severity
  305.                                | eDPF_ErrCode | eDPF_ErrSubCode);
  306.     TDiagPostFlags new_flags = 0;
  307.     bool   is_set;
  308.     string format = request.GetEntry("diag-format", &is_set);
  309.     if ( !is_set )
  310.         return;
  311.     if (s_FlagMap.empty()) {
  312.         s_FlagMap["file"]        = eDPF_File;
  313.         s_FlagMap["path"]        = eDPF_LongFilename;
  314.         s_FlagMap["line"]        = eDPF_Line;
  315.         s_FlagMap["prefix"]      = eDPF_Prefix;
  316.         s_FlagMap["severity"]    = eDPF_Severity;
  317.         s_FlagMap["code"]        = eDPF_ErrCode;
  318.         s_FlagMap["subcode"]     = eDPF_ErrSubCode;
  319.         s_FlagMap["time"]        = eDPF_DateTime;
  320.         s_FlagMap["omitinfosev"] = eDPF_OmitInfoSev;
  321.         s_FlagMap["all"]         = eDPF_All;
  322.         s_FlagMap["trace"]       = eDPF_Trace;
  323.         s_FlagMap["log"]         = eDPF_Log;
  324.     }
  325.     list<string> flags;
  326.     NStr::Split(format, " ", flags);
  327.     ITERATE(list<string>, flag, flags) {
  328.         TFlagMap::const_iterator it;
  329.         if ((it = s_FlagMap.find(*flag)) != s_FlagMap.end()) {
  330.             new_flags |= it->second;
  331.         } else if ((*flag)[0] == '!'
  332.                    &&  ((it = s_FlagMap.find(flag->substr(1)))
  333.                         != s_FlagMap.end())) {
  334.             new_flags &= ~(it->second);
  335.         } else if (*flag == "default") {
  336.             new_flags |= defaults;
  337.         }
  338.     }
  339.     SetDiagPostAllFlags(new_flags);
  340. }
  341. CCgiApplication::ELogOpt CCgiApplication::GetLogOpt() const
  342. {
  343.     string log = GetConfig().Get("CGI", "Log");
  344.     CCgiApplication::ELogOpt logopt = eNoLog;
  345.     if ((NStr::CompareNocase(log, "On") == 0) ||
  346.         (NStr::CompareNocase(log, "true") == 0)) {
  347.         logopt = eLog;
  348.     } else if (NStr::CompareNocase(log, "OnError") == 0) {
  349.         logopt = eLogOnError;
  350.     }
  351. #ifdef _DEBUG
  352.     else if (NStr::CompareNocase(log, "OnDebug") == 0) {
  353.         logopt = eLog;
  354.     }
  355. #endif
  356.     return logopt;
  357. }
  358. void CCgiApplication::x_LogPost(const char*             msg_header,
  359.                                 unsigned int            iteration,
  360.                                 const CTime&            start_time,
  361.                                 const CNcbiEnvironment* env,
  362.                                 TLogPostFlags           flags)
  363.     const
  364. {
  365.     CNcbiOstrstream msg;
  366.     const CNcbiRegistry& reg = GetConfig();
  367.     if ( msg_header ) {
  368.         msg << msg_header << NcbiEndl;
  369.     }
  370.     if ( flags & fBegin ) {
  371.         bool is_print_iter = reg.GetBool("FastCGI", "PrintIterNo",
  372.                                          false, CNcbiRegistry::eErrPost);
  373.         if ( is_print_iter ) {
  374.             msg << " Iteration = " << iteration << NcbiEndl;
  375.         }
  376.     }
  377.     bool is_timing =
  378.         reg.GetBool("CGI", "TimeStamp", false, CNcbiRegistry::eErrPost);
  379.     if ( is_timing ) {
  380.         msg << " start time = "  << start_time.AsString();
  381.         if ( flags & fEnd ) {
  382.             CTime end_time(CTime::eCurrent);
  383.             CTime elapsed(end_time.DiffSecond(start_time));
  384.             msg << "    end time = " << end_time.AsString()
  385.                 << "    elapsed = "  << elapsed.AsString();
  386.         }
  387.         msg << NcbiEndl;
  388.     }
  389.     if ((flags & fBegin)  &&  env) {
  390.         string print_env = reg.Get("CGI", "PrintEnv");
  391.         if ( !print_env.empty() ) {
  392.             if (NStr::CompareNocase(print_env, "all") == 0) {
  393.                 // TODO
  394.                 ERR_POST("CCgiApp::  [CGI].PrintEnv=all not implemented");
  395.             } else {  // list of variables
  396.                 list<string> vars;
  397.                 NStr::Split(print_env, ",; ", vars);
  398.                 ITERATE (list<string>, i, vars) {
  399.                     msg << *i << "=" << env->Get(*i) << NcbiEndl;
  400.                 }
  401.             }
  402.         }
  403.     }
  404.     ERR_POST( (string) CNcbiOstrstreamToString(msg) );
  405. }
  406. CCgiStatistics* CCgiApplication::CreateStat()
  407. {
  408.     return new CCgiStatistics(*this);
  409. }
  410. void CCgiApplication::x_AddLBCookie()
  411. {
  412.     const CNcbiRegistry& reg = GetConfig();
  413.     string cookie_name = GetConfig().Get("CGI-LB", "Name");
  414.     if ( cookie_name.empty() )
  415.         return;
  416.     int life_span = reg.GetInt("CGI-LB", "LifeSpan", 0,
  417.                                CNcbiRegistry::eReturn);
  418.     string domain = reg.GetString("CGI-LB", "Domain", ".ncbi.nlm.nih.gov");
  419.     if ( domain.empty() ) {
  420.         ERR_POST("CGI-LB: 'Domain' not specified.");
  421.     } else {
  422.         if (domain[0] != '.') {     // domain must start with dot
  423.             domain.insert(0, ".");
  424.         }
  425.     }
  426.     string path = reg.Get("CGI-LB", "Path");
  427.     bool secure = reg.GetBool("CGI-LB", "Secure", false,
  428.                               CNcbiRegistry::eErrPost);
  429.     string host;
  430.     // Getting host configuration can take some time
  431.     // for fast CGIs we try to avoid overhead and call it only once
  432.     // m_HostIP variable keeps the cached value
  433.     if ( m_HostIP ) {     // repeated call
  434.         host = m_HostIP;
  435.     }
  436.     else {               // first time call
  437.         host = reg.Get("CGI-LB", "Host");
  438.         if ( host.empty() ) {
  439.             if ( m_Caf.get() ) {
  440.                 char  host_ip[64] = {0,};
  441.                 m_Caf->GetHostIP(host_ip, sizeof(host_ip));
  442.                 m_HostIP = m_Caf->Encode(host_ip, 0);
  443.                 host = m_HostIP;
  444.             }
  445.             else {
  446.                 ERR_POST("CGI-LB: 'Host' not specified.");
  447.             }
  448.         }
  449.     }
  450.     CCgiCookie cookie(cookie_name, host, domain, path);
  451.     if (life_span > 0) {
  452.         CTime exp_time(CTime::eCurrent, CTime::eGmt);
  453.         exp_time.AddSecond(life_span);
  454.         cookie.SetExpTime(exp_time);
  455.     }
  456.     cookie.SetSecure(secure);
  457.     GetContext().GetResponse().Cookies().Add(cookie);
  458. }
  459. ///////////////////////////////////////////////////////
  460. // CCgiStatistics
  461. //
  462. CCgiStatistics::CCgiStatistics(CCgiApplication& cgi_app)
  463.     : m_CgiApp(cgi_app), m_LogDelim(";")
  464. {
  465. }
  466. CCgiStatistics::~CCgiStatistics()
  467. {
  468. }
  469. void CCgiStatistics::Reset(const CTime& start_time,
  470.                            int          result,
  471.                            const std::exception*  ex)
  472. {
  473.     m_StartTime = start_time;
  474.     m_Result    = result;
  475.     m_ErrMsg    = ex ? ex->what() : kEmptyStr;
  476. }
  477. string CCgiStatistics::Compose(void)
  478. {
  479.     const CNcbiRegistry& reg = m_CgiApp.GetConfig();
  480.     CTime end_time(CTime::eCurrent);
  481.     // Check if it is assigned NOT to log the requests took less than
  482.     // cut off time threshold
  483.     int time_cutoff = reg.GetInt("CGI", "TimeStatCutOff", 0,
  484.                                  CNcbiRegistry::eReturn);
  485.     if (time_cutoff > 0) {
  486.         int diff = end_time.DiffSecond(m_StartTime);
  487.         if (diff < time_cutoff) {
  488.             return kEmptyStr;  // do nothing if it is a light weight request
  489.         }
  490.     }
  491.     string msg, tmp_str;
  492.     tmp_str = Compose_ProgramName();
  493.     if ( !tmp_str.empty() ) {
  494.         msg.append(tmp_str);
  495.         msg.append(m_LogDelim);
  496.     }
  497.     tmp_str = Compose_Result();
  498.     if ( !tmp_str.empty() ) {
  499.         msg.append(tmp_str);
  500.         msg.append(m_LogDelim);
  501.     }
  502.     bool is_timing =
  503.         reg.GetBool("CGI", "TimeStamp", false, CNcbiRegistry::eErrPost);
  504.     if ( is_timing ) {
  505.         tmp_str = Compose_Timing(end_time);
  506.         if ( !tmp_str.empty() ) {
  507.             msg.append(tmp_str);
  508.             msg.append(m_LogDelim);
  509.         }
  510.     }
  511.     tmp_str = Compose_Entries();
  512.     if ( !tmp_str.empty() ) {
  513.         msg.append(tmp_str);
  514.     }
  515.     tmp_str = Compose_ErrMessage();
  516.     if ( !tmp_str.empty() ) {
  517.         msg.append(tmp_str);
  518.         msg.append(m_LogDelim);
  519.     }
  520.     return msg;
  521. }
  522. void CCgiStatistics::Submit(const string& message)
  523. {
  524.     LOG_POST(message);
  525. }
  526. string CCgiStatistics::Compose_ProgramName(void)
  527. {
  528.     return m_CgiApp.GetArguments().GetProgramName();
  529. }
  530. string CCgiStatistics::Compose_Timing(const CTime& end_time)
  531. {
  532.     CTime elapsed(end_time.DiffSecond(m_StartTime));
  533.     return m_StartTime.AsString() + m_LogDelim + elapsed.AsString();
  534. }
  535. string CCgiStatistics::Compose_Entries(void)
  536. {
  537.     const CCgiContext* ctx = m_CgiApp.m_Context.get();
  538.     if ( !ctx )
  539.         return kEmptyStr;
  540.     const CCgiRequest& cgi_req = ctx->GetRequest();
  541.     // LogArgs - list of CGI arguments to log.
  542.     // Can come as list of arguments (LogArgs = param1;param2;param3),
  543.     // or be supplemented with aliases (LogArgs = param1=1;param2=2;param3).
  544.     // When alias is provided we use it for logging purposes (this feature
  545.     // can be used to save logging space or reduce the net traffic).
  546.     const CNcbiRegistry& reg = m_CgiApp.GetConfig();
  547.     string log_args = reg.Get("CGI", "LogArgs");
  548.     if ( log_args.empty() )
  549.         return kEmptyStr;
  550.     list<string> vars;
  551.     NStr::Split(log_args, ",; t", vars);
  552.     string msg;
  553.     ITERATE (list<string>, i, vars) {
  554.         bool is_entry_found;
  555.         const string& arg = *i;
  556.         size_t pos = arg.find_last_of('=');
  557.         if (pos == 0) {
  558.             return "<misconf>" + m_LogDelim;
  559.         } else if (pos != string::npos) {   // alias assigned
  560.             string key = arg.substr(0, pos);
  561.             const CCgiEntry& entry = cgi_req.GetEntry(key, &is_entry_found);
  562.             if ( is_entry_found ) {
  563.                 string alias = arg.substr(pos+1, arg.length());
  564.                 msg.append(alias);
  565.                 msg.append("='");
  566.                 msg.append(entry.GetValue());
  567.                 msg.append("'");
  568.                 msg.append(m_LogDelim);
  569.             }
  570.         } else {
  571.             const CCgiEntry& entry = cgi_req.GetEntry(arg, &is_entry_found);
  572.             if ( is_entry_found ) {
  573.                 msg.append(arg);
  574.                 msg.append("='");
  575.                 msg.append(entry.GetValue());
  576.                 msg.append("'");
  577.                 msg.append(m_LogDelim);
  578.             }
  579.         }
  580.     }
  581.     return msg;
  582. }
  583. string CCgiStatistics::Compose_Result(void)
  584. {
  585.     return NStr::IntToString(m_Result);
  586. }
  587. string CCgiStatistics::Compose_ErrMessage(void)
  588. {
  589.     return m_ErrMsg;
  590. }
  591. END_NCBI_SCOPE
  592. /*
  593. * ===========================================================================
  594. * $Log: cgiapp.cpp,v $
  595. * Revision 1000.2  2004/06/01 18:39:07  gouriano
  596. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.53
  597. *
  598. * Revision 1.53  2004/05/17 20:56:50  gorelenk
  599. * Added include of PCH ncbi_pch.hpp
  600. *
  601. * Revision 1.52  2004/05/11 12:43:55  kuznets
  602. * Changes to control HTTP parsing (CCgiRequest flags)
  603. *
  604. * Revision 1.51  2004/04/07 22:21:41  vakatov
  605. * Convert multi-line diagnostic messages into one-line ones by default
  606. *
  607. * Revision 1.50  2004/03/10 23:35:13  vakatov
  608. * Disable background reporting for CGI applications
  609. *
  610. * Revision 1.49  2004/01/30 14:02:22  lavr
  611. * Insert a space between "page" and "back" in the exception report
  612. *
  613. * Revision 1.48  2003/05/22 21:02:56  vakatov
  614. * [UNIX]  Show ProcessID in diagnostic messages (as prefix)
  615. *
  616. * Revision 1.47  2003/05/21 17:38:34  vakatov
  617. *    If an exception is thrown while processing the request, then
  618. * call OnException() and use its return as the CGI exit code (rather
  619. * than re-throwing the exception).
  620. *    Restore diagnostics setting after processing the request.
  621. *    New configuration parameter '[CGI].DiagPrefixEnv' to prefix all
  622. * diagnostic messages with a value of an arbitrary env.variable.
  623. *    Fixed wrong flags used in most calls to GetConfig().GetString().
  624. *
  625. * Revision 1.46  2003/04/16 21:48:19  vakatov
  626. * Slightly improved logging format, and some minor coding style fixes.
  627. *
  628. * Revision 1.45  2003/03/24 16:15:59  ucko
  629. * Initialize m_Iteration to 0.
  630. *
  631. * Revision 1.44  2003/03/12 16:10:23  kuznets
  632. * iterate -> ITERATE
  633. *
  634. * Revision 1.43  2003/03/11 19:17:31  kuznets
  635. * Improved error diagnostics in CCgiRequest
  636. *
  637. * Revision 1.42  2003/03/03 16:36:46  kuznets
  638. * explicit use of std namespace when reffering exception
  639. *
  640. * Revision 1.41  2003/02/26 17:34:35  kuznets
  641. * CCgiStatistics::Reset changed to take exception as a parameter
  642. *
  643. * Revision 1.40  2003/02/25 14:11:11  kuznets
  644. * Added support of CCookieAffinity service interface, host IP address, cookie encoding
  645. *
  646. * Revision 1.39  2003/02/21 22:20:44  vakatov
  647. * Get rid of a compiler warning
  648. *
  649. * Revision 1.38  2003/02/19 20:57:29  vakatov
  650. * ...and do not include <connect/ncbi_socket.h> too
  651. *
  652. * Revision 1.37  2003/02/19 20:52:33  vakatov
  653. * Temporarily disable auto-detection of host address
  654. *
  655. * Revision 1.36  2003/02/19 17:51:46  kuznets
  656. * Added generation of load balancing cookie
  657. *
  658. * Revision 1.35  2003/02/10 22:33:54  ucko
  659. * Use CTime::DiffSecond rather than operator -, which works in days, and
  660. * don't rely on implicit time_t -> CTime construction.
  661. *
  662. * Revision 1.34  2003/02/04 21:27:22  kuznets
  663. * + Implementation of statistics logging
  664. *
  665. * Revision 1.33  2003/01/23 19:59:02  kuznets
  666. * CGI logging improvements
  667. *
  668. * Revision 1.32  2002/08/02 20:13:53  gouriano
  669. * disable arg descriptions by default
  670. *
  671. * Revision 1.31  2001/12/06 15:06:04  ucko
  672. * Remove name of unused argument to CAsBodyDiagFactory::New.
  673. *
  674. * Revision 1.30  2001/11/19 15:20:17  ucko
  675. * Switch CGI stuff to new diagnostics interface.
  676. *
  677. * Revision 1.29  2001/10/29 15:16:12  ucko
  678. * Preserve default CGI diagnostic settings, even if customized by app.
  679. *
  680. * Revision 1.28  2001/10/17 15:59:55  ucko
  681. * Don't crash if m_DiagHandler is null.
  682. *
  683. * Revision 1.27  2001/10/17 14:18:22  ucko
  684. * Add CCgiApplication::SetCgiDiagHandler for the benefit of derived
  685. * classes that overload ConfigureDiagDestination.
  686. *
  687. * Revision 1.26  2001/10/05 14:56:26  ucko
  688. * Minor interface tweaks for CCgiStreamDiagHandler and descendants.
  689. *
  690. * Revision 1.25  2001/10/04 18:17:52  ucko
  691. * Accept additional query parameters for more flexible diagnostics.
  692. * Support checking the readiness of CGI input and output streams.
  693. *
  694. * Revision 1.24  2001/06/13 21:04:37  vakatov
  695. * Formal improvements and general beautifications of the CGI lib sources.
  696. *
  697. * Revision 1.23  2001/01/12 21:58:43  golikov
  698. * cgicontext available from cgiapp
  699. *
  700. * Revision 1.22  2000/01/20 17:54:58  vakatov
  701. * CCgiApplication:: constructor to get CNcbiArguments, and not raw argc/argv.
  702. * SetupDiag_AppSpecific() to override the one from CNcbiApplication:: -- lest
  703. * to write the diagnostics to the standard output.
  704. *
  705. * Revision 1.21  1999/12/17 17:24:52  vakatov
  706. * Get rid of some extra stuff
  707. *
  708. * Revision 1.20  1999/12/17 04:08:04  vakatov
  709. * cgiapp.cpp
  710. *
  711. * Revision 1.19  1999/11/17 22:48:51  vakatov
  712. * Moved "GetModTime()"-related code and headers to under #if HAVE_LIBFASTCGI
  713. *
  714. * Revision 1.18  1999/11/15 15:54:53  sandomir
  715. * Registry support moved from CCgiApplication to CNcbiApplication
  716. *
  717. * Revision 1.17  1999/10/21 14:50:49  sandomir
  718. * optimization for overflow() (internal buffer added)
  719. *
  720. * Revision 1.16  1999/07/09 18:50:21  sandomir
  721. * FASTCGI mode: if programs modification date changed, break out the loop
  722. *
  723. * Revision 1.15  1999/07/08 14:10:16  sandomir
  724. * Simple output add on exitfastcgi command
  725. *
  726. * Revision 1.14  1999/06/11 20:30:26  vasilche
  727. * We should catch exception by reference, because catching by value
  728. * doesn't preserve comment string.
  729. *
  730. * Revision 1.13  1999/06/03 21:47:20  vakatov
  731. * CCgiApplication::LoadConfig():  patch for R1.12
  732. *
  733. * Revision 1.12  1999/05/27 16:42:42  vakatov
  734. * CCgiApplication::LoadConfig():  if the executable name is "*.exe" then
  735. * compose the default registry file name as "*.ini" rather than
  736. * "*.exe.ini";  use "Warning" rather than "Error" diagnostic severity
  737. * if cannot open the default registry file
  738. *
  739. * Revision 1.11  1999/05/17 00:26:18  vakatov
  740. * Use double-quote rather than angle-brackets for the private headers
  741. *
  742. * Revision 1.10  1999/05/14 19:21:53  pubmed
  743. * myncbi - initial version; minor changes in CgiContext, history, query
  744. *
  745. * Revision 1.8  1999/05/06 23:16:45  vakatov
  746. * <fcgibuf.hpp> became a local header file.
  747. * Use #HAVE_LIBFASTCGI(from <ncbiconf.h>) rather than cmd.-line #FAST_CGI.
  748. *
  749. * Revision 1.7  1999/05/06 20:33:42  pubmed
  750. * CNcbiResource -> CNcbiDbResource; utils from query; few more context methods
  751. *
  752. * Revision 1.6  1999/05/04 16:14:43  vasilche
  753. * Fixed problems with program environment.
  754. * Added class CNcbiEnvironment for cached access to C environment.
  755. *
  756. * Revision 1.5  1999/05/04 00:03:11  vakatov
  757. * Removed the redundant severity arg from macro ERR_POST()
  758. *
  759. * Revision 1.4  1999/04/30 19:21:02  vakatov
  760. * Added more details and more control on the diagnostics
  761. * See #ERR_POST, EDiagPostFlag, and ***DiagPostFlag()
  762. *
  763. * Revision 1.3  1999/04/28 16:54:40  vasilche
  764. * Implemented stream input processing for FastCGI applications.
  765. * Fixed POST request parsing
  766. *
  767. * Revision 1.2  1999/04/27 16:11:11  vakatov
  768. * Moved #define FAST_CGI from inside the "cgiapp.cpp" to "sunpro50.sh"
  769. *
  770. * Revision 1.1  1999/04/27 14:50:03  vasilche
  771. * Added FastCGI interface.
  772. * CNcbiContext renamed to CCgiContext.
  773. * ===========================================================================
  774. */