NCBI C++ ToolKit
cgiapp.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: cgiapp.cpp 103158 2024-09-16 18:35:06Z grichenk $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Eugene Vasilchenko, Denis Vakatov, Anatoliy Kuznetsov
27 *
28 * File Description:
29 * Definition CGI application class and its context class.
30 */
31 
32 #include <ncbi_pch.hpp>
33 #include <cgi/cgiapp.hpp>
34 
35 #include <corelib/ncbienv.hpp>
36 #include <corelib/rwstream.hpp>
37 #include <corelib/stream_utils.hpp>
38 #include <corelib/ncbi_system.hpp> // for SuppressSystemMessageBox
39 #include <corelib/rwstream.hpp>
41 #include <corelib/request_ctx.hpp>
42 #include <corelib/ncbi_strings.h>
43 
44 #include <util/multi_writer.hpp>
45 #include <util/cache/cache_ref.hpp>
46 
47 #include <cgi/cgictx.hpp>
48 #include <cgi/cgi_exception.hpp>
49 #include <cgi/cgi_serial.hpp>
50 #include <cgi/error_codes.hpp>
51 #include <signal.h>
52 
53 
54 #ifdef NCBI_OS_UNIX
55 # include <unistd.h>
56 #endif
57 
58 
59 #define NCBI_USE_ERRCODE_X Cgi_Application
60 
61 
63 
64 
65 NCBI_PARAM_DECL(bool, CGI, Print_Http_Referer);
66 NCBI_PARAM_DEF_EX(bool, CGI, Print_Http_Referer, true, eParam_NoThread,
67  CGI_PRINT_HTTP_REFERER);
68 typedef NCBI_PARAM_TYPE(CGI, Print_Http_Referer) TPrintRefererParam;
69 
70 
71 NCBI_PARAM_DECL(bool, CGI, Print_User_Agent);
72 NCBI_PARAM_DEF_EX(bool, CGI, Print_User_Agent, true, eParam_NoThread,
73  CGI_PRINT_USER_AGENT);
74 typedef NCBI_PARAM_TYPE(CGI, Print_User_Agent) TPrintUserAgentParam;
75 
76 
77 NCBI_PARAM_DECL(bool, CGI, Print_Self_Url);
78 NCBI_PARAM_DEF_EX(bool, CGI, Print_Self_Url, true, eParam_NoThread,
79  CGI_PRINT_SELF_URL);
80 typedef NCBI_PARAM_TYPE(CGI, Print_Self_Url) TPrintSelfUrlParam;
81 
82 
83 NCBI_PARAM_DECL(bool, CGI, Print_Request_Method);
84 NCBI_PARAM_DEF_EX(bool, CGI, Print_Request_Method, true, eParam_NoThread,
85  CGI_PRINT_REQUEST_METHOD);
86 typedef NCBI_PARAM_TYPE(CGI, Print_Request_Method) TPrintRequestMethodParam;
87 
88 
89 NCBI_PARAM_DECL(bool, CGI, Allow_Sigpipe);
90 NCBI_PARAM_DEF_EX(bool, CGI, Allow_Sigpipe, false, eParam_NoThread,
91  CGI_ALLOW_SIGPIPE);
92 typedef NCBI_PARAM_TYPE(CGI, Allow_Sigpipe) TParamAllowSigpipe;
93 
94 // Log any broken connection with status 299 rather than 499.
97  CGI_CLIENT_CONNECTION_INTERRUPTION_OKAY);
98 
99 // Severity for logging broken connection errors.
101 {
102  {"Info", eDiag_Info},
103  {"Warning", eDiag_Warning},
104  {"Error", eDiag_Error},
105  {"Critical", eDiag_Critical},
106  {"Fatal", eDiag_Fatal},
107  {"Trace", eDiag_Trace}
108 };
111  CGI_CLIENT_CONNECTION_INTERRUPTION_SEVERITY);
112 
113 
114 ///////////////////////////////////////////////////////
115 // IO streams with byte counting for CGI applications
116 //
117 
118 
119 class CCGIStreamReader : public IReader
120 {
121 public:
122  CCGIStreamReader(istream& is) : m_IStr(is) { }
123 
124  virtual ERW_Result Read(void* buf,
125  size_t count,
126  size_t* bytes_read = 0);
127  virtual ERW_Result PendingCount(size_t* /*count*/)
128  { return eRW_NotImplemented; }
129 
130 protected:
131  istream& m_IStr;
132 };
133 
134 
136  size_t count,
137  size_t* bytes_read)
138 {
139  size_t x_read = (size_t)CStreamUtils::Readsome(m_IStr, (char*)buf, count);
141  if (x_read > 0 || count == 0) {
143  }
144  else {
145  result = m_IStr.eof() ? eRW_Eof : eRW_Error;
146  }
147  if (bytes_read) {
148  *bytes_read = x_read;
149  }
150  return result;
151 }
152 
153 
154 ///////////////////////////////////////////////////////
155 // CCgiStreamWrapper, CCgiStreamWrapperWriter
156 //
157 
158 NCBI_PARAM_DECL(bool, CGI, Count_Transfered);
159 NCBI_PARAM_DEF_EX(bool, CGI, Count_Transfered, true, eParam_NoThread,
160  CGI_COUNT_TRANSFERED);
161 typedef NCBI_PARAM_TYPE(CGI, Count_Transfered) TCGI_Count_Transfered;
162 
163 
164 // Helper writer used to:
165 // - count bytes read/written to the stream;
166 // - disable output stream during HEAD requests after sending headers
167 // so that the application can not output more data or clear 'bad' bit;
168 // - send chunked data to the client;
169 // - copy data to cache stream when necessary.
171 {
172 public:
174  virtual ~CCgiStreamWrapperWriter(void);
175 
176  virtual ERW_Result Write(const void* buf,
177  size_t count,
178  size_t* bytes_written = 0);
179 
180  virtual ERW_Result Flush(void);
181 
183 
185  void SetCacheStream(CNcbiOstream& stream);
186 
188  void AbortChunkedTransfer(void);
189 
190 private:
191  void x_SetChunkSize(size_t sz);
192  void x_WriteChunk(const char* buf, size_t count);
193 
196  // block mode
198  // chunked mode
199  size_t m_ChunkSize;
200  char* m_Chunk;
201  size_t m_Count;
202  bool m_UsedChunkedTransfer; // remember if chunked transfer was enabled.
203 };
204 
205 
207  : m_Mode(CCgiStreamWrapper::eNormal),
208  m_Out(&out),
209  m_ErrorReported(false),
210  m_ChunkSize(0),
211  m_Chunk(0),
212  m_Count(0),
213  m_UsedChunkedTransfer(false)
214 {
215 }
216 
217 
219 {
221  x_SetChunkSize(0); // cleanup
222  }
223 }
224 
225 
227 {
228  if (!buf || count == 0) return;
229  *m_Out << NStr::NumericToString(count, 0, 16) << HTTP_EOL;
230  m_Out->write(buf, count);
231  *m_Out << HTTP_EOL;
232 }
233 
234 
236  size_t count,
237  size_t* bytes_written)
238 {
240  size_t written = 0;
241 
242  switch (m_Mode) {
244  {
245  if (!m_Out->write((char*)buf, count)) {
246  result = eRW_Error;
247  }
248  else {
250  written = count;
251  }
252  break;
253  }
255  {
256  if ( !m_ErrorReported ) {
257  if ( m_UsedChunkedTransfer ) {
258  ERR_POST_X(16, "CCgiStreamWrapperWriter::Write() -- attempt to "
259  "write data after finishing chunked transfer.");
260  }
261  else {
262  ERR_POST_X(15, "CCgiStreamWrapperWriter::Write() -- attempt to "
263  "write data after sending headers on HEAD request.");
264  }
265  m_ErrorReported = true;
266  }
267  // Pretend the operation was successfull so that applications
268  // which check I/O result do not fail.
269  written = count;
270  break;
271  }
273  {
274  const char* cbuf = static_cast<const char*>(buf);
275  if (m_Chunk && m_ChunkSize > 0) {
276  // Copy data to own buffer
277  while (count && result == eRW_Success) {
278  size_t chunk_count = min(count, m_ChunkSize - m_Count);
279  memcpy(m_Chunk + m_Count, cbuf, chunk_count);
280  cbuf += chunk_count;
281  m_Count += chunk_count;
282  count -= chunk_count;
283  written += chunk_count;
284  if (m_Count >= m_ChunkSize) {
286  if (!m_Out->good()) {
287  result = eRW_Error;
288  written -= chunk_count;
289  }
290  m_Count = 0;
291  }
292  }
293  }
294  else {
295  // If chunk size is zero, use the whole original buffer.
296  x_WriteChunk(cbuf, count);
297  if (m_Out->good()) {
298  written = count;
299  }
300  else {
301  result = eRW_Error;
302  }
303  }
304  break;
305  }
306  }
307 
308  if (bytes_written) {
309  *bytes_written = written;
310  }
311  return result;
312 }
313 
314 
316 {
317  switch (m_Mode) {
319  break;
321  // Report success
322  return eRW_Success;
324  if (m_Count) {
326  m_Count = 0;
327  }
328  break;
329  }
330  return m_Out->flush() ? eRW_Success : eRW_Error;
331 }
332 
333 
335 {
336  switch (mode) {
338  break;
341  m_Out->flush();
342  // Prevent output from writing anything, disable exceptions -
343  // an attemp to write will be reported by the wrapper.
344  m_Out->exceptions(ios_base::goodbit);
345  m_Out->setstate(ios_base::badbit);
346  break;
349  // Use default chunk size.
351  m_UsedChunkedTransfer = true;
352  break;
353  }
354  m_Mode = mode;
355 }
356 
357 
359 {
360  list<CNcbiOstream*> slist;
361  slist.push_back(m_Out);
362  slist.push_back(&stream);
363  m_Out = new CWStream(new CMultiWriter(slist), 1, 0,
365 }
366 
367 
369  const CCgiStreamWrapper::TTrailer* trailer)
370 {
372  Flush();
373  // Zero chunk indicates end of chunked data.
374  *m_Out << "0" << HTTP_EOL;
375  x_SetChunkSize(0);
376  // Allow to write trailers after the last chunk.
378  if ( trailer ) {
379  ITERATE(CCgiStreamWrapper::TTrailer, it, *trailer) {
380  *m_Out << it->first << ": " << it->second << HTTP_EOL;
381  }
382  }
383  // Finish chunked data/trailer.
384  *m_Out << HTTP_EOL;
385  }
386 }
387 
388 
390 {
392  x_SetChunkSize(0);
393  }
394  // Disable any writes.
396 }
397 
398 
400 {
401  if (m_Chunk) {
403  delete[](m_Chunk);
404  m_Chunk = 0;
405  }
406  m_Count = 0;
407  m_ChunkSize = sz;
408  if (m_ChunkSize) {
409  m_Chunk = new char[m_ChunkSize];
410  }
411 }
412 
413 
415  : CWStream(m_Writer = new CCgiStreamWrapperWriter(out),
416  1, 0, CRWStreambuf::fOwnWriter) // '1, 0' disables buffering by the wrapper
417 {
418 }
419 
420 
422 {
423  return m_Writer->GetMode();
424 }
425 
426 
428 {
429  flush();
431 }
432 
433 
435 {
436  m_Writer->SetCacheStream(stream);
437 }
438 
439 
441 {
443 }
444 
445 
447 {
449 }
450 
451 
452 ///////////////////////////////////////////////////////
453 // CCgiApplication
454 //
455 
456 
458 {
459  return dynamic_cast<CCgiApplication*> (CParent::Instance());
460 }
461 
462 
463 extern "C" void SigTermHandler(int)
464 {
465 }
466 
467 
469 {
470  // Value to return from this method Run()
471  int result;
472 
473  // Try to run as a Fast-CGI loop
474  if ( x_RunFastCGI(&result) ) {
475  return result;
476  }
477 
479 
480  /// Run as a plain CGI application
481 
482  // Make sure to restore old diagnostic state after the Run()
483  CDiagRestorer diag_restorer;
484 
485 #if defined(NCBI_OS_UNIX)
486  // Disable SIGPIPE if not allowed.
487  if ( !TParamAllowSigpipe::GetDefault() ) {
488  signal(SIGPIPE, SIG_IGN);
489  struct sigaction sigterm, sigtermold;
490  memset(&sigterm, 0, sizeof(sigterm));
491  sigterm.sa_handler = SigTermHandler;
492  sigterm.sa_flags = SA_RESETHAND;
493  if (sigaction(SIGTERM, &sigterm, &sigtermold) == 0
494  && sigtermold.sa_handler != SIG_DFL) {
495  sigaction(SIGTERM, &sigtermold, 0);
496  }
497  }
498 
499  // Compose diagnostics prefix
500  PushDiagPostPrefix(NStr::IntToString(getpid()).c_str());
501 #endif
503 
504  // Timing
506 
507  // Logging for statistics
508  bool is_stat_log = GetConfig().GetBool("CGI", "StatLog", false,
510  bool skip_stat_log = false;
511  unique_ptr<CCgiStatistics> stat(is_stat_log ? CreateStat() : 0);
512 
513  CNcbiOstream* orig_stream = NULL;
514  //int orig_fd = -1;
515  CNcbiStrstream result_copy;
516  unique_ptr<CNcbiOstream> new_stream;
517  shared_ptr<CCgiContext> context;
518  unique_ptr<ICache> cache;
519 
520  try {
521  _TRACE("(CGI) CCgiApplication::Run: calling ProcessRequest");
523 
524  context.reset(CreateContext());
525  _ASSERT(context);
526  processor.SetContext(context);
527 
529  x_AddLBCookie();
530  try {
531  // Print request start message
533 
537 
538  context->CheckStatus();
539 
540  try {
541  cache.reset( GetCacheStorage() );
542  } catch (const exception& ex) {
543  ERR_POST_X(1, "Couldn't create cache : " << ex.what());
544  }
545  bool skip_process_request = false;
546  bool caching_needed = IsCachingNeeded(context->GetRequest());
547  if (cache && caching_needed) {
548  skip_process_request = GetResultFromCache(context->GetRequest(),
549  context->GetResponse().out(),
550  *cache);
551  }
552  if (!skip_process_request) {
553  if( cache ) {
554  CCgiStreamWrapper* wrapper = dynamic_cast<CCgiStreamWrapper*>(
555  context->GetResponse().GetOutput());
556  if ( wrapper ) {
557  wrapper->SetCacheStream(result_copy);
558  }
559  else {
560  list<CNcbiOstream*> slist;
561  orig_stream = context->GetResponse().GetOutput();
562  slist.push_back(orig_stream);
563  slist.push_back(&result_copy);
564  new_stream.reset(new CWStream(new CMultiWriter(slist), 1, 0,
566  context->GetResponse().SetOutput(new_stream.get());
567  }
568  }
570  if (x_ProcessHelpRequest(processor) ||
571  x_ProcessVersionRequest(processor) ||
572  CCgiContext::ProcessCORSRequest(context->GetRequest(), context->GetResponse()) ||
573  x_ProcessAdminRequest(processor)) {
574  result = 0;
575  }
576  else {
579  "Invalid or missing CSRF token.", CCgiException::e403_Forbidden);
580  }
581  result = processor.ProcessRequest(*context);
582  }
584  context->GetResponse().Finalize();
585  if (result != 0) {
586  processor.SetHTTPStatus(500);
587  processor.SetErrorStatus(true);
588  context->GetResponse().AbortChunkedTransfer();
589  } else {
590  context->GetResponse().FinishChunkedTransfer();
591  if ( cache ) {
592  context->GetResponse().Flush();
593  if (processor.GetResultReady()) {
594  if(caching_needed)
595  SaveResultToCache(context->GetRequest(), result_copy, *cache);
596  else {
597  unique_ptr<CCgiRequest> request(GetSavedRequest(processor.GetRID(), *cache));
598  if (request.get())
599  SaveResultToCache(*request, result_copy, *cache);
600  }
601  } else if (caching_needed) {
602  SaveRequest(processor.GetRID(), context->GetRequest(), *cache);
603  }
604  }
605  }
606  }
607  }
608  catch (const CCgiException& e) {
609  if ( context && x_DoneHeadRequest(*context) ) {
610  // Ignore errors after HEAD request has been finished.
612  }
613  else {
616  throw;
617  }
618  context->GetResponse().FinishChunkedTransfer();
620  // If for some reason exception with status 2xx was thrown,
621  // set the result to 0, update HTTP status and continue.
622  context->GetResponse().SetStatus(e.GetStatusCode(),
623  e.GetStatusMessage());
624  }
625  result = 0;
626  }
627 
628 #ifdef NCBI_OS_MSWIN
629  // Logging - on MSWin this must be done before flushing the output.
630  if ( is_stat_log && !skip_stat_log ) {
631  stat->Reset(start_time, result);
632  stat->Submit(stat->Compose());
633  }
634  is_stat_log = false;
635 #endif
636 
637  _TRACE("CCgiApplication::Run: flushing");
638  context->GetResponse().Flush();
639  _TRACE("CCgiApplication::Run: return " << result);
642  }
643  catch (exception& e) {
644  if ( context ) {
645  context->GetResponse().AbortChunkedTransfer();
646  }
648  if ( context && x_DoneHeadRequest(*context) ) {
649  // Ignore errors after HEAD request has been finished.
650  result = 0;
652  }
653  else {
654  // Call the exception handler and set the CGI exit code
657 
658  // Logging
659  {{
660  string msg = "(CGI) CCgiApplication::ProcessRequest() failed: ";
661  msg += e.what();
662 
663  if ( is_stat_log ) {
664  stat->Reset(start_time, result, &e);
665  msg = stat->Compose();
666  stat->Submit(msg);
667  skip_stat_log = true; // Don't print the same message again
668  }
669  }}
670 
671  // Exception reporting. Use different severity for broken connection.
672  ios_base::failure* fex = dynamic_cast<ios_base::failure*>(&e);
673  CNcbiOstream* os = context ? context->GetResponse().GetOutput() : NULL;
674  if ((fex && os && !os->good()) || processor.GetOutputBroken()) {
675  if ( !TClientConnIntOk::GetDefault() ) {
676  ERR_POST_X(13, Severity(TClientConnIntSeverity::GetDefault()) <<
677  "Connection interrupted");
678  }
679  }
680  else {
681  NCBI_REPORT_EXCEPTION_X(13, "(CGI) CCgiApplication::Run", e);
682  }
683  }
684  }
685 
686 #ifndef NCBI_OS_MSWIN
687  // Logging
688  if ( is_stat_log && !skip_stat_log ) {
689  stat->Reset(start_time, result);
690  stat->Submit(stat->Compose());
691  }
692 #endif
693 
694  x_OnEvent(eEndRequest, 120);
696 
697  if ( context ) {
698  context->GetResponse().SetOutput(NULL);
699  }
700  return result;
701 }
702 
703 
705 {
706  // Set HTTP_REFERER
707  string ref = x_GetProcessor().GetSelfReferer();
708  if ( !ref.empty() ) {
709  GetRWConfig().Set("CONN", "HTTP_REFERER", ref);
710  CDiagContext::GetRequestContext().SetProperty("SELF_URL", ref);
711  }
712 }
713 
714 
716 {
718 }
719 
721 {
722  const auto& req = ctx.GetRequest();
723  const auto& diag = GetDiagContext();
724 
725  string str;
726  if (TPrintRequestMethodParam::GetDefault()) {
727  // Print request method
728  string method = req.GetRequestMethodName();
729  if (!method.empty()) {
730  diag.Extra().Print("REQUEST_METHOD", method);
731  }
732  }
733  if ( TPrintSelfUrlParam::GetDefault() ) {
734  // Print script URL
735  string self_url = ctx.GetSelfURL();
736  if ( !self_url.empty() ) {
737  string args =
738  req.GetRandomProperty("REDIRECT_QUERY_STRING", false);
739  if ( args.empty() ) {
740  args = req.GetProperty(eCgi_QueryString);
741  }
742  if ( !args.empty() ) {
743  self_url += "?" + args;
744  }
745  }
746  // Add target url
747  string target_url = req.GetProperty(eCgi_ScriptName);
748  if ( !target_url.empty() ) {
749  bool secure = AStrEquiv(req.GetRandomProperty("HTTPS",
750  false), "on", PNocase());
751  string host = (secure ? "https://" : "http://") + diag.GetHost();
752  string port = req.GetProperty(eCgi_ServerPort);
753  if (!port.empty() && port != (secure ? "443" : "80")) {
754  host += ":" + port;
755  }
756  target_url = host + target_url;
757  }
758  if ( !self_url.empty() || !target_url.empty() ) {
759  diag.Extra().Print("SELF_URL", self_url).
760  Print("TARGET_URL", target_url);
761  }
762  }
763  // Print HTTP_REFERER
764  if ( TPrintRefererParam::GetDefault() ) {
765  str = req.GetProperty(eCgi_HttpReferer);
766  if ( !str.empty() ) {
767  diag.Extra().Print("HTTP_REFERER", str);
768  }
769  }
770  // Print USER_AGENT
771  if ( TPrintUserAgentParam::GetDefault() ) {
772  str = req.GetProperty(eCgi_HttpUserAgent);
773  if ( !str.empty() ) {
774  diag.Extra().Print("USER_AGENT", str);
775  }
776  }
777  // Print NCBI_LOG_FIELDS
778  CNcbiLogFields f("http");
780  list<string> names;
781  const CNcbiEnvironment& rq_env = req.GetEnvironment();
782  rq_env.Enumerate(names);
783  ITERATE(list<string>, it, names) {
784  if (!NStr::StartsWith(*it, "HTTP_")) continue;
785  string name = it->substr(5);
786  NStr::ToLower(name);
787  NStr::ReplaceInPlace(name, "_", "-");
788  env[name] = rq_env.Get(*it);
789  }
790  f.LogFields(env);
791 }
792 
793 
795 {
797 
799 }
800 
801 
803 {
804  if ( !x_IsSetProcessor() || !x_GetProcessor().IsSetContext() ) {
805  ERR_POST_X(2, "CCgiApplication::GetContext: no context set");
806  throw runtime_error("no context set");
807  }
808  return x_GetProcessor().GetContext();
809 }
810 
811 
813 {
814  if ( !m_Resource.get() ) {
815  ERR_POST_X(3, "CCgiApplication::GetResource: no resource set");
816  throw runtime_error("no resource set");
817  }
818  return *m_Resource;
819 }
820 
821 
823 {
824  return m_Processor->GetValue();
825 }
826 
827 
829 {
830  auto proc = m_Processor->GetValue();
831  if (!proc) {
832  ERR_POST_X(17, "CCgiApplication::GetResource: no processor set");
833  throw runtime_error("no request processor set");
834  }
835  return *proc;
836 }
837 
838 
840 {
841  return m_Processor->GetValue();
842 }
843 
844 
845 static void s_CleanupProcessor(CCgiRequestProcessor* processor, void* /* cleanup_data */)
846 {
847  if (processor != nullptr) delete processor;
848 }
849 
850 
852 {
854  return x_GetProcessor();
855 }
856 
857 
858 NCBI_PARAM_DECL(bool, CGI, Merge_Log_Lines);
859 NCBI_PARAM_DEF_EX(bool, CGI, Merge_Log_Lines, true, eParam_NoThread,
860  CGI_MERGE_LOG_LINES);
861 typedef NCBI_PARAM_TYPE(CGI, Merge_Log_Lines) TMergeLogLines;
862 
863 
865 {
866  if ( TMergeLogLines::GetDefault() ) {
867  // Convert multi-line diagnostic messages into one-line ones by default.
869  }
870 
871  CParent::Init();
872 
873  m_Resource.reset(LoadResource());
874 
875  m_DiagPrefixEnv = GetConfig().Get("CGI", "DiagPrefixEnv");
876 }
877 
878 
880 {
881  m_Processor->Reset();
882  m_Resource.reset();
883  CParent::Exit();
884 }
885 
886 
888 {
889  return 0;
890 }
891 
892 
894 {
895  return 0;
896 }
897 
898 
900 (CNcbiArguments* args,
902  CNcbiIstream* inp,
903  CNcbiOstream* out,
904  int ifd,
905  int ofd)
906 {
907  return CreateContextWithFlags(args, env,
908  inp, out, ifd, ofd, m_RequestFlags);
909 }
910 
912 (CNcbiArguments* args,
914  CNcbiIstream* inp,
915  CNcbiOstream* out,
916  int ifd,
917  int ofd,
918  int flags)
919 {
921  args, env, inp, out, ifd, ofd, flags);
922 }
923 
924 
926  CCgiRequestProcessor& processor,
927  CNcbiArguments* args,
929  CNcbiIstream* inp,
930  CNcbiOstream* out,
931  int ifd,
932  int ofd,
933  int flags)
934 {
935  int errbuf_size =
936  GetConfig().GetInt("CGI", "RequestErrBufSize", 256, 0,
938 
939  bool need_output_wrapper =
940  TCGI_Count_Transfered::GetDefault() ||
942  (env &&
943  NStr::EqualNocase("HEAD",
945 
946  if ( TCGI_Count_Transfered::GetDefault() ) {
947  if ( !inp ) {
948  if ( !processor.IsSetInputStream() ) {
949  processor.SetInputStream(
950  new CRStream(new CCGIStreamReader(std::cin), 0, 0,
952  }
953  inp = &processor.GetInputStream();
954  ifd = 0;
955  }
956  }
957  if ( need_output_wrapper ) {
958  if ( !out ) {
959  if ( !processor.IsSetOutputStream() ) {
960  processor.SetOutputStream(new CCgiStreamWrapper(std::cout));
961  }
962  out = &processor.GetOutputStream();
963  ofd = 1;
964  if ( processor.IsSetInputStream() ) {
965  // If both streams are created by the application, tie them.
966  inp->tie(out);
967  }
968  }
969  else {
970  processor.SetOutputStream(new CCgiStreamWrapper(*out));
971  out = &processor.GetOutputStream();
972  }
973  }
974  return
975  new CCgiContext(*this, args, env, inp, out, ifd, ofd,
976  (errbuf_size >= 0) ? (size_t) errbuf_size : 256,
977  flags);
978 }
979 
980 
982 {
983  return new CCgiRequestProcessor(*this);
984 }
985 
986 
988 {
989  m_Caf.reset(caf);
990 }
991 
992 
993 
994 // Flexible diagnostics support
995 //
996 
998 {
999 public:
1000  virtual CDiagHandler* New(const string&) {
1001  return new CStreamDiagHandler(&NcbiCerr);
1002  }
1003 };
1004 
1005 
1007 {
1008 public:
1010  virtual CDiagHandler* New(const string&) {
1011  CCgiResponse& response = m_App->GetContext().GetResponse();
1012  CDiagHandler* result = new CStreamDiagHandler(&response.out());
1013  if (!response.IsHeaderWritten()) {
1014  response.SetContentType("text/plain");
1015  response.WriteHeader();
1016  }
1017  response.SetOutput(0); // suppress normal output
1018  return result;
1019  }
1020 
1021 private:
1023 };
1024 
1025 
1027  : CNcbiApplication(build_info),
1028  m_RequestFlags(0),
1029  m_CaughtSigterm(false),
1030  m_Processor(new CTls<CCgiRequestProcessor>()),
1031  m_HostIP(0)
1032 {
1033  m_Iteration.Set(0);
1034  // Disable system popup messages
1036 
1037  // Turn on iteration number
1040 
1043  RegisterDiagFactory("stderr", new CStderrDiagFactory);
1044  RegisterDiagFactory("asbody", new CAsBodyDiagFactory(this));
1045  cerr.tie(0);
1046 }
1047 
1048 
1050 {
1052  delete it->second;
1053  }
1054  if ( m_HostIP )
1055  free(m_HostIP);
1056 }
1057 
1058 
1060 {
1061  return x_IsSetProcessor() ? x_GetProcessor().OnException(e, os) : -1;
1062 }
1063 
1064 
1066 {
1067  // Are there no argument descriptions or no CGI context (yet?)
1068  if (!GetArgDescriptions() || !x_IsSetProcessor()) return CParent::GetArgs();
1069  return x_GetProcessor().GetArgs();
1070 }
1071 
1072 
1073 void CCgiApplication::x_OnEvent(CCgiRequestProcessor* pprocessor, EEvent event, int status)
1074 {
1075  switch ( event ) {
1076  case eStartRequest:
1077  {
1078  // Set context properties
1079  if (!pprocessor) break;
1080  CCgiRequestProcessor& processor = *pprocessor;
1081  const CCgiRequest& req = processor.GetContext().GetRequest();
1082 
1083  // Set span kind for tracing, if any.
1085  // Print request start message
1087  CExtraEntryCollector collector;
1088  req.GetCGIEntries(collector);
1090  .AllowBadSymbolsInArgNames()
1091  .Print(collector.GetArgs());
1092  processor.SetRequestStartPrinted(true);
1093  }
1094 
1095  // Set default HTTP status code (reset above by PrintRequestStart())
1096  processor.SetHTTPStatus(200);
1097  processor.SetErrorStatus(false);
1098 
1099  auto& req_ctx = CDiagContext::GetRequestContext();
1100  // This will log ncbi_phid as a separate 'extra' message
1101  // if not yet logged.
1102  req_ctx.GetHitID();
1103 
1104  // Post request properties to the current tracer span, if any.
1105  auto span = req_ctx.GetTracerSpan();
1106  if ( span ) {
1107  string s = req.GetProperty(eCgi_ScriptName);
1108  if (!s.empty()) span->SetName(s);
1109  s = req.GetProperty(eCgi_ServerName);
1110  if (!s.empty()) {
1111  span->SetAttribute(ITracerSpan::eServerAddress, s);
1112  s = req.GetProperty(eCgi_ServerPort);
1113  if (!s.empty()) span->SetAttribute(ITracerSpan::eServerPort, s);
1114  }
1115  s = processor.GetContext().GetSelfURL();
1116  if (!s.empty()) {
1117  string args = req.GetRandomProperty("REDIRECT_QUERY_STRING", false);
1118  if ( args.empty() ) {
1119  args = req.GetProperty(eCgi_QueryString);
1120  }
1121  if ( !args.empty() ) {
1122  s += "?" + args;
1123  }
1124  span->SetAttribute(ITracerSpan::eUrl, s);
1125  }
1127  if (!s.empty()) span->SetAttribute(ITracerSpan::eRequestMethod, s);
1129  if (!s.empty()) {
1130  span->SetAttribute(ITracerSpan::eUrlScheme, s);
1131  // Although HttpScheme is deprecated by Opentelemetry in favor of UrlScheme,
1132  // elasticapm may expect it.
1133  span->SetAttribute(ITracerSpan::eHttpScheme, s);
1134  }
1135  s = req.GetProperty(eCgi_RemoteAddr);
1136  if (!s.empty()) span->SetAttribute(ITracerSpan::eClientAddress, s);
1137  s = req.GetProperty(eCgi_ContentType);
1138  if (!s.empty()) span->SetHttpHeader(ITracerSpan::eRequest, "CONTENT_TYPE", s);
1140  if (!s.empty()) span->SetHttpHeader(ITracerSpan::eRequest, "CONTENT_LENGTH", s);
1142  if (!s.empty()) span->SetHttpHeader(ITracerSpan::eRequest, "HTTP_USER_AGENT", s);
1143  }
1144 
1145  // Check if ncbi_st cookie is set
1147  if ( st ) {
1148  CUrlArgs pg_info(st->GetValue());
1149  // Log ncbi_st values
1151  // extra.SetType("NCBICGI");
1152  ITERATE(CUrlArgs::TArgs, it, pg_info.GetArgs()) {
1153  extra.Print(it->name, it->value);
1154  }
1155  extra.Flush();
1156  }
1157  break;
1158  }
1159  case eSuccess:
1160  case eError:
1161  case eException:
1162  {
1163  if (!pprocessor) break;
1164  CCgiRequestProcessor& processor = *pprocessor;
1166  try {
1167  if ( processor.IsSetInputStream() ) {
1168  auto& in = processor.GetInputStream();
1169  if ( !in.good() ) {
1170  in.clear();
1171  }
1172  rctx.SetBytesRd(NcbiStreamposToInt8(in.tellg()));
1173  }
1174  }
1175  catch (const exception&) {
1176  }
1177  try {
1178  if ( processor.IsSetOutputStream() ) {
1179  auto& out = processor.GetOutputStream();
1180  if ( !out.good() ) {
1181  processor.SetOutputBroken(true); // set flag to indicate broken output
1182  out.clear();
1183  }
1184  rctx.SetBytesWr(NcbiStreamposToInt8(out.tellp()));
1185  }
1186  }
1187  catch (const exception&) {
1188  }
1189 
1191  if ( span ) {
1192  span->SetSpanStatus(event == eSuccess ? ITracerSpan::eSuccess : ITracerSpan::eError);
1193  }
1194  break;
1195  }
1196  case eEndRequest:
1197  {
1198  if (!pprocessor) break;
1199  CCgiRequestProcessor& processor = *pprocessor;
1200  CCgiContext& cgi_ctx = processor.GetContext();
1201  CDiagContext& diag_ctx = GetDiagContext();
1203 
1204  // If an error status has been set by ProcessRequest, don't try
1205  // to check the output stream and change the status to 299/499.
1206  if ( !processor.GetErrorStatus() ) {
1207  // Log broken connection as 299/499 status
1208  CNcbiOstream* os = processor.IsSetContext() ?
1209  cgi_ctx.GetResponse().GetOutput() : NULL;
1210  if ((os && !os->good()) || processor.GetOutputBroken()) {
1211  // 'Accept-Ranges: bytes' indicates a request for
1212  // content length, broken connection is OK.
1213  // If Content-Range is also set, the client was downloading
1214  // partial data. Broken connection is not OK in this case.
1215  if (TClientConnIntOk::GetDefault() ||
1216  (cgi_ctx.GetResponse().AcceptRangesBytes() &&
1217  !cgi_ctx.GetResponse().HaveContentRange())) {
1218  rctx.SetRequestStatus(
1220  }
1221  else {
1222  rctx.SetRequestStatus(
1224  }
1225  }
1226  }
1228  if (processor.GetRequestStartPrinted()) {
1229  // This will also reset request context
1230  diag_ctx.PrintRequestStop();
1231  processor.SetRequestStartPrinted(false);
1232  }
1233  rctx.Reset();
1234  }
1235  break;
1236  }
1237  case eExit:
1238  case eExecutable:
1239  case eWatchFile:
1240  case eExitOnFail:
1241  case eExitRequest:
1242  case eWaiting:
1243  {
1244  break;
1245  }
1246  }
1247 
1248  OnEvent(event, status);
1249 }
1250 
1251 
1253  int exit_code)
1254 {
1255  if (x_IsSetProcessor()) x_GetProcessor().OnEvent(event, exit_code);
1256 }
1257 
1258 
1260  CDiagFactory* fact)
1261 {
1262  m_DiagFactories[key] = fact;
1263 }
1264 
1265 
1267 {
1269  if (it == m_DiagFactories.end())
1270  return 0;
1271  return it->second;
1272 }
1273 
1274 
1276 {
1277  // Disable for production servers?
1281 }
1282 
1283 
1285 {
1286  const CCgiRequest& request = context.GetRequest();
1287 
1288  bool is_set;
1289  string dest = request.GetEntry("diag-destination", &is_set);
1290  if ( !is_set )
1291  return;
1292 
1293  SIZE_TYPE colon = dest.find(':');
1294  CDiagFactory* factory = FindDiagFactory(dest.substr(0, colon));
1295  if ( factory ) {
1296  SetDiagHandler(factory->New(dest.substr(colon + 1)));
1297  }
1298 }
1299 
1300 
1302 {
1303  const CCgiRequest& request = context.GetRequest();
1304 
1305  bool is_set;
1306  string threshold = request.GetEntry("diag-threshold", &is_set);
1307  if ( !is_set )
1308  return;
1309 
1310  if (threshold == "fatal") {
1312  } else if (threshold == "critical") {
1314  } else if (threshold == "error") {
1316  } else if (threshold == "warning") {
1318  } else if (threshold == "info") {
1320  } else if (threshold == "trace") {
1323  }
1324 }
1325 
1326 
1328 {
1329  const CCgiRequest& request = context.GetRequest();
1330 
1331  typedef map<string, TDiagPostFlags> TFlagMap;
1332  static CSafeStatic<TFlagMap> s_FlagMap;
1333  TFlagMap& flagmap = s_FlagMap.Get();
1334 
1337 
1339  defaults |= (eDPF_UID | eDPF_PID | eDPF_RequestId |
1341  }
1342 
1343  TDiagPostFlags new_flags = 0;
1344 
1345  bool is_set;
1346  string format = request.GetEntry("diag-format", &is_set);
1347  if ( !is_set )
1348  return;
1349 
1350  if (flagmap.empty()) {
1351  flagmap["file"] = eDPF_File;
1352  flagmap["path"] = eDPF_LongFilename;
1353  flagmap["line"] = eDPF_Line;
1354  flagmap["prefix"] = eDPF_Prefix;
1355  flagmap["severity"] = eDPF_Severity;
1356  flagmap["code"] = eDPF_ErrCode;
1357  flagmap["subcode"] = eDPF_ErrSubCode;
1358  flagmap["time"] = eDPF_DateTime;
1359  flagmap["omitinfosev"] = eDPF_OmitInfoSev;
1360  flagmap["all"] = eDPF_All;
1361  flagmap["trace"] = eDPF_Trace;
1362  flagmap["log"] = eDPF_Log;
1363  flagmap["errorid"] = eDPF_ErrorID;
1364  flagmap["location"] = eDPF_Location;
1365  flagmap["pid"] = eDPF_PID;
1366  flagmap["tid"] = eDPF_TID;
1367  flagmap["serial"] = eDPF_SerialNo;
1368  flagmap["serial_thr"] = eDPF_SerialNo_Thread;
1369  flagmap["iteration"] = eDPF_RequestId;
1370  flagmap["uid"] = eDPF_UID;
1371  }
1372  list<string> flags;
1373  NStr::Split(format, " ", flags,
1375  ITERATE(list<string>, flag, flags) {
1376  TFlagMap::const_iterator it;
1377  if ((it = flagmap.find(*flag)) != flagmap.end()) {
1378  new_flags |= it->second;
1379  } else if ((*flag)[0] == '!'
1380  && ((it = flagmap.find(flag->substr(1)))
1381  != flagmap.end())) {
1382  new_flags &= ~(it->second);
1383  } else if (*flag == "default") {
1384  new_flags |= defaults;
1385  }
1386  }
1387  SetDiagPostAllFlags(new_flags);
1388 }
1389 
1390 
1392 {
1393  string log = GetConfig().Get("CGI", "Log");
1394 
1396  if ((NStr::CompareNocase(log, "On") == 0) ||
1397  (NStr::CompareNocase(log, "true") == 0)) {
1398  logopt = eLog;
1399  } else if (NStr::CompareNocase(log, "OnError") == 0) {
1400  logopt = eLogOnError;
1401  }
1402 #ifdef _DEBUG
1403  else if (NStr::CompareNocase(log, "OnDebug") == 0) {
1404  logopt = eLog;
1405  }
1406 #endif
1407 
1408  return logopt;
1409 }
1410 
1411 
1413 {
1414  return new CCgiStatistics(*this);
1415 }
1416 
1417 
1420 {
1421  return 0;
1422 }
1423 
1424 
1425 bool CCgiApplication::IsCachingNeeded(const CCgiRequest& /*request*/) const
1426 {
1427  return true;
1428 }
1429 
1430 
1432 {
1433  return NULL;
1434 }
1435 
1436 
1439  const char* const* argv)
1440 {
1441  static const char* s_ArgVersion = "-version";
1442  static const char* s_ArgFullVersion = "-version-full";
1443 
1444  if (argc != 2 || !argv[1]) {
1445  return ePreparse_Continue;
1446  }
1447  if ( NStr::strcmp(argv[1], s_ArgVersion) == 0 ) {
1448  // Print VERSION
1451  return ePreparse_Exit;
1452  }
1453  else if ( NStr::strcmp(argv[1], s_ArgFullVersion) == 0 ) {
1454  // Print full VERSION
1456  return ePreparse_Exit;
1457  }
1458  return ePreparse_Continue;
1459 }
1460 
1461 
1462 void CCgiApplication::SetRequestId(const string& rid, bool is_done)
1463 {
1464  x_GetProcessor().SetRequestId(rid, is_done);
1465 }
1466 
1467 
1469 {
1470  string checksum, content;
1471  if (!request.CalcChecksum(checksum, content))
1472  return false;
1473 
1474  try {
1475  CCacheHashedContent helper(cache);
1476  unique_ptr<IReader> reader( helper.GetHashedContent(checksum, content));
1477  if (reader.get()) {
1478  //cout << "(Read) " << checksum << " --- " << content << endl;
1479  CRStream cache_reader(reader.get());
1480  return NcbiStreamCopy(os, cache_reader);
1481  }
1482  } catch (const exception& ex) {
1483  ERR_POST_X(5, "Couldn't read cached request : " << ex.what());
1484  }
1485  return false;
1486 }
1487 
1488 
1490 {
1491  string checksum, content;
1492  if ( !request.CalcChecksum(checksum, content) )
1493  return;
1494  try {
1495  CCacheHashedContent helper(cache);
1496  unique_ptr<IWriter> writer( helper.StoreHashedContent(checksum, content) );
1497  if (writer.get()) {
1498  // cout << "(Write) : " << checksum << " --- " << content << endl;
1499  CWStream cache_writer(writer.get());
1500  NcbiStreamCopy(cache_writer, is);
1501  }
1502  } catch (const exception& ex) {
1503  ERR_POST_X(6, "Couldn't cache request : " << ex.what());
1504  }
1505 }
1506 
1507 
1508 void CCgiApplication::SaveRequest(const string& rid, const CCgiRequest& request, ICache& cache)
1509 {
1510  if (rid.empty())
1511  return;
1512  try {
1513  unique_ptr<IWriter> writer( cache.GetWriteStream(rid, 0, "NS_JID") );
1514  if (writer.get()) {
1515  CWStream cache_stream(writer.get());
1516  request.Serialize(cache_stream);
1517  }
1518  } catch (const exception& ex) {
1519  ERR_POST_X(7, "Couldn't save request : " << ex.what());
1520  }
1521 }
1522 
1523 
1525 {
1526  if (rid.empty())
1527  return NULL;
1528  try {
1529  unique_ptr<IReader> reader(cache.GetReadStream(rid, 0, "NS_JID"));
1530  if (reader.get()) {
1531  CRStream cache_stream(reader.get());
1532  unique_ptr<CCgiRequest> request(new CCgiRequest);
1533  request->Deserialize(cache_stream, 0);
1534  return request.release();
1535  }
1536  } catch (const exception& ex) {
1537  ERR_POST_X(8, "Couldn't read saved request : " << ex.what());
1538  }
1539  return NULL;
1540 }
1541 
1542 
1544 {
1545  const CNcbiRegistry& reg = GetConfig();
1546 
1547  string cookie_name = GetConfig().Get("CGI-LB", "Name");
1548  if ( cookie_name.empty() )
1549  return;
1550 
1551  int life_span = reg.GetInt("CGI-LB", "LifeSpan", 0, 0,
1553 
1554  string domain = reg.GetString("CGI-LB", "Domain", ".ncbi.nlm.nih.gov");
1555 
1556  if ( domain.empty() ) {
1557  ERR_POST_X(9, "CGI-LB: 'Domain' not specified.");
1558  } else {
1559  if (domain[0] != '.') { // domain must start with dot
1560  domain.insert(0, ".");
1561  }
1562  }
1563 
1564  string path = reg.Get("CGI-LB", "Path");
1565 
1566  bool secure = reg.GetBool("CGI-LB", "Secure", false,
1568 
1569  string host;
1570 
1571  // Getting host configuration can take some time
1572  // for fast CGIs we try to avoid overhead and call it only once
1573  // m_HostIP variable keeps the cached value
1574 
1575  if ( m_HostIP ) { // repeated call
1576  host = m_HostIP;
1577  }
1578  else { // first time call
1579  host = reg.Get("CGI-LB", "Host");
1580  if ( host.empty() ) {
1581  if ( m_Caf.get() ) {
1582  char host_ip[64] = {0,};
1583  m_Caf->GetHostIP(host_ip, sizeof(host_ip));
1584  m_HostIP = m_Caf->Encode(host_ip, 0);
1585  host = m_HostIP;
1586  }
1587  else {
1588  ERR_POST_X(10, "CGI-LB: 'Host' not specified.");
1589  }
1590  }
1591  }
1592 
1593 
1594  CCgiCookie cookie(cookie_name, host, domain, path);
1595  if (life_span > 0) {
1596  CTime exp_time(CTime::eCurrent, CTime::eGmt);
1597  exp_time.AddSecond(life_span);
1598  cookie.SetExpTime(exp_time);
1599  }
1600  cookie.SetSecure(secure);
1601  cookies.Add(cookie);
1602 }
1603 
1604 
1606 {
1607  AddLBCookie(GetContext().GetResponse().Cookies());
1608 }
1609 
1610 
1612 {
1613  string x_moz = context.GetRequest().GetRandomProperty("X_MOZ");
1614  if ( NStr::EqualNocase(x_moz, "prefetch") ) {
1616  "Prefetch is not allowed for CGIs");
1617  ex.SetStatus(CCgiException::e403_Forbidden);
1618  ex.SetSeverity(eDiag_Info);
1620  }
1621 }
1622 
1623 
1625 {
1626  // Print application start message
1629  }
1630 }
1631 
1632 
1633 void CCgiApplication::AppStop(int exit_code)
1634 {
1635  GetDiagContext().SetExitCode(exit_code);
1636 }
1637 
1638 
1639 const char* kToolkitRcPath = "/etc/toolkitrc";
1640 const char* kWebDirToPort = "Web_dir_to_port";
1641 
1643 {
1644  string log_path = "/log/";
1645 
1646  string exe_path = GetProgramExecutablePath();
1647  CNcbiIfstream is(kToolkitRcPath, ios::binary);
1648  CNcbiRegistry reg(is);
1649  list<string> entries;
1651  size_t min_pos = exe_path.length();
1652  string web_dir;
1653  // Find the first dir name corresponding to one of the entries
1654  ITERATE(list<string>, it, entries) {
1655  if (!it->empty() && (*it)[0] != '/') {
1656  // not an absolute path
1657  string mask = "/" + *it;
1658  if (mask[mask.length() - 1] != '/') {
1659  mask += "/";
1660  }
1661  size_t pos = exe_path.find(mask);
1662  if (pos < min_pos) {
1663  min_pos = pos;
1664  web_dir = *it;
1665  }
1666  }
1667  else {
1668  // absolute path
1669  if (exe_path.substr(0, it->length()) == *it) {
1670  web_dir = *it;
1671  break;
1672  }
1673  }
1674  }
1675  if ( !web_dir.empty() ) {
1676  return log_path + reg.GetString(kWebDirToPort, web_dir, kEmptyStr);
1677  }
1678  // Could not find a valid web-dir entry, use port or 'srv'
1679  const char* port = ::getenv("SERVER_PORT");
1680  return port ? log_path + string(port) : log_path + "srv";
1681 }
1682 
1683 
1684 void CCgiApplication::SetHTTPStatus(unsigned int status, const string& reason)
1685 {
1686  if ( x_IsSetProcessor() ) {
1687  x_GetProcessor().SetHTTPStatus(status, reason);
1688  }
1689  else {
1691  }
1692 }
1693 
1694 
1696 {
1697  const CCgiRequest& req = context.GetRequest();
1698  const CCgiResponse& res = context.GetResponse();
1700  !res.IsHeaderWritten() ) {
1701  return false;
1702  }
1703  return true;
1704 }
1705 
1706 
1707 inline
1709 {
1710  // Prefer specific type over wildcard.
1711  bool this_wc = m_Type == "*";
1712  bool other_wc = entry.m_Type == "*";
1713  if (this_wc != other_wc) return !this_wc;
1714  // Prefer specific subtype over wildcard.
1715  this_wc = m_Subtype == "*";
1716  other_wc = entry.m_Subtype == "*";
1717  if (this_wc != other_wc) return !this_wc;
1718  // Prefer more specific media range params.
1719  if (m_MediaRangeParams.empty() != entry.m_MediaRangeParams.empty()) {
1720  return !m_MediaRangeParams.empty();
1721  }
1722  // Prefer higher quality factor.
1723  if (m_Quality != entry.m_Quality) return m_Quality > entry.m_Quality;
1724  // Otherwise sort by type/subtype values.
1725  if (m_Type != entry.m_Type) return m_Type < entry.m_Type;
1726  if (m_Subtype != entry.m_Subtype) return m_Subtype < entry.m_Subtype;
1727  // Otherwise (same type/subtype, quality factor and number of params)
1728  // consider entries equal.
1729  return false;
1730 }
1731 
1732 
1734 {
1736 }
1737 
1738 
1739 NCBI_PARAM_DECL(bool, CGI, EnableHelpRequest);
1740 NCBI_PARAM_DEF_EX(bool, CGI, EnableHelpRequest, true,
1741  eParam_NoThread, CGI_ENABLE_HELP_REQUEST);
1742 typedef NCBI_PARAM_TYPE(CGI, EnableHelpRequest) TEnableHelpRequest;
1743 
1744 
1746 {
1747  if (!TEnableHelpRequest::GetDefault()) return false;
1748  CCgiRequest& request = processor.GetContext().GetRequest();
1749  if (request.GetRequestMethod() != CCgiRequest::eMethod_GET) return false;
1750  bool found = false;
1751  string format = request.GetEntry("ncbi_help", &found);
1752  if ( !found ) return false;
1753  processor.ProcessHelpRequest(format);
1754  return true;
1755 }
1756 
1757 
1758 static const char* kStdFormats[] = { "html", "xml", "json" };
1759 static const char* kStdContentTypes[] = { "text/html", "text/xml", "application/json" };
1760 
1762  for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) {
1763  if (format == kStdFormats[i]) return kStdContentTypes[i];
1764  }
1765  return kEmptyStr;
1766 }
1767 
1768 
1770 {
1772 }
1773 
1774 
1775 NCBI_PARAM_DECL(string, CGI, EnableVersionRequest);
1776 NCBI_PARAM_DEF_EX(string, CGI, EnableVersionRequest, "t",
1777  eParam_NoThread, CGI_ENABLE_VERSION_REQUEST);
1778 typedef NCBI_PARAM_TYPE(CGI, EnableVersionRequest) TEnableVersionRequest;
1779 
1780 
1782 {
1783  CCgiRequest& request = processor.GetContext().GetRequest();
1784  if (request.GetRequestMethod() != CCgiRequest::eMethod_GET) return false;
1785 
1786  // If param value is a bool, enable the default ncbi_version CGI arg.
1787  // Otherwise try to use the value as the arg's name, then fallback to
1788  // ncbi_version.
1789  bool use_alt_name = false;
1790  string vparam = TEnableVersionRequest::GetDefault();
1791  if ( vparam.empty() ) return false;
1792  try {
1793  bool is_enabled = NStr::StringToBool(vparam);
1794  if (!is_enabled) return false;
1795  }
1796  catch (const CStringException&) {
1797  use_alt_name = true;
1798  }
1799 
1800  string ver_type;
1801  bool found = false;
1802  if ( use_alt_name ) {
1803  ver_type = request.GetEntry(vparam, &found);
1804  }
1805  if ( !found ) {
1806  ver_type = request.GetEntry("ncbi_version", &found);
1807  }
1808  if ( !found ) return false;
1809 
1810  EVersionType vt;
1811  if (ver_type.empty() || ver_type == "short") {
1812  vt = eVersion_Short;
1813  }
1814  else if (ver_type == "full") {
1815  vt = eVersion_Full;
1816  }
1817  else {
1819  "Unsupported ncbi_version argument value");
1820  }
1821  processor.ProcessVersionRequest(vt);
1822  return true;
1823 }
1824 
1825 
1827 {
1829 }
1830 
1832 {
1833  CCgiRequest& request = processor.GetContext().GetRequest();
1834  if (request.GetRequestMethod() != CCgiRequest::eMethod_GET) return false;
1835 
1836  bool found = false;
1837  string cmd_name = request.GetEntry("ncbi_admin_cmd", &found);
1838  if ( !found ) {
1839  // Check if PATH_INFO contains a command.
1840  string path_info = request.GetProperty(eCgi_PathInfo);
1841  NStr::TrimSuffixInPlace(path_info, "/");
1842  NStr::TrimPrefixInPlace(path_info, "/");
1843  if ( path_info.empty() ) return false;
1844  cmd_name = path_info;
1845  }
1847  if ( NStr::EqualNocase(cmd_name, "health") ) {
1848  cmd = eAdmin_Health;
1849  }
1850  else if ( NStr::EqualNocase(cmd_name, "deep-health") ) {
1852  }
1853  else if ( NStr::EqualNocase(cmd_name, "healthz") ) {
1854  cmd = eAdmin_HealthZ;
1855  }
1856  else if ( NStr::EqualNocase(cmd_name, "readyz") ) {
1857  cmd = eAdmin_ReadyZ;
1858  }
1859  else if ( NStr::EqualNocase(cmd_name, "livez") ) {
1860  cmd = eAdmin_LiveZ;
1861  }
1862 
1863  // If the overriden method failed or refused to process a command,
1864  // fallback to the default processing which returns true for all known commands.
1865  return processor.ProcessAdminRequest(cmd) || processor.ProcessAdminRequest_Base(cmd);
1866 }
1867 
1868 
1870 {
1872 }
1873 
1874 
1875 NCBI_PARAM_DECL(bool, CGI, ValidateCSRFToken);
1876 NCBI_PARAM_DEF_EX(bool, CGI, ValidateCSRFToken, false, eParam_NoThread,
1877  CGI_VALIDATE_CSRF_TOKEN);
1878 typedef NCBI_PARAM_TYPE(CGI, ValidateCSRFToken) TParamValidateCSRFToken;
1879 
1880 static const char* kCSRFTokenName = "NCBI_CSRF_TOKEN";
1881 
1883 {
1885 }
1886 
1887 
1889 {
1890  string path;
1891  const char* p = getenv("FCGI_STANDALONE_SERVER");
1892  if (p && *p) {
1893  path = p;
1894  } else {
1895  path = GetConfig().Get("FastCGI", "StandaloneServer");
1896  }
1897  return path;
1898 }
1899 
1900 
1902 {
1903  return GetConfig().GetBool("CGI", "StatLog", false, 0, CNcbiRegistry::eReturn);
1904 }
1905 
1906 
1907 unsigned int CCgiApplication::GetFastCGIIterations(unsigned int def_iter) const
1908 {
1909  int ret = def_iter;
1910  int x_iterations = GetConfig().GetInt("FastCGI", "Iterations", (int) def_iter, 0, CNcbiRegistry::eErrPost);
1911  if (x_iterations > 0) {
1912  ret = (unsigned int) x_iterations;
1913  } else {
1914  ERR_POST_X(6, "CCgiApplication::x_RunFastCGI: invalid "
1915  "[FastCGI].Iterations config.parameter value: "
1916  << x_iterations);
1917  _ASSERT(def_iter);
1918  ret = def_iter;
1919  }
1920 
1921  int iterations_rnd_inc = GetConfig().
1922  GetInt("FastCGI", "Iterations_Random_Increase", 0, 0, CNcbiRegistry::eErrPost);
1923  if (iterations_rnd_inc > 0) {
1924  ret += rand() % iterations_rnd_inc;
1925  }
1926 
1927  _TRACE("CCgiApplication::Run: FastCGI limited to "
1928  << ret << " iterations");
1929  return ret;
1930 }
1931 
1932 
1934 {
1935  return GetConfig().GetBool("FastCGI", "Complete_Request_On_Sigterm", false);
1936 }
1937 
1938 
1940 {
1941  const string& orig_filename = GetConfig().Get("FastCGI", "WatchFile.Name");
1942  if ( !orig_filename.empty() ) {
1943  string filename = CDirEntry::CreateAbsolutePath
1944  (orig_filename, CDirEntry::eRelativeToExe);
1945  if (filename != orig_filename) {
1946  _TRACE("Adjusted relative CGI watch file name " << orig_filename
1947  << " to " << filename);
1948  }
1949  int limit = GetConfig().GetInt("FastCGI", "WatchFile.Limit", -1, 0,
1951  if (limit <= 0) {
1952  limit = 1024; // set a reasonable default
1953  }
1954  return new CCgiWatchFile(filename, limit);
1955  }
1956  return nullptr;
1957 }
1958 
1959 
1960 unsigned int CCgiApplication::GetFastCGIWatchFileTimeout(bool have_watcher) const
1961 {
1962  int ret = GetConfig().GetInt("FastCGI", "WatchFile.Timeout", 0, 0, CNcbiRegistry::eErrPost);
1963  if (ret <= 0) {
1964  if ( have_watcher ) {
1965  ERR_POST_X(7, "CCgiApplication::x_RunFastCGI: non-positive "
1966  "[FastCGI].WatchFile.Timeout conf.param. value ignored: " << ret);
1967  }
1968  return 0;
1969  }
1970  return (unsigned int) ret;
1971 }
1972 
1973 
1975 {
1976  int ret = GetConfig().GetInt("FastCGI", "WatchFile.RestartDelay", 0, 0, CNcbiRegistry::eErrPost);
1977  if (ret <= 0) return 0;
1978  // CRandom is higher-quality, but would introduce an extra
1979  // dependency on libxutil; rand() should be good enough here.
1980  srand(CCurrentProcess::GetPid());
1981  double r = rand() / (RAND_MAX + 1.0);
1982  return 1 + (int)(ret * r);
1983 }
1984 
1985 
1987 {
1988  return GetConfig().GetBool("FastCGI", "ChannelErrors", false, 0, CNcbiRegistry::eReturn);
1989 }
1990 
1991 
1993 {
1994  return GetConfig().GetBool("FastCGI", "HonorExitRequest", false, 0, CNcbiRegistry::eErrPost);
1995 }
1996 
1998 {
1999  return GetConfig().GetBool("FastCGI", "Debug", false, 0, CNcbiRegistry::eErrPost);
2000 }
2001 
2002 
2004 {
2005  return GetConfig().GetBool("FastCGI", "StopIfFailed", false, 0, CNcbiRegistry::eErrPost);
2006 }
2007 
2008 
2010 {
2011  const int kDefaultMaxThreads = 8;
2012  int ret = GetConfig().GetInt("FastCGI", "MaxThreads", kDefaultMaxThreads, 0, CNcbiRegistry::eErrPost);
2013  if (ret <= 0) ret = kDefaultMaxThreads;
2014  return (unsigned int)ret;
2015 }
2016 
2017 
2019 {
2020  CTime mtime;
2021  if ( !CDirEntry(filename).GetTime(&mtime) ) {
2022  NCBI_THROW(CCgiErrnoException, eModTime,
2023  "Cannot get modification time of the CGI executable "
2024  + filename);
2025  }
2026  return mtime;
2027 }
2028 
2029 
2031 {
2033  GetConfig().GetString("FastCGI", "TotalMemoryLimit", "0", CNcbiRegistry::eReturn),
2035  if ( limit ) {
2036  CCurrentProcess::SMemoryUsage memory_usage;
2037  if ( !CCurrentProcess::GetMemoryUsage(memory_usage) ) {
2038  ERR_POST("Could not check self memory usage" );
2039  }
2040  else if (memory_usage.total > limit) {
2041  ERR_POST(Warning << "Memory usage (" << memory_usage.total <<
2042  ") is above the configured limit (" <<
2043  limit << ")");
2044  return true;
2045  }
2046  }
2047  return false;
2048 }
2049 
2050 
2051 DEFINE_STATIC_FAST_MUTEX(s_RestartReasonMutex);
2052 
2054 {
2055  static CSafeStatic<CTime> restart_time;
2056  static ERestartReason restart_reason = eSR_None;
2057 
2058  CFastMutexGuard guard(s_RestartReasonMutex);
2059  if (restart_reason != eSR_None) return restart_reason;
2060 
2061  // Check if this CGI executable has been changed
2064  if ( mtimeNew != mtime) {
2065  _TRACE("CCgiApplication::x_RunFastCGI: "
2066  "the program modification date has changed");
2067  restart_reason = eSR_Executable;
2068  } else if ( watcher && watcher->HasChanged()) {
2069  // Check if the file we're watching (if any) has changed
2070  // (based on contents, not timestamp!)
2071  ERR_POST_X(3, Warning <<
2072  "Scheduling restart of Fast-CGI, as its watch file has changed");
2073  restart_reason = eSR_WatchFile;
2074  }
2075 
2076  if (restart_reason != eSR_None) {
2077  if (restart_time->IsEmpty()) {
2078  restart_time->SetTimeZone(CTime::eGmt);
2079  restart_time->SetCurrent();
2080  restart_time->AddSecond(delay);
2081  _TRACE("Will restart Fast-CGI in " << delay << " seconds, at "
2082  << restart_time->GetLocalTime().AsString("h:m:s"));
2083  }
2084  if (CurrentTime(CTime::eGmt) >= *restart_time) {
2085  return restart_reason;
2086  }
2087  }
2088 
2089  return eSR_None;
2090 }
2091 
2092 
2094 {
2095  // Copy cmd-line arg values to CGI args
2096  args.Assign(CParent::GetArgs());
2097  // Add CGI parameters to the CGI version of args
2098  GetArgDescriptions()->ConvertKeys(&args, context.GetRequest().GetEntries(), true /*update=yes*/);
2099 }
2100 
2101 
2102 ///////////////////////////////////////////////////////
2103 // CCgiStatistics
2104 //
2105 
2106 
2108  : m_CgiApp(cgi_app), m_LogDelim(";")
2109 {
2110 }
2111 
2112 
2114 {
2115 }
2116 
2117 
2119  int result,
2120  const std::exception* ex)
2121 {
2123  m_Result = result;
2124  m_ErrMsg = ex ? ex->what() : kEmptyStr;
2125 }
2126 
2127 
2129 {
2130  const CNcbiRegistry& reg = m_CgiApp.GetConfig();
2131  CTime end_time(CTime::eCurrent);
2132 
2133  // Check if it is assigned NOT to log the requests took less than
2134  // cut off time threshold
2135  TSeconds time_cutoff = reg.GetInt("CGI", "TimeStatCutOff", 0, 0,
2137  if (time_cutoff > 0) {
2138  TSeconds diff = end_time.DiffSecond(m_StartTime);
2139  if (diff < time_cutoff) {
2140  return kEmptyStr; // do nothing if it is a light weight request
2141  }
2142  }
2143 
2144  string msg, tmp_str;
2145 
2146  tmp_str = Compose_ProgramName();
2147  if ( !tmp_str.empty() ) {
2148  msg.append(tmp_str);
2149  msg.append(m_LogDelim);
2150  }
2151 
2152  tmp_str = Compose_Result();
2153  if ( !tmp_str.empty() ) {
2154  msg.append(tmp_str);
2155  msg.append(m_LogDelim);
2156  }
2157 
2158  bool is_timing =
2159  reg.GetBool("CGI", "TimeStamp", false, 0, CNcbiRegistry::eErrPost);
2160  if ( is_timing ) {
2161  tmp_str = Compose_Timing(end_time);
2162  if ( !tmp_str.empty() ) {
2163  msg.append(tmp_str);
2164  msg.append(m_LogDelim);
2165  }
2166  }
2167 
2168  tmp_str = Compose_Entries();
2169  if ( !tmp_str.empty() ) {
2170  msg.append(tmp_str);
2171  }
2172 
2173  tmp_str = Compose_ErrMessage();
2174  if ( !tmp_str.empty() ) {
2175  msg.append(tmp_str);
2176  msg.append(m_LogDelim);
2177  }
2178 
2179  return msg;
2180 }
2181 
2182 
2183 void CCgiStatistics::Submit(const string& message)
2184 {
2185  LOG_POST_X(11, message);
2186 }
2187 
2188 
2190 {
2192 }
2193 
2194 
2195 string CCgiStatistics::Compose_Timing(const CTime& end_time)
2196 {
2197  CTimeSpan elapsed = end_time.DiffTimeSpan(m_StartTime);
2198  return m_StartTime.AsString() + m_LogDelim + elapsed.AsString();
2199 }
2200 
2201 
2203 {
2204  if (!m_CgiApp.x_GetProcessor().IsSetContext()) return kEmptyStr;
2205  const CCgiRequest& cgi_req = m_CgiApp.x_GetProcessor().GetContext().GetRequest();
2206 
2207  // LogArgs - list of CGI arguments to log.
2208  // Can come as list of arguments (LogArgs = param1;param2;param3),
2209  // or be supplemented with aliases (LogArgs = param1=1;param2=2;param3).
2210  // When alias is provided we use it for logging purposes (this feature
2211  // can be used to save logging space or reduce the net traffic).
2212  const CNcbiRegistry& reg = m_CgiApp.GetConfig();
2213  string log_args = reg.Get("CGI", "LogArgs");
2214  if ( log_args.empty() )
2215  return kEmptyStr;
2216 
2217  list<string> vars;
2218  NStr::Split(log_args, ",; \t", vars,
2220 
2221  string msg;
2222  ITERATE (list<string>, i, vars) {
2223  bool is_entry_found;
2224  const string& arg = *i;
2225 
2226  size_t pos = arg.find_last_of('=');
2227  if (pos == 0) {
2228  return "<misconf>" + m_LogDelim;
2229  } else if (pos != string::npos) { // alias assigned
2230  string key = arg.substr(0, pos);
2231  const CCgiEntry& entry = cgi_req.GetEntry(key, &is_entry_found);
2232  if ( is_entry_found ) {
2233  string alias = arg.substr(pos+1, arg.length());
2234  msg.append(alias);
2235  msg.append("='");
2236  msg.append(entry.GetValue());
2237  msg.append("'");
2238  msg.append(m_LogDelim);
2239  }
2240  } else {
2241  const CCgiEntry& entry = cgi_req.GetEntry(arg, &is_entry_found);
2242  if ( is_entry_found ) {
2243  msg.append(arg);
2244  msg.append("='");
2245  msg.append(entry.GetValue());
2246  msg.append("'");
2247  msg.append(m_LogDelim);
2248  }
2249  }
2250  }
2251 
2252  return msg;
2253 }
2254 
2255 
2257 {
2258  return NStr::IntToString(m_Result);
2259 }
2260 
2261 
2263 {
2264  return m_ErrMsg;
2265 }
2266 
2267 
2268 /////////////////////////////////////////////////////////////////////////////
2269 // CCgiWatchFile
2270 
2272 {
2273  CNcbiIfstream in(m_Filename.c_str());
2274  if (in) {
2275  in.read(buf, m_Limit);
2276  return (int) in.gcount();
2277  } else {
2278  return -1;
2279  }
2280 }
2281 
2282 CCgiWatchFile::CCgiWatchFile(const string& filename, int limit)
2283  : m_Filename(filename), m_Limit(limit), m_Buf(new char[limit])
2284 {
2285  m_Count = x_Read(m_Buf.get());
2286  if (m_Count < 0) {
2287  ERR_POST_X(2, "Failed to open CGI watch file " << filename);
2288  }
2289 }
2290 
2292 {
2293  TBuf buf(new char[m_Limit]);
2294  if (x_Read(buf.get()) != m_Count) {
2295  return true;
2296  } else if (m_Count == -1) { // couldn't be opened
2297  return false;
2298  } else {
2299  return memcmp(buf.get(), m_Buf.get(), m_Count) != 0;
2300  }
2301  // no need to update m_Count or m_Buf, since the CGI will restart
2302  // if there are any discrepancies.
2303 }
2304 
2305 
2306 ///////////////////////////////////////////////////////
2307 // CCgiRequestProcessor
2308 //
2309 
2310 
2312  : m_App(app)
2313 {
2314 }
2315 
2316 
2318 {
2319 }
2320 
2321 
2323 {
2324  _ASSERT(m_Context.get() == &context);
2325  return m_App.ProcessRequest(context);
2326 }
2327 
2328 
2330 {
2331  string base_name = m_App.GetProgramExecutablePath();
2332  string fname;
2333  string content_type;
2334  // If 'format' is set, try to find <basename>.help.<format> or help.<format> file.
2335  if ( !format.empty() ) {
2336  string fname_fmt = base_name + ".help." + format;
2337  if ( CFile(fname_fmt).Exists() ) {
2338  fname = fname_fmt;
2339  content_type = FindContentType(format);
2340  }
2341  else {
2342  fname_fmt = "help." + format;
2343  if ( CFile(fname_fmt).Exists() ) {
2344  fname = fname_fmt;
2345  content_type = FindContentType(format);
2346  }
2347  }
2348  }
2349 
2350  // If 'format' is not set or there's no file of the specified format, check
2351  // 'Accept:' header.
2352  if ( fname.empty() ) {
2356  string fname_accept = base_name + ".help." + it->m_Subtype + it->m_MediaRangeParams;
2357  if ( CFile(fname_accept).Exists() ) {
2358  fname = fname_accept;
2359  content_type = it->m_Type + "/" + it->m_Subtype;
2360  break;
2361  }
2362  }
2363  if ( fname.empty() ) {
2365  string fname_accept = "help." + it->m_Subtype + it->m_MediaRangeParams;
2366  if ( CFile(fname_accept).Exists() ) {
2367  fname = fname_accept;
2368  content_type = it->m_Type + "/" + it->m_Subtype;
2369  break;
2370  }
2371  }
2372  }
2373  }
2374 
2375  // Finally, check standard formats: html/xml/json
2376  if ( fname.empty() ) {
2377  for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) {
2378  string fname_std = base_name + ".help." + kStdFormats[i];
2379  if ( CFile(fname_std).Exists() ) {
2380  fname = fname_std;
2381  content_type = kStdContentTypes[i];
2382  break;
2383  }
2384  }
2385  }
2386  if ( fname.empty() ) {
2387  for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) {
2388  string fname_std = string("help.") + kStdFormats[i];
2389  if ( CFile(fname_std).Exists() ) {
2390  fname = fname_std;
2391  content_type = kStdContentTypes[i];
2392  break;
2393  }
2394  }
2395  }
2396 
2397  CCgiResponse& response = GetContext().GetResponse();
2398  if ( !fname.empty() ) {
2399  CNcbiIfstream in(fname.c_str());
2400 
2401  // Check if the file starts with "Content-type:" header followed by double-eol.
2402  bool ct_found = false;
2403  string ct;
2404  getline(in, ct);
2405  if ( NStr::StartsWith(ct, "content-type:", NStr::eNocase) ) {
2406  string eol;
2407  getline(in, eol);
2408  if ( eol.empty() ) {
2409  ct_found = true;
2410  content_type = NStr::TruncateSpaces(ct.substr(13));
2411  }
2412  }
2413  if ( !ct_found ) {
2414  in.seekg(0);
2415  }
2416 
2417  if ( !content_type.empty()) {
2418  response.SetContentType(content_type);
2419  }
2420  response.WriteHeader();
2421  NcbiStreamCopy(*response.GetOutput(), in);
2422  }
2423  else {
2424  // Could not find help file, use arg descriptions instead.
2425  const CArgDescriptions* args = m_App.GetArgDescriptions();
2426  if ( args ) {
2427  response.SetContentType("text/xml");
2428  response.WriteHeader();
2429  args->PrintUsageXml(*response.GetOutput());
2430  }
2431  else {
2433  "Can not find help for CGI application");
2434  }
2435  }
2436 }
2437 
2438 
2440 {
2441  string format = "plain";
2442  string content_type = "text/plain";
2446  if (it->m_Subtype == "xml" || it->m_Subtype == "json" ||
2447  (it->m_Type == "text" && it->m_Subtype == "plain")) {
2448  format = it->m_Subtype;
2449  content_type = it->m_Type + "/" + it->m_Subtype;
2450  break;
2451  }
2452  }
2453 
2454  CCgiResponse& response = GetContext().GetResponse();
2455  response.SetContentType(content_type);
2456  response.WriteHeader();
2457  CNcbiOstream& out = *response.GetOutput();
2458  if (format == "plain") {
2459  switch (ver_type) {
2461  out << m_App.GetVersion().Print();
2462  break;
2465  break;
2466  }
2467  }
2468  else if (format == "xml") {
2469  switch (ver_type) {
2472  break;
2475  break;
2476  }
2477  }
2478  else if (format == "json") {
2479  switch (ver_type) {
2482  break;
2485  break;
2486  }
2487  }
2488  else {
2490  "Unsupported version format");
2491  }
2492 }
2493 
2494 
2496 {
2497  return ProcessAdminRequest_Base(cmd);
2498 }
2499 
2500 
2502 {
2503  if (cmd == CCgiApplication::eAdmin_Unknown) return false;
2504 
2505  // By default report status 200 and write headers for any command.
2506  CCgiResponse& response = GetContext().GetResponse();
2507  response.SetContentType("text/plain");
2510  response.WriteHeader();
2511  return true;
2512 }
2513 
2514 
2516 {
2517  if (!TParamValidateCSRFToken::GetDefault()) return true;
2518  const CCgiRequest& req = GetContext().GetRequest();
2519  const string& token = req.GetRandomProperty(kCSRFTokenName, false);
2520  return !token.empty() && token == req.GetTrackingCookie();
2521 }
2522 
2523 
2525 {
2526  string ref = m_Context->GetSelfURL();
2527  if ( !ref.empty() ) {
2528  string args = m_Context->GetRequest().GetProperty(eCgi_QueryString);
2529  if ( !args.empty() ) ref += "?" + args;
2530  }
2531  return ref;
2532 }
2533 
2534 
2535 NCBI_PARAM_DECL(string, CGI, Exception_Message);
2536 NCBI_PARAM_DEF_EX(string, CGI, Exception_Message, "", eParam_NoThread,
2537  CGI_EXCEPTION_MESSAGE);
2538 typedef NCBI_PARAM_TYPE(CGI, Exception_Message) TExceptionMessage;
2539 
2540 
2542 {
2543  // Discriminate between different types of error
2544  string status_str = "500 Server Error";
2545  string message = "";
2546 
2547  // Save current HTTP status. Later it may be changed to 299 or 499
2548  // depending on this value.
2549  SetErrorStatus(CDiagContext::GetRequestContext().GetRequestStatus() >= 400);
2550  SetHTTPStatus(500);
2551 
2552  CException* ce = dynamic_cast<CException*> (&e);
2553  if ( ce ) {
2554  message = ce->GetMsg();
2555  CCgiException* cgi_e = dynamic_cast<CCgiException*>(&e);
2556  if ( cgi_e ) {
2557  if ( cgi_e->GetStatusCode() != CCgiException::eStatusNotSet ) {
2558  SetHTTPStatus(cgi_e->GetStatusCode());
2559  status_str = NStr::IntToString(cgi_e->GetStatusCode()) +
2560  " " + cgi_e->GetStatusMessage();
2561  }
2562  else {
2563  // Convert CgiRequestException and CCgiArgsException
2564  // to error 400
2565  if (dynamic_cast<CCgiRequestException*> (&e) ||
2566  dynamic_cast<CUrlException*> (&e)) {
2567  SetHTTPStatus(400);
2568  status_str = "400 Malformed HTTP Request";
2569  }
2570  }
2571  }
2572  }
2573  else {
2574  message = e.what();
2575  }
2576 
2577  // Don't try to write to a broken output
2578  if (!os.good() || GetOutputBroken()) {
2579  return -1;
2580  }
2581 
2582  string expt_msg = TExceptionMessage::GetDefault();
2583  if ( !expt_msg.empty() ) {
2584  message = expt_msg;
2585  }
2586 
2587  try {
2588  // HTTP header
2589  os << "Status: " << status_str << HTTP_EOL;
2590  os << "Content-Type: text/plain" HTTP_EOL HTTP_EOL;
2591 
2592  // Message
2593  os << "ERROR: " << status_str << " " HTTP_EOL HTTP_EOL;
2594  os << NStr::HtmlEncode(message) << HTTP_EOL HTTP_EOL;
2595 
2596  if ( dynamic_cast<CArgException*> (&e) ) {
2597  string ustr;
2598  const CArgDescriptions* descr = m_App.GetArgDescriptions();
2599  if (descr) {
2600  os << descr->PrintUsage(ustr) << HTTP_EOL HTTP_EOL;
2601  }
2602  }
2603 
2604  // Check for problems in sending the response
2605  if ( !os.good() ) {
2606  ERR_POST_X(4, "CCgiApplication::OnException() failed to send error page"
2607  " back to the client");
2608  return -1;
2609  }
2610  }
2611  catch (const exception& ex) {
2612  NCBI_REPORT_EXCEPTION_X(14, "(CGI) CCgiApplication::Run", ex);
2613  }
2614  return 0;
2615 }
2616 
2617 
2619 {
2620  return;
2621 }
2622 
2623 
2624 void CCgiRequestProcessor::SetHTTPStatus(unsigned int status, const string& reason)
2625 {
2626  if ( m_Context.get() ) {
2627  m_Context->GetResponse().SetStatus(status, reason);
2628  }
2629  else {
2631  }
2632 
2634  if ( span ) {
2635  span->SetAttribute(ITracerSpan::eStatusCode, NStr::NumericToString(status));
2636  span->SetAttribute(ITracerSpan::eStatusString, reason);
2637  }
2638 }
2639 
2640 
2641 void CCgiRequestProcessor::SetRequestId(const string& rid, bool is_done)
2642 {
2643  m_RID = rid;
2644  m_IsResultReady = is_done;
2645 }
2646 
2647 
2649 {
2650  string accept = GetContext().GetRequest().GetProperty(eCgi_HttpAccept);
2651  if (accept.empty()) return;
2652  list<string> types;
2654  ITERATE(list<string>, type_it, types) {
2655  list<string> parts;
2657  if ( parts.empty() ) continue;
2658  entries.push_back(TAcceptEntry());
2659  TAcceptEntry& entry = entries.back();
2660  NStr::SplitInTwo(NStr::TruncateSpaces(parts.front()), "/", entry.m_Type, entry.m_Subtype);
2663  list<string>::const_iterator ext_it = parts.begin();
2664  ++ext_it; // skip type/subtype
2665  bool aparams = false;
2666  while (ext_it != parts.end()) {
2667  string name, value;
2668  NStr::SplitInTwo(NStr::TruncateSpaces(*ext_it), "=", name, value);
2671  if (name == "q") {
2672  entry.m_Quality = NStr::StringToNumeric<float>(value, NStr::fConvErr_NoThrow);
2673  if (entry.m_Quality == 0 && errno != 0) {
2674  entry.m_Quality = 1;
2675  }
2676  aparams = true;
2677  ++ext_it;
2678  continue;
2679  }
2680  if (aparams) {
2681  entry.m_AcceptParams[name] = value;
2682  }
2683  else {
2684  entry.m_MediaRangeParams += ";" + name + "=" + value;
2685  }
2686  ++ext_it;
2687  }
2688  }
2689  entries.sort();
2690 }
2691 
2692 
2694 {
2695  m_CgiArgs.reset(new CArgs());
2697 }
2698 
2699 /////////////////////////////////////////////////////////////////////////////
2700 // Tracking Environment
2701 
2703 NCBI_PARAM_DEF(string, CGI, TrackingCookieName, "ncbi_sid");
2704 NCBI_PARAM_DEF(string, CGI, TrackingTagName, "NCBI-SID");
2707 
2708 
ncbi::TMaskedQueryRegions mask
cache (ICache) external reference using hash key(CRC32, MD5)
Exception classes used by the NCBI CGI framework.
NCBI_PARAM_DEF_EX(bool, CGI, Print_Http_Referer, true, eParam_NoThread, CGI_PRINT_HTTP_REFERER)
const char * kWebDirToPort
Definition: cgiapp.cpp:1640
NCBI_PARAM_ENUM_DEF_EX(EDiagSev, CGI, Client_Connection_Interruption_Severity, eDiag_Error, eParam_NoThread, CGI_CLIENT_CONNECTION_INTERRUPTION_SEVERITY)
const char * kToolkitRcPath
Definition: cgiapp.cpp:1639
typedef NCBI_PARAM_TYPE(CGI, Print_Http_Referer) TPrintRefererParam
DEFINE_STATIC_FAST_MUTEX(s_RestartReasonMutex)
static const char * kStdFormats[]
Definition: cgiapp.cpp:1758
NCBI_PARAM_ENUM_ARRAY(EDiagSev, CGI, Client_Connection_Interruption_Severity)
Definition: cgiapp.cpp:100
NCBI_PARAM_DEF(bool, CGI, DisableTrackingCookie, false)
string FindContentType(CTempString format)
Definition: cgiapp.cpp:1761
static void s_CleanupProcessor(CCgiRequestProcessor *processor, void *)
Definition: cgiapp.cpp:845
static const char * kStdContentTypes[]
Definition: cgiapp.cpp:1759
NCBI_PARAM_DECL(bool, CGI, Print_Http_Referer)
void SigTermHandler(int)
Definition: cgiapp.cpp:463
static const char * kCSRFTokenName
Definition: cgiapp.cpp:1880
CArgDescriptions –.
Definition: ncbiargs.hpp:541
CArgException –.
Definition: ncbiargs.hpp:120
CArgs –.
Definition: ncbiargs.hpp:379
CCgiApplication * m_App
Definition: cgiapp.cpp:1022
CAsBodyDiagFactory(CCgiApplication *app)
Definition: cgiapp.cpp:1009
virtual CDiagHandler * New(const string &)
Factory method interface.
Definition: cgiapp.cpp:1010
virtual ERW_Result Read(void *buf, size_t count, size_t *bytes_read=0)
Read as many as "count" bytes into a buffer pointed to by the "buf" argument.
Definition: cgiapp.cpp:135
virtual ERW_Result PendingCount(size_t *)
Via parameter "count" (which is guaranteed to be supplied non-NULL) return the number of bytes that a...
Definition: cgiapp.cpp:127
istream & m_IStr
Definition: cgiapp.cpp:131
CCGIStreamReader(istream &is)
Definition: cgiapp.cpp:122
Hashed content cache.
Definition: cache_ref.hpp:65
bool GetHashedContent(const string &hash_str, const string &hashed_content, string *ref_value)
Get hashed content Method compares both hash value and hashed content.
Definition: cache_ref.hpp:306
void StoreHashedContent(const string &hash_str, const string &hashed_content, const string &ref_value)
Store hashed content.
Definition: cache_ref.hpp:175
CCgiCookie::
Definition: ncbicgi.hpp:67
CCgiCookies::
Definition: ncbicgi.hpp:219
CCgiErrnoException –.
CCgiRequestException –.
Base class for request processors.
Definition: cgiapp.hpp:582
CCgiRequest::
Definition: ncbicgi.hpp:685
void FinishChunkedTransfer(const CCgiStreamWrapper::TTrailer *trailer)
Definition: cgiapp.cpp:368
void SetCacheStream(CNcbiOstream &stream)
Definition: cgiapp.cpp:358
virtual ERW_Result Write(const void *buf, size_t count, size_t *bytes_written=0)
Write up to "count" bytes from the buffer pointed to by the "buf" argument onto the output device.
Definition: cgiapp.cpp:235
CCgiStreamWrapper::EStreamMode GetMode(void) const
Definition: cgiapp.cpp:182
void x_WriteChunk(const char *buf, size_t count)
Definition: cgiapp.cpp:226
CCgiStreamWrapper::EStreamMode m_Mode
Definition: cgiapp.cpp:194
virtual ~CCgiStreamWrapperWriter(void)
Definition: cgiapp.cpp:218
void AbortChunkedTransfer(void)
Definition: cgiapp.cpp:389
void x_SetChunkSize(size_t sz)
Definition: cgiapp.cpp:399
void SetMode(CCgiStreamWrapper::EStreamMode mode)
Definition: cgiapp.cpp:334
virtual ERW_Result Flush(void)
Flush pending data (if any) down to the output device.
Definition: cgiapp.cpp:315
CCgiStreamWrapperWriter(CNcbiOstream &out)
Definition: cgiapp.cpp:206
CNcbiOstream * m_Out
Definition: cgiapp.cpp:195
Temporary object for holding extra message arguments.
Definition: ncbidiag.hpp:1828
CDiagFactory –.
Definition: ncbidiag.hpp:2925
CDiagRestorer –.
Definition: ncbidiag.hpp:2941
CDirEntry –.
Definition: ncbifile.hpp:262
CFile –.
Definition: ncbifile.hpp:1605
IWriter which can write simultaneously to the different streams.
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:264
CNcbiArguments –.
Definition: ncbienv.hpp:236
CNcbiEnvironment –.
Definition: ncbienv.hpp:110
CNcbiLogFields –.
Definition: ncbidiag.hpp:2397
CNcbiRegistry –.
Definition: ncbireg.hpp:913
Note about the "buf_size" parameter for streams in this API.
Definition: rwstream.hpp:122
Reader-writer-based stream buffer.
Definition: rwstreambuf.hpp:60
@ fOwnReader
Own the underlying reader.
Definition: rwstreambuf.hpp:66
@ fOwnWriter
Own the underlying writer.
Definition: rwstreambuf.hpp:67
CSafeStatic<>::
T & Get(void)
Create the variable if not created yet, return the reference.
virtual CDiagHandler * New(const string &)
Factory method interface.
Definition: cgiapp.cpp:1000
CStreamDiagHandler –.
Definition: ncbidiag.hpp:2596
CStringException –.
Definition: ncbistr.hpp:4500
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
CTimeSpan.
Definition: ncbitime.hpp:1313
CTime –.
Definition: ncbitime.hpp:296
CTls –.
Definition: ncbithr.hpp:166
CUrlArgs::
Definition: ncbi_url.hpp:240
CUrlException –.
Definition: ncbi_url.hpp:511
Writer-based output stream.
Definition: rwstream.hpp:171
BLOB cache read/write/maintenance interface.
Definition: icache.hpp:64
virtual IWriter * GetWriteStream(const string &key, TBlobVersion version, const string &subkey, unsigned int time_to_live=0, const string &owner=kEmptyStr)=0
Return sequential stream interface to write BLOB data.
virtual IReader * GetReadStream(const string &key, TBlobVersion version, const string &subkey)=0
Return sequential stream interface to read BLOB data.
ICgiSessionStorage –.
A very basic data-read interface.
A very basic data-write interface.
Severity –.
Definition: ncbidiag.hpp:833
const_iterator end() const
Definition: map.hpp:152
const_iterator find(const key_type &key) const
Definition: map.hpp:153
void Print(const CCompactSAMApplication::AlignInfo &ai)
static uch flags
std::ofstream out("events_result.xml")
main entry point for tests
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
CS_CONTEXT * ctx
Definition: t0006.c:12
static const struct name_t names[]
static int failure
Definition: t0019.c:11
static time_t start_time
Definition: timeout.c:14
#define false
Definition: bool.h:36
static const char * str(char *buf, int n)
Definition: stats.c:84
static const char * proc
Definition: stats.c:21
static HENV env
Definition: transaction2.c:38
static const struct type types[]
Definition: type.c:22
static FILE * f
Definition: readconf.c:23
static string GetAppName(EAppNameType name_type=eBaseName, int argc=0, const char *const *argv=NULL)
Definition: ncbiapp.cpp:1390
const CNcbiEnvironment & GetEnvironment(void) const
Get the application's cached environment.
const string & GetProgramExecutablePath(EFollowLinks follow_links=eIgnoreLinks) const
Get the application's executable path.
virtual void Init(void)
Initialize the application.
Definition: ncbiapp.cpp:286
const CNcbiRegistry & GetConfig(void) const
Get the application's cached configuration parameters (read-only).
virtual const CArgs & GetArgs(void) const
Get parsed command line arguments.
Definition: ncbiapp.cpp:305
CVersionInfo GetVersion(void) const
Get the program version information.
Definition: ncbiapp.cpp:1197
virtual void SetupArgDescriptions(CArgDescriptions *arg_desc)
Setup the command line argument descriptions.
Definition: ncbiapp.cpp:1208
EPreparseArgs
Result of PreparseArgs()
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
void SetStdioFlags(TStdioSetupFlags stdio_flags)
Adjust the behavior of standard I/O streams.
Definition: ncbiapp.cpp:1331
const CArgDescriptions * GetArgDescriptions(void) const
Get argument descriptions (set by SetupArgDescriptions)
element_type * get(void) const
Get pointer.
Definition: ncbimisc.hpp:469
virtual void Exit(void)
Cleanup on application exit.
Definition: ncbiapp.cpp:299
const string & GetProgramDisplayName(void) const
Get the application's "display" name.
void DisableArgDescriptions(TDisableArgDesc disable=fDisableStdArgs)
Definition: ncbiapp.cpp:1319
CNcbiRegistry & GetRWConfig(void)
Get the application's cached configuration parameters, accessible for read-write for an application's...
const CVersionAPI & GetFullVersion(void) const
Get the program version information.
Definition: ncbiapp.cpp:1202
const CNcbiArguments & GetArguments(void) const
Get the application's cached unprocessed command-line arguments.
@ fBinaryCout
treat standard output as binary
@ fBinaryCin
treat standard input as binary
@ ePreparse_Exit
Exit the application with zero exit code.
@ ePreparse_Continue
Continue application execution.
virtual string & PrintUsage(string &str, bool detailed=false) const
Print usage message to end of specified string.
Definition: ncbiargs.cpp:3815
virtual void PrintUsageXml(CNcbiOstream &out) const
Print argument description in XML format.
Definition: ncbiargs.cpp:3953
CArgs & Assign(const CArgs &other)
Copy contents of another object into this one.
Definition: ncbiargs.cpp:1770
void SetArgsType(EArgSetType args_type)
Set type of argument description (cmdline vs CGI).
Definition: ncbiargs.cpp:2361
void ConvertKeys(CArgs *args, const T &arg_map, bool update) const
Convert argument map (key-value pairs) into arguments in accordance with the argument descriptions.
Definition: ncbiargs.hpp:1320
@ eCgiArgs
CGI application.
Definition: ncbiargs.hpp:561
void x_InitArgs(void) const
Definition: cgiapp.cpp:2693
void SetHTTPStatus(unsigned int status, const string &reason=kEmptyStr)
Definition: cgiapp.cpp:2624
virtual void SetupArgDescriptions(CArgDescriptions *arg_desc)
Setup the command line argument descriptions.
Definition: cgiapp.cpp:794
EAdminCommand
Admin commands passed through ncbi_admin_cmd argument.
Definition: cgiapp.hpp:327
virtual string Compose_Entries(void)
Definition: cgiapp.cpp:2202
virtual void Init(void)
This method is called on the CGI application initialization – before starting to process a HTTP reque...
Definition: cgiapp.cpp:864
virtual int OnException(std::exception &e, CNcbiOstream &os)
This method is called if an exception is thrown during the processing of HTTP request.
Definition: cgiapp.cpp:1059
unsigned int GetFastCGIWatchFileTimeout(bool have_watcher) const
Definition: cgiapp.cpp:1960
bool GetRequestStartPrinted(void) const
Definition: cgiapp.hpp:660
virtual string Compose_ErrMessage(void)
Definition: cgiapp.cpp:2262
const CCgiResponse & GetResponse(void) const
Definition: cgictx.hpp:388
virtual ~CCgiStatistics()
Definition: cgiapp.cpp:2113
void SetOutputBroken(bool val)
Definition: cgiapp.hpp:658
const CCgiContext & GetContext(void) const
Get current server context. Throw exception if the context is not set.
Definition: cgiapp.hpp:78
void SetRequestStartPrinted(bool val)
Definition: cgiapp.hpp:661
bool GetFastCGIComplete_Request_On_Sigterm(void) const
Definition: cgiapp.cpp:1933
TrackingCookieName
Definition: cgiapp.hpp:690
bool CheckMemoryLimit(void)
Definition: cgiapp.cpp:2030
virtual string Compose_Result(void)
Definition: cgiapp.cpp:2256
CCgiStatistics(CCgiApplication &cgi_app)
Definition: cgiapp.cpp:2107
virtual bool x_RunFastCGI(int *result, unsigned int def_iter=10)
Definition: cgi_run.cpp:44
void SetErrorStatus(bool val)
Definition: cgiapp.hpp:664
const CCgiRequest & GetRequest(void) const
Definition: cgictx.hpp:374
unsigned int GetFastCGIIterations(unsigned int def_iter) const
Definition: cgiapp.cpp:1907
string m_Filename
Definition: cgiapp.hpp:536
shared_ptr< CCgiContext > m_Context
Definition: cgiapp.hpp:620
string m_LogDelim
Definition: cgiapp.hpp:513
CCgiStreamWrapperWriter * m_Writer
Definition: cgiapp.hpp:575
bool GetOutputBroken(void) const
Definition: cgiapp.hpp:657
unsigned int GetFastCGIMTMaxThreads(void) const
Definition: cgiapp.cpp:2009
void AbortChunkedTransfer(void)
Definition: cgiapp.cpp:446
string
Definition: cgiapp.hpp:690
friend class CCgiRequestProcessor
Definition: cgiapp.hpp:65
CDiagFactory * FindDiagFactory(const string &key)
Definition: cgiapp.cpp:1266
CAtomicCounter m_Iteration
Definition: cgiapp.hpp:437
virtual void ProcessVersionRequest(CCgiApplication::EVersionType ver_type)
Definition: cgiapp.cpp:2439
virtual void ConfigureDiagFormat(CCgiContext &context)
Definition: cgiapp.cpp:1327
int GetFastCGIWatchFileRestartDelay(void) const
Definition: cgiapp.cpp:1974
CCgiApplication(const SBuildInfo &build_info=NCBI_SBUILDINFO_DEFAULT())
Definition: cgiapp.cpp:1026
virtual CCgiRequestProcessor * CreateRequestProcessor(void)
Create request processor to process the request.
Definition: cgiapp.cpp:981
CTime m_StartTime
Definition: cgiapp.hpp:514
virtual void ConfigureDiagnostics(CCgiContext &context)
Definition: cgiapp.cpp:1275
char * m_HostIP
Definition: cgiapp.hpp:459
virtual int ProcessRequest(CCgiContext &context)
Process request provided by the context. By default calls application's ProcessRequest.
Definition: cgiapp.cpp:2322
int x_Read(char *buf)
Definition: cgiapp.cpp:2271
static CTime GetFileModificationTime(const string &filename)
Definition: cgiapp.cpp:2018
string m_MediaRangeParams
Media range parameters.
Definition: cgiapp.hpp:351
int m_RequestFlags
Bit flags for CCgiRequest.
Definition: cgiapp.hpp:378
CCgiRequestProcessor & x_GetProcessor(void) const
Definition: cgiapp.cpp:828
bool ProcessAdminRequest_Base(CCgiApplication::EAdminCommand cmd)
Definition: cgiapp.cpp:2501
virtual void Exit(void)
This method is called on the CGI application exit.
Definition: cgiapp.cpp:879
bool HasChanged(void)
Definition: cgiapp.cpp:2291
virtual ~CCgiRequestProcessor(void)
Definition: cgiapp.cpp:2317
virtual void ConfigureDiagDestination(CCgiContext &context)
Definition: cgiapp.cpp:1284
bool x_IsSetProcessor(void) const
Definition: cgiapp.cpp:822
virtual ICgiSessionStorage * GetSessionStorage(CCgiSessionParameters &params) const
Get instance of CGI session storage interface.
Definition: cgiapp.cpp:1419
virtual EPreparseArgs PreparseArgs(int argc, const char *const *argv)
Check the command line arguments before parsing them.
Definition: cgiapp.cpp:1438
CArgs & GetArgs(void)
Definition: cgiapp.hpp:643
virtual bool ProcessAdminRequest(CCgiApplication::EAdminCommand cmd)
Definition: cgiapp.cpp:2495
bool GetFastCGIStatLog(void) const
Definition: cgiapp.cpp:1901
void RegisterDiagFactory(const string &key, CDiagFactory *fact)
Definition: cgiapp.cpp:1259
CCgiApplication::SAcceptEntry TAcceptEntry
Definition: cgiapp.hpp:611
void SetInputStream(CNcbiIstream *in)
Definition: cgiapp.hpp:649
unique_ptr< CNcbiResource > m_Resource
Definition: cgiapp.hpp:453
CCgiWatchFile(const string &filename, int limit=1024)
Definition: cgiapp.cpp:2282
void SetCacheStream(CNcbiOstream &stream)
Definition: cgiapp.cpp:434
CNcbiResource & x_GetResource(void) const
Definition: cgiapp.cpp:812
virtual const CArgs & GetArgs(void) const
Get parsed command line arguments extended with CGI parameters.
Definition: cgiapp.cpp:1065
void x_AddLBCookie()
Definition: cgiapp.cpp:1605
bool GetFastCGIStopIfFailed(void) const
Definition: cgiapp.cpp:2003
static bool ProcessCORSRequest(const CCgiRequest &request, CCgiResponse &response)
Process cross-origin resource sharing (CORS) request.
Definition: cgictx.cpp:839
bool x_ProcessHelpRequest(CCgiRequestProcessor &processor)
Definition: cgiapp.cpp:1745
virtual void OnEvent(EEvent event, int status)
This method is called after each request, or when the CGI is forced to skip a request,...
Definition: cgiapp.cpp:1252
CNcbiOstream & GetOutputStream(void)
Definition: cgiapp.hpp:652
virtual void OnEvent(CCgiApplication::EEvent event, int status)
Definition: cgiapp.cpp:2618
virtual void ProcessHelpRequest(const string &format)
Definition: cgiapp.cpp:2329
float m_Quality
Quality factor or "1" if not set (or not numeric).
Definition: cgiapp.hpp:350
virtual void Reset(const CTime &start_time, int result, const std::exception *ex=0)
Definition: cgiapp.cpp:2118
bool GetErrorStatus(void) const
Definition: cgiapp.hpp:663
CCgiApplication & m_App
Definition: cgiapp.hpp:619
EStreamMode GetWriterMode(void)
Definition: cgiapp.cpp:421
virtual void ConfigureDiagThreshold(CCgiContext &context)
Definition: cgiapp.cpp:1301
DisableTrackingCookie
Definition: cgiapp.hpp:688
string GetFastCGIStandaloneServer(void) const
Definition: cgiapp.cpp:1888
static ERestartReason ShouldRestart(CTime &mtime, CCgiWatchFile *watcher, int delay)
Definition: cgiapp.cpp:2053
virtual bool ProcessAdminRequest(EAdminCommand cmd)
Process admin command passed through ncbi_admin_cmd argument.
Definition: cgiapp.cpp:1869
bool operator<(const SAcceptEntry &entry) const
Definition: cgiapp.cpp:1708
CCgiContext & x_GetContext(void) const
Definition: cgiapp.cpp:802
void SetRequestId(const string &rid, bool is_done)
Definition: cgiapp.cpp:2641
void SetHTTPStatus(unsigned int status, const string &reason=kEmptyStr)
Set HTTP status code in the current request context and in the current CHttpResponse if one exists.
Definition: cgiapp.cpp:1684
bool x_ProcessAdminRequest(CCgiRequestProcessor &processor)
Definition: cgiapp.cpp:1831
virtual void AppStart(void)
Prepare properties and print the application start message.
Definition: cgiapp.cpp:1624
virtual CCgiContext * CreateContext(CNcbiArguments *args=0, CNcbiEnvironment *env=0, CNcbiIstream *inp=0, CNcbiOstream *out=0, int ifd=-1, int ofd=-1)
Factory method for the Context object construction.
Definition: cgiapp.cpp:900
void x_OnEvent(CCgiRequestProcessor *pprocessor, EEvent event, int status)
Definition: cgiapp.cpp:1073
bool x_DoneHeadRequest(CCgiContext &context) const
Definition: cgiapp.cpp:1695
void ParseAcceptHeader(TAcceptEntries &entries) const
Definition: cgiapp.cpp:2648
virtual ICache * GetCacheStorage(void) const
Definition: cgiapp.cpp:1431
unique_ptr< CCookieAffinity > m_Caf
Definition: cgiapp.hpp:458
virtual string Compose(void)
Definition: cgiapp.cpp:2128
CCgiApplication::TAcceptEntries TAcceptEntries
Definition: cgiapp.hpp:610
virtual int OnException(std::exception &e, CNcbiOstream &os)
Definition: cgiapp.cpp:2541
virtual string Compose_ProgramName(void)
Definition: cgiapp.cpp:2189
void SetWriterMode(EStreamMode mode)
Definition: cgiapp.cpp:427
bool IsSetOutputStream(void) const
Definition: cgiapp.hpp:655
virtual int Run(void)
Do not override this method yourself! – it includes all the CGI specific machinery.
Definition: cgiapp.cpp:468
TrackingTagName
Definition: cgiapp.hpp:692
ELogOpt GetLogOpt(void) const
Definition: cgiapp.cpp:1391
virtual bool ValidateSynchronizationToken(void)
Definition: cgiapp.cpp:2515
string GetRID(void) const
Definition: cgiapp.hpp:666
TDiagFactoryMap m_DiagFactories
Definition: cgiapp.hpp:456
TrackingCookiePath
Definition: cgiapp.hpp:696
ELogOpt
Analyze registry settings ([CGI] Log) and return current logging option.
Definition: cgiapp.hpp:256
virtual bool ValidateSynchronizationToken(void)
Validate synchronization token (cross-site request forgery prevention).
Definition: cgiapp.cpp:1882
virtual bool IsCachingNeeded(const CCgiRequest &request) const
Definition: cgiapp.cpp:1425
friend class CCgiStatistics
Definition: cgiapp.hpp:64
string m_DiagPrefixEnv
Definition: cgiapp.hpp:462
virtual void Submit(const string &message)
Definition: cgiapp.cpp:2183
virtual CCgiStatistics * CreateStat()
Class factory for statistics class.
Definition: cgiapp.cpp:1412
void SetRequestId(const string &rid, bool is_done)
Definition: cgiapp.cpp:1462
virtual void ProcessHelpRequest(const string &format)
Process help request: set content type, print usage informations etc.
Definition: cgiapp.cpp:1769
virtual CNcbiResource * LoadResource(void)
Definition: cgiapp.cpp:887
virtual string Compose_Timing(const CTime &end_time)
Definition: cgiapp.cpp:2195
void SaveResultToCache(const CCgiRequest &request, CNcbiIstream &is, ICache &cache)
Definition: cgiapp.cpp:1489
bool x_ProcessVersionRequest(CCgiRequestProcessor &processor)
Definition: cgiapp.cpp:1781
bool IsSetInputStream(void) const
Definition: cgiapp.hpp:650
void InitArgs(CArgs &args, CCgiContext &context) const
Definition: cgiapp.cpp:2093
void SetContext(shared_ptr< CCgiContext > context)
Definition: cgiapp.hpp:640
CCgiApplication & m_CgiApp
Definition: cgiapp.hpp:512
void SaveRequest(const string &rid, const CCgiRequest &request, ICache &cache)
Definition: cgiapp.cpp:1508
CCgiRequestProcessor * x_GetProcessorOrNull(void) const
Definition: cgiapp.cpp:839
string m_ErrMsg
Definition: cgiapp.hpp:516
void SetOutputStream(CNcbiOstream *out)
Definition: cgiapp.hpp:654
bool IsSetContext(void) const
Definition: cgiapp.hpp:641
virtual CCgiServerContext * LoadServerContext(CCgiContext &context)
Definition: cgiapp.cpp:893
static CCgiApplication * Instance(void)
Singleton.
Definition: cgiapp.cpp:457
virtual void ProcessVersionRequest(EVersionType ver_type)
Process version request: set content type, print version informations etc.
Definition: cgiapp.cpp:1826
virtual CCgiContext * CreateContextWithFlags(CNcbiArguments *args, CNcbiEnvironment *env, CNcbiIstream *inp, CNcbiOstream *out, int ifd, int ofd, int flags)
The same as CreateContext(), but allows for a custom set of flags to be specified in the CCgiRequest ...
Definition: cgiapp.cpp:912
CCgiContext & GetContext(void)
Definition: cgiapp.hpp:638
CCgiRequestProcessor & x_CreateProcessor(void)
Definition: cgiapp.cpp:851
CCgiRequest * GetSavedRequest(const string &rid, ICache &cache)
Definition: cgiapp.cpp:1524
string GetSelfReferer(void) const
Get self-URL to be used as referer.
Definition: cgiapp.cpp:2524
CCgiRequestProcessor(CCgiApplication &app)
Definition: cgiapp.cpp:2311
list< SAcceptEntry > TAcceptEntries
Definition: cgiapp.hpp:357
CRef< CTls< CCgiRequestProcessor > > m_Processor
Definition: cgiapp.hpp:436
CCgiContext * CreateContextWithFlags_Default(CCgiRequestProcessor &processor, CNcbiArguments *args, CNcbiEnvironment *env, CNcbiIstream *inp, CNcbiOstream *out, int ifd, int ofd, int flags)
Default implementation of CreateContextWithFlags.
Definition: cgiapp.cpp:925
Client_Connection_Interruption_Okay
Definition: cgiapp.hpp:699
virtual int ProcessRequest(CCgiContext &context)=0
This is the method you should override.
void ParseAcceptHeader(TAcceptEntries &entries) const
Parse "Accept:" header, put entries to the list, more specific first.
Definition: cgiapp.cpp:1733
void SetCafService(CCookieAffinity *caf)
Attach cookie affinity service interface.
Definition: cgiapp.cpp:987
bool GetFastCGIDebug(void) const
Definition: cgiapp.cpp:1997
CCgiWatchFile * CreateFastCGIWatchFile(void) const
Definition: cgiapp.cpp:1939
unique_ptr< CArgs > m_CgiArgs
Definition: cgiapp.hpp:622
CCgiStreamWrapper(CNcbiOstream &out)
Definition: cgiapp.cpp:414
~CCgiApplication(void)
Definition: cgiapp.cpp:1049
Client_Connection_Interruption_Severity
Definition: cgiapp.hpp:703
virtual string GetDefaultLogPath(void) const
Get default path for the log files.
Definition: cgiapp.cpp:1642
CNcbiIstream & GetInputStream(void)
Definition: cgiapp.hpp:647
bool GetResultReady(void) const
Definition: cgiapp.hpp:669
bool GetResultFromCache(const CCgiRequest &request, CNcbiOstream &os, ICache &cache)
Definition: cgiapp.cpp:1468
virtual void AppStop(int exit_code)
Prepare properties for application stop message.
Definition: cgiapp.cpp:1633
void LogRequest(void) const
Definition: cgiapp.cpp:715
bool GetFastCGIHonorExitRequest(void) const
Definition: cgiapp.cpp:1992
TParams m_AcceptParams
Accept parameters.
Definition: cgiapp.hpp:352
void VerifyCgiContext(CCgiContext &context)
Check CGI context for possible problems, throw exception with HTTP status set if something is wrong.
Definition: cgiapp.cpp:1611
void FinishChunkedTransfer(const TTrailer *trailer)
Definition: cgiapp.cpp:440
const string & GetSelfURL(ESelfUrlPort) const
Using HTTP environment variables, compose the CGI's own URL as: SCHEME://SERVER_NAME[:SERVER_PORT]/SC...
Definition: cgictx.hpp:217
bool GetFastCGIChannelErrors(void) const
Definition: cgiapp.cpp:1986
void AddLBCookie(CCgiCookies &cookies)
Definition: cgiapp.cpp:1543
TrackingCookieDomain
Definition: cgiapp.hpp:694
void ProcessHttpReferer(void)
Set CONN_HTTP_REFERER, print self-URL and referer to log.
Definition: cgiapp.cpp:704
CGI
Definition: cgiapp.hpp:688
@ eAdmin_HealthZ
Report health for this CGI as kubernetes expects.
Definition: cgiapp.hpp:330
@ eAdmin_Health
Report health for this CGI only.
Definition: cgiapp.hpp:328
@ eAdmin_Unknown
Unrecognized command.
Definition: cgiapp.hpp:333
@ eAdmin_HealthDeep
Report health for this CGI and any services used by it.
Definition: cgiapp.hpp:329
@ eAdmin_LiveZ
Report if this CGI is alive as kubernetes expects.
Definition: cgiapp.hpp:332
@ eAdmin_ReadyZ
Report readyness for this CGI as kubernetes expects.
Definition: cgiapp.hpp:331
@ eException
An exception occured during the request processing.
Definition: cgiapp.hpp:193
@ eExitRequest
FCGI forced to exit by client's 'exitfastcgi' request.
Definition: cgiapp.hpp:199
@ eExit
No more iterations, exiting (called the very last)
Definition: cgiapp.hpp:195
@ eWaiting
Periodic awakening while waiting for the next request.
Definition: cgiapp.hpp:192
@ eError
The HTTP request was processed, non-zero exit code.
Definition: cgiapp.hpp:191
@ eEndRequest
HTTP request processed, all results sent to client.
Definition: cgiapp.hpp:194
@ eExecutable
FCGI forced to exit as its modif. time has changed.
Definition: cgiapp.hpp:196
@ eWatchFile
FCGI forced to exit as its "watch file" has changed.
Definition: cgiapp.hpp:197
@ eExitOnFail
[FastCGI].StopIfFailed set, and the iteration failed
Definition: cgiapp.hpp:198
@ eSuccess
The HTTP request was processed, with zero exit code.
Definition: cgiapp.hpp:190
#define NCBI_CGI_THROW_WITH_STATUS(exception, err_code, message, status)
EStatusCode GetStatusCode(void) const
static string GetStdStatusMessage(EStatusCode code)
string GetStatusMessage(void) const
@ eStatusNotSet
Internal value - code not set.
bool HaveContentRange(void) const
Check if 'Content-Range' header is set.
Definition: ncbicgir.cpp:586
void SetSecure(bool secure)
Definition: ncbicgi.hpp:1022
bool CalcChecksum(string &checksum, string &content) const
Definition: ncbicgi.cpp:1771
SIZE_TYPE find(const char *s, SIZE_TYPE pos=0) const
Definition: ncbicgi.hpp:544
CCgiCookie * Find(const string &name, const string &domain, const string &path)
Return NULL if cannot find this exact cookie.
Definition: ncbicgi.cpp:690
void Serialize(CNcbiOstream &os) const
Serialize/Deserialize a request to/from a stream.
Definition: ncbicgi.cpp:1566
void GetCGIEntries(CEntryCollector_Base &collector) const
Get full set of arguments (both GET and POST), URL-encoded.
Definition: ncbicgi.cpp:1648
CNcbiOstream & out(void) const
Get output stream. Throw exception if GetOutput() is NULL.
Definition: ncbicgir.cpp:257
const string & GetValue() const
Get the value as a string, (necessarily) prefetching it all if applicable; the result remains availab...
Definition: ncbicgi.hpp:470
void SetExpTime(const CTime &exp_time)
Definition: ncbicgi.cpp:363
const CCgiCookies & GetCookies(void) const
Retrieve the request cookies.
Definition: ncbicgi.hpp:1173
static bool x_ClientSupportsChunkedTransfer(const CNcbiEnvironment &env)
Definition: ncbicgir.cpp:639
string substr(SIZE_TYPE i=0, SIZE_TYPE n=NPOS) const
Definition: ncbicgi.hpp:542
void SetOutput(CNcbiOstream *os, int fd=-1)
Set output stream (NULL here means "no output stream").
Definition: ncbicgir.cpp:223
const string & GetProperty(ECgiProp prop) const
Get value of a "standard" property (return empty string if not defined)
Definition: ncbicgi.cpp:1432
CDiagContext_Extra::TExtraArgs & GetArgs(void)
Definition: ncbicgi.hpp:670
const string & GetTrackingCookie(void) const
Definition: ncbicgi.hpp:926
CCgiCookie * Add(const string &name, const string &value, const string &domain=kEmptyStr, const string &path=kEmptyStr, EOnBadCookie on_bad_cookie=eOnBadCookie_SkipAndError)
All Add() functions: if the added cookie has the same {name, domain, path} as an already existing one...
Definition: ncbicgi.cpp:383
static size_t GetChunkSize(void)
Definition: ncbicgir.cpp:633
bool IsHeaderWritten() const
Definition: ncbicgir.hpp:406
bool AcceptRangesBytes(void) const
Check if 'Accept-Ranges' header is set to 'bytes'.
Definition: ncbicgir.cpp:579
void SetContentType(const string &type)
Set content type (text/html by default if not provided)
Definition: ncbicgir.hpp:337
const string & GetRandomProperty(const string &key, bool http=true) const
Get value of a random client property; if "http" is TRUE then add prefix "HTTP_" to the property name...
Definition: ncbicgi.cpp:1438
CNcbiOstream & WriteHeader(void) const
Write HTTP response header to the output stream.
Definition: ncbicgir.hpp:396
const CCgiEntry & GetEntry(const string &name, bool *is_found=0) const
Get entry value by name.
Definition: ncbicgi.cpp:1449
static const string GetPropertyName(ECgiProp prop)
Get name (not value!) of a "standard" property.
Definition: ncbicgi.cpp:949
CNcbiOstream * GetOutput(void) const
Get output stream (NULL here means "no output stream").
Definition: ncbicgir.cpp:239
ERequestMethod GetRequestMethod(void) const
Get request method.
Definition: ncbicgi.cpp:1810
@ eCgi_ServerProtocol
Definition: ncbicgi.hpp:383
@ eCgi_ContentType
Definition: ncbicgi.hpp:391
@ eCgi_ServerName
Definition: ncbicgi.hpp:381
@ eCgi_HttpUserAgent
Definition: ncbicgi.hpp:411
@ eCgi_HttpReferer
Definition: ncbicgi.hpp:410
@ eCgi_HttpAccept
Definition: ncbicgi.hpp:407
@ eCgi_PathInfo
Definition: ncbicgi.hpp:396
@ eCgi_RemoteAddr
Definition: ncbicgi.hpp:388
@ eCgi_ContentLength
Definition: ncbicgi.hpp:392
@ eCgi_RequestMethod
Definition: ncbicgi.hpp:395
@ eCgi_QueryString
Definition: ncbicgi.hpp:399
@ eCgi_ServerPort
Definition: ncbicgi.hpp:384
@ eCgi_ScriptName
Definition: ncbicgi.hpp:398
#define NULL
Definition: ncbistd.hpp:225
void Set(TValue new_value) THROWS_NONE
Set atomic counter value.
Definition: ncbicntr.hpp:185
#define _TRACE(message)
Definition: ncbidbg.hpp:122
virtual CDiagHandler * New(const string &s)=0
Factory method interface.
void PushDiagPostPrefix(const char *prefix)
Push a string to the list of message prefixes.
Definition: ncbidiag.cpp:6112
void PrintRequestStop(void)
Print request stop message (for request-driven applications)
Definition: ncbidiag.cpp:2778
CDiagContext_Extra & Print(const string &name, const string &value)
The method does not print the argument, but adds it to the string.
Definition: ncbidiag.cpp:2622
void SetBytesWr(Int8 bytes)
void SetDiagPostFlag(EDiagPostFlag flag)
Set the specified flag (globally).
Definition: ncbidiag.cpp:6073
#define LOG_POST_X(err_subcode, message)
Definition: ncbidiag.hpp:553
static bool IsSetOldPostFormat(void)
Check old/new format flag (for compatibility only)
Definition: ncbidiag.cpp:3346
void PrintStart(const string &message)
Print start/stop etc.
Definition: ncbidiag.cpp:2095
CDiagContext & GetDiagContext(void)
Get diag context instance.
Definition: logging.cpp:818
void SetTracerSpanKind(ITracerSpan::ESpanKind kind)
At least Opentememetry tracer allows to set span kind only at span creation time.
void SetAppState(EDiagAppState state)
Set application state.
Definition: ncbidiag.cpp:2815
void PrintRequestStart(const string &message)
Print request start message (for request-driven applications)
Definition: ncbidiag.cpp:2762
CDiagContext_Extra Extra(void) const
Create a temporary CDiagContext_Extra object.
Definition: ncbidiag.hpp:2095
int TDiagPostFlags
Binary OR of "EDiagPostFlag".
Definition: ncbidiag.hpp:785
void SetProperty(const string &name, const string &value)
Add/change property.
shared_ptr< ITracerSpan > GetTracerSpan(void) const
static CRequestContext & GetRequestContext(void)
Shortcut to CDiagContextThreadData::GetThreadData().GetRequestContext()
Definition: ncbidiag.cpp:1901
void SetRequestStatus(int status)
EDiagSev SetDiagPostLevel(EDiagSev post_sev=eDiag_Error)
Set the threshold severity for posting the messages.
Definition: ncbidiag.cpp:6132
void SetExitCode(int exit_code)
Set exit code.
Definition: ncbidiag.hpp:2176
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
void Flush(void)
Print the message and reset object.
Definition: ncbidiag.cpp:2332
void SetBytesRd(Int8 bytes)
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
void SetDiagHandler(CDiagHandler *handler, bool can_delete=true)
Set the diagnostic handler using the specified diagnostic handler class.
Definition: ncbidiag.cpp:6291
void Reset(void)
Reset all properties to the initial state.
void SetDiagTrace(EDiagTrace how, EDiagTrace dflt=eDT_Default)
Set the diagnostic trace settings.
Definition: ncbidiag.cpp:6229
EDiagSev
Severity level for the posted diagnostics.
Definition: ncbidiag.hpp:650
TDiagPostFlags SetDiagPostAllFlags(TDiagPostFlags flags)
Set global post flags to "flags".
Definition: ncbidiag.cpp:6068
void SetDiagTraceFlag(EDiagPostFlag flag)
Definition: ncbidiag.cpp:6089
@ eDPF_UID
Definition: ncbidiag.hpp:712
@ eDPF_SerialNo_Thread
Definition: ncbidiag.hpp:709
@ eDPF_TID
Thread ID.
Definition: ncbidiag.hpp:705
@ eDPF_Location
Include class and function if any.
Definition: ncbidiag.hpp:704
@ eDPF_PID
Definition: ncbidiag.hpp:707
@ eDPF_MergeLines
Escape EOLs.
Definition: ncbidiag.hpp:751
@ eDPF_DateTime
Include date and time.
Definition: ncbidiag.hpp:700
@ eDPF_ErrorID
Error code and subcode (default)
Definition: ncbidiag.hpp:698
@ eDPF_RequestId
Definition: ncbidiag.hpp:710
@ eDPF_Log
Print the posted message only; without severity, location, prefix, etc.
Definition: ncbidiag.hpp:747
@ eDPF_Severity
Severity (default)
Definition: ncbidiag.hpp:697
@ eDPF_OmitInfoSev
No sev. indication if eDiag_Info.
Definition: ncbidiag.hpp:753
@ eDPF_ErrSubCode
Definition: ncbidiag.hpp:715
@ eDPF_Line
Source line.
Definition: ncbidiag.hpp:695
@ eDPF_Trace
Default flags to use when tracing.
Definition: ncbidiag.hpp:722
@ eDPF_File
File name (not full path)
Definition: ncbidiag.hpp:693
@ eDPF_ErrCode
Definition: ncbidiag.hpp:714
@ eDPF_LongFilename
Full file path.
Definition: ncbidiag.hpp:694
@ eDPF_SerialNo
Definition: ncbidiag.hpp:708
@ eDPF_Prefix
Prefix (default)
Definition: ncbidiag.hpp:696
@ eDPF_All
All flags (except for the "unusual" ones!)
Definition: ncbidiag.hpp:718
@ eDT_Enable
Enable messages of severity "eDiag_Trace".
Definition: ncbidiag.hpp:1550
@ eDiagAppState_RequestEnd
RE.
Definition: ncbidiag.hpp:796
@ eDiagAppState_RequestBegin
RB.
Definition: ncbidiag.hpp:794
@ eDiagAppState_Request
R.
Definition: ncbidiag.hpp:795
@ eDiag_Trace
Trace message.
Definition: ncbidiag.hpp:657
@ eDiag_Info
Informational message.
Definition: ncbidiag.hpp:651
@ eDiag_Error
Error message.
Definition: ncbidiag.hpp:653
@ eDiag_Warning
Warning message.
Definition: ncbidiag.hpp:652
@ eDiag_Fatal
Fatal error – guarantees exit(or abort)
Definition: ncbidiag.hpp:655
@ eDiag_Critical
Critical error message.
Definition: ncbidiag.hpp:654
@ e299_PartialContentBrokenConnection
Non-standard status code - used to indicate broken connection while serving partial-content request.
@ e499_BrokenConnection
Non-standard status code - used to indicate broken connection while serving normal request.
const string & Get(const string &name, bool *found=NULL) const
Get environment value by name.
Definition: ncbienv.cpp:109
void Enumerate(list< string > &names, const string &prefix=kEmptyStr) const
Find all variable names starting with an optional prefix.
Definition: ncbienv.cpp:133
const string & GetProgramName(EFollowLinks follow_links=eIgnoreLinks) const
Get program name.
Definition: ncbienv.cpp:373
#define NCBI_EXCEPTION_VAR(name, exception_class, err_code, message)
Create an instance of the exception to be thrown later.
Definition: ncbiexpt.hpp:684
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
const string & GetMsg(void) const
Get message string.
Definition: ncbiexpt.cpp:461
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
#define NCBI_EXCEPTION_THROW(exception_var)
Throw an existing exception object.
Definition: ncbiexpt.hpp:688
#define NCBI_REPORT_EXCEPTION_X(err_subcode, title, ex)
Generate a report on the exception with default error code and given subcode.
Definition: ncbiexpt.hpp:761
static string CreateAbsolutePath(const string &path, ERelativeToWhat rtw=eRelativeToCwd)
Get an absolute path from some, possibly relative, path.
Definition: ncbifile.cpp:665
virtual bool Exists(void) const
Check existence of file.
Definition: ncbifile.hpp:4039
@ eRelativeToExe
Relative to the executable's location.
Definition: ncbifile.hpp:440
@ eParam_NoThread
Do not use per-thread values.
Definition: ncbi_param.hpp:418
uint64_t Uint8
8-byte (64-bit) unsigned integer
Definition: ncbitype.h:105
static TPid GetPid(void)
Get process identifier (pid) for the current process.
size_t total
Total memory usage.
static bool GetMemoryUsage(SMemoryUsage &usage)
Get current process memory usage.
virtual bool GetBool(const string &section, const string &name, bool default_value, TFlags flags=0, EErrAction err_action=eThrow) const
Get boolean value of specified parameter name.
Definition: ncbireg.cpp:391
virtual const string & Get(const string &section, const string &name, TFlags flags=0) const
Get the parameter value.
Definition: ncbireg.cpp:262
virtual int GetInt(const string &section, const string &name, int default_value, TFlags flags=0, EErrAction err_action=eThrow) const
Get integer value of specified parameter name.
Definition: ncbireg.cpp:362
virtual void EnumerateEntries(const string &section, list< string > *entries, TFlags flags=fAllLayers) const
Enumerate parameter names for a specified section.
Definition: ncbireg.cpp:514
virtual string GetString(const string &section, const string &name, const string &default_value, TFlags flags=0) const
Get the parameter string value.
Definition: ncbireg.cpp:321
bool Set(const string &section, const string &name, const string &value, TFlags flags=0, const string &comment=kEmptyStr)
Set the configuration parameter value.
Definition: ncbireg.cpp:826
@ eReturn
Return default value.
Definition: ncbireg.hpp:203
@ eErrPost
Log the error message and return default value.
Definition: ncbireg.hpp:202
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
ERW_Result
Result codes for I/O operations.
Int8 NcbiStreamposToInt8(NCBI_NS_STD::char_traits< char >::pos_type stream_pos)
Convert stream position to 64-bit int.
Definition: ncbistre.hpp:771
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
#define NcbiCout
Definition: ncbistre.hpp:543
IO_PREFIX::istream CNcbiIstream
Portable alias for istream.
Definition: ncbistre.hpp:146
static streamsize Readsome(CNcbiIstream &is, CT_CHAR_TYPE *buf, streamsize buf_size)
#define NcbiCerr
Definition: ncbistre.hpp:544
IO_PREFIX::ifstream CNcbiIfstream
Portable alias for ifstream.
Definition: ncbistre.hpp:439
bool NcbiStreamCopy(CNcbiOstream &os, CNcbiIstream &is)
Copy the entire contents of stream "is" to stream "os".
Definition: ncbistre.cpp:211
@ eRW_NotImplemented
Action / information is not available.
@ eRW_Eof
End of data, should be considered permanent.
@ eRW_Error
Unrecoverable error, no retry possible.
@ eRW_Success
Everything is okay, I/O completed.
static bool StringToBool(const CTempString str)
Convert string to bool.
Definition: ncbistr.cpp:2812
NCBI_NS_STD::string::size_type SIZE_TYPE
Definition: ncbistr.hpp:132
#define kEmptyStr
Definition: ncbistr.hpp:123
static int CompareNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive compare of a substring with another string.
Definition: ncbistr.cpp:219
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3452
static int strcmp(const char *s1, const char *s2)
String compare.
Definition: ncbistr.hpp:5202
const char * g_GetNcbiString(ENcbiStrings what)
Definition: ncbi_strings.c:42
static string HtmlEncode(const CTempString str, THtmlEncode flags=fHtmlEnc_EncodeAll)
Encode a string for HTML.
Definition: ncbistr.cpp:4113
static Uint8 StringToUInt8_DataSize(const CTempString str, TStringToNumFlags flags=0)
Convert string that can contain "software" qualifiers to Uint8.
Definition: ncbistr.cpp:1530
static void TruncateSpacesInPlace(string &str, ETrunc where=eTrunc_Both)
Truncate whitespace in a string (in-place)
Definition: ncbistr.cpp:3192
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5078
bool AStrEquiv(const Arg1 &x, const Arg2 &y, Pred pr)
Check equivalence of arguments using predicate.
Definition: ncbistr.hpp:5031
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5406
static void TrimSuffixInPlace(string &str, const CTempString suffix, ECase use_case=eCase)
Trim suffix from a string (in-place)
Definition: ncbistr.cpp:3269
static bool SplitInTwo(const CTempString str, const CTempString delim, string &str1, string &str2, TSplitFlags flags=0)
Split a string into two pieces using the specified delimiters.
Definition: ncbistr.cpp:3545
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5347
static void TrimPrefixInPlace(string &str, const CTempString prefix, ECase use_case=eCase)
Trim prefix from a string (in-place)
Definition: ncbistr.cpp:3233
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3396
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate whitespace in a string.
Definition: ncbistr.cpp:3177
static string & ToLower(string &str)
Convert string to lower case – string& version.
Definition: ncbistr.cpp:405
@ eNcbiStrings_Stat
Definition: ncbi_strings.h:55
@ fConvErr_NoThrow
Do not throw an exception on error.
Definition: ncbistr.hpp:285
@ fSplit_Truncate
Definition: ncbistr.hpp:2503
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2500
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
void Reset(void)
Reset thread local storage.
Definition: ncbithr.hpp:217
void SetValue(TValue *value, FCleanup cleanup=0, void *cleanup_data=0, ENativeThreadCleanup native=eSkipCleanup)
Set value.
Definition: ncbithr.hpp:203
TValue * GetValue(void) const
Get the pointer previously stored by SetValue().
Definition: ncbithr.hpp:179
Int8 TSeconds
Number of seconds.
Definition: ncbitime.hpp:77
CTime & AddSecond(TSeconds seconds=1, EDaylight adl=eDaylightDefault)
Add specified seconds.
Definition: ncbitime.cpp:1880
string AsString(const CTimeFormat &format=kEmptyStr, TSeconds out_tz=eCurrentTimeZone) const
Transform time to string.
Definition: ncbitime.cpp:1512
CTime CurrentTime(CTime::ETimeZone tz=CTime::eLocal, CTime::ETimeZonePrecision tzp=CTime::eTZPrecisionDefault)
Definition: ncbitime.hpp:2184
CTimeSpan DiffTimeSpan(const CTime &t) const
Difference in nanoseconds from specified time.
Definition: ncbitime.cpp:2305
TSeconds DiffSecond(const CTime &t) const
Difference in seconds from specified time.
Definition: ncbitime.cpp:2282
string AsString(const CTimeFormat &fmt=kEmptyStr) const
Transform time span to string.
Definition: ncbitime.cpp:2681
@ eCurrent
Use current time. See also CCurrentTime.
Definition: ncbitime.hpp:300
@ eGmt
GMT (Greenwich Mean Time)
Definition: ncbitime.hpp:308
const TArgs & GetArgs(void) const
Get the const list of arguments.
Definition: ncbi_url.hpp:300
list< TArg > TArgs
Definition: ncbi_url.hpp:276
virtual string Print(void) const
Print version information.
Definition: version.cpp:120
string Print(const string &appname, TPrintFlags flags=fPrintAll) const
Print version data, plain text.
Definition: version.cpp:728
string PrintXml(const string &appname, TPrintFlags flags=fPrintAll) const
Print version data, XML.
Definition: version.cpp:774
string PrintJson(const string &appname, TPrintFlags flags=fPrintAll) const
Print version data, JSON.
Definition: version.cpp:824
@ fPackageShort
Print package info, if available.
@ fVersionInfo
Print version info.
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
Definition of all error codes used in cgi (xcgi.lib).
char * buf
int i
const TYPE & Get(const CNamedParameterList *param)
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::KEY key
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
Static variables safety - create on demand, destroy on application termination.
String constants used in NCBI C/C++ toolkit.
void SuppressSystemMessageBox(TSuppressSystemMessageBox mode=fSuppress_Default)
Suppress popup messages on execution errors.
const char * s_ArgFullVersion
Definition: ncbiargs.cpp:85
const char * s_ArgVersion
Definition: ncbiargs.cpp:84
Defines unified interface to application:
#define GetProgramName
Avoid name clash with the NCBI C Toolkit.
Definition: ncbienv.hpp:49
#define HTTP_EOL
Definition: ncbistre.hpp:120
T min(T x_, T y_)
static Format format
Definition: njn_ioutil.cpp:53
std::istream & in(std::istream &in_, double &x_)
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
#define count
Defines CRequestContext class for NCBI C++ diagnostic API.
Reader-writer based streams.
static SLJIT_INLINE sljit_ins st(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
static SLJIT_INLINE sljit_ins msg(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
"Accept:" header entry.
Definition: cgiapp.hpp:343
Process memory usage information, in bytes.
This class allows to add build info (date and tag) to application version.
Definition: version_api.hpp:62
#define _ASSERT
else result
Definition: token2.c:20
static CS_CONTEXT * context
Definition: will_convert.c:21
static wxAcceleratorEntry entries[3]
void free(voidpf ptr)
Modified on Fri Sep 20 14:57:56 2024 by modify_doxy.py rev. 669887