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

Go to the SVN repository for this file.

1 /* $Id: cgiapp.cpp 100914 2023-09-29 13:09:15Z sadyrovr $
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 
226 void CCgiStreamWrapperWriter::x_WriteChunk(const char* buf, size_t count)
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  // Print request start message
1085  CExtraEntryCollector collector;
1086  req.GetCGIEntries(collector);
1088  .AllowBadSymbolsInArgNames()
1089  .Print(collector.GetArgs());
1090  processor.SetRequestStartPrinted(true);
1091  }
1092 
1093  // Set default HTTP status code (reset above by PrintRequestStart())
1094  processor.SetHTTPStatus(200);
1095  processor.SetErrorStatus(false);
1096 
1097  // This will log ncbi_phid as a separate 'extra' message
1098  // if not yet logged.
1100 
1101  // Check if ncbi_st cookie is set
1103  if ( st ) {
1104  CUrlArgs pg_info(st->GetValue());
1105  // Log ncbi_st values
1107  // extra.SetType("NCBICGI");
1108  ITERATE(CUrlArgs::TArgs, it, pg_info.GetArgs()) {
1109  extra.Print(it->name, it->value);
1110  }
1111  extra.Flush();
1112  }
1113  break;
1114  }
1115  case eSuccess:
1116  case eError:
1117  case eException:
1118  {
1119  if (!pprocessor) break;
1120  CCgiRequestProcessor& processor = *pprocessor;
1122  try {
1123  if ( processor.IsSetInputStream() ) {
1124  auto& in = processor.GetInputStream();
1125  if ( !in.good() ) {
1126  in.clear();
1127  }
1128  rctx.SetBytesRd(NcbiStreamposToInt8(in.tellg()));
1129  }
1130  }
1131  catch (const exception&) {
1132  }
1133  try {
1134  if ( processor.IsSetOutputStream() ) {
1135  auto& out = processor.GetOutputStream();
1136  if ( !out.good() ) {
1137  processor.SetOutputBroken(true); // set flag to indicate broken output
1138  out.clear();
1139  }
1140  rctx.SetBytesWr(NcbiStreamposToInt8(out.tellp()));
1141  }
1142  }
1143  catch (const exception&) {
1144  }
1145  break;
1146  }
1147  case eEndRequest:
1148  {
1149  if (!pprocessor) break;
1150  CCgiRequestProcessor& processor = *pprocessor;
1151  CCgiContext& cgi_ctx = processor.GetContext();
1152  CDiagContext& diag_ctx = GetDiagContext();
1154  // If an error status has been set by ProcessRequest, don't try
1155  // to check the output stream and change the status to 299/499.
1156  if ( !processor.GetErrorStatus() ) {
1157  // Log broken connection as 299/499 status
1158  CNcbiOstream* os = processor.IsSetContext() ?
1159  cgi_ctx.GetResponse().GetOutput() : NULL;
1160  if ((os && !os->good()) || processor.GetOutputBroken()) {
1161  // 'Accept-Ranges: bytes' indicates a request for
1162  // content length, broken connection is OK.
1163  // If Content-Range is also set, the client was downloading
1164  // partial data. Broken connection is not OK in this case.
1165  if (TClientConnIntOk::GetDefault() ||
1166  (cgi_ctx.GetResponse().AcceptRangesBytes() &&
1167  !cgi_ctx.GetResponse().HaveContentRange())) {
1168  rctx.SetRequestStatus(
1170  }
1171  else {
1172  rctx.SetRequestStatus(
1174  }
1175  }
1176  }
1178  if (processor.GetRequestStartPrinted()) {
1179  // This will also reset request context
1180  diag_ctx.PrintRequestStop();
1181  processor.SetRequestStartPrinted(false);
1182  }
1183  rctx.Reset();
1184  }
1185  break;
1186  }
1187  case eExit:
1188  case eExecutable:
1189  case eWatchFile:
1190  case eExitOnFail:
1191  case eExitRequest:
1192  case eWaiting:
1193  {
1194  break;
1195  }
1196  }
1197 
1198  OnEvent(event, status);
1199 }
1200 
1201 
1203  int exit_code)
1204 {
1205  if (x_IsSetProcessor()) x_GetProcessor().OnEvent(event, exit_code);
1206 }
1207 
1208 
1210  CDiagFactory* fact)
1211 {
1212  m_DiagFactories[key] = fact;
1213 }
1214 
1215 
1217 {
1219  if (it == m_DiagFactories.end())
1220  return 0;
1221  return it->second;
1222 }
1223 
1224 
1226 {
1227  // Disable for production servers?
1231 }
1232 
1233 
1235 {
1236  const CCgiRequest& request = context.GetRequest();
1237 
1238  bool is_set;
1239  string dest = request.GetEntry("diag-destination", &is_set);
1240  if ( !is_set )
1241  return;
1242 
1243  SIZE_TYPE colon = dest.find(':');
1244  CDiagFactory* factory = FindDiagFactory(dest.substr(0, colon));
1245  if ( factory ) {
1246  SetDiagHandler(factory->New(dest.substr(colon + 1)));
1247  }
1248 }
1249 
1250 
1252 {
1253  const CCgiRequest& request = context.GetRequest();
1254 
1255  bool is_set;
1256  string threshold = request.GetEntry("diag-threshold", &is_set);
1257  if ( !is_set )
1258  return;
1259 
1260  if (threshold == "fatal") {
1262  } else if (threshold == "critical") {
1264  } else if (threshold == "error") {
1266  } else if (threshold == "warning") {
1268  } else if (threshold == "info") {
1270  } else if (threshold == "trace") {
1273  }
1274 }
1275 
1276 
1278 {
1279  const CCgiRequest& request = context.GetRequest();
1280 
1281  typedef map<string, TDiagPostFlags> TFlagMap;
1282  static CSafeStatic<TFlagMap> s_FlagMap;
1283  TFlagMap& flagmap = s_FlagMap.Get();
1284 
1287 
1289  defaults |= (eDPF_UID | eDPF_PID | eDPF_RequestId |
1291  }
1292 
1293  TDiagPostFlags new_flags = 0;
1294 
1295  bool is_set;
1296  string format = request.GetEntry("diag-format", &is_set);
1297  if ( !is_set )
1298  return;
1299 
1300  if (flagmap.empty()) {
1301  flagmap["file"] = eDPF_File;
1302  flagmap["path"] = eDPF_LongFilename;
1303  flagmap["line"] = eDPF_Line;
1304  flagmap["prefix"] = eDPF_Prefix;
1305  flagmap["severity"] = eDPF_Severity;
1306  flagmap["code"] = eDPF_ErrCode;
1307  flagmap["subcode"] = eDPF_ErrSubCode;
1308  flagmap["time"] = eDPF_DateTime;
1309  flagmap["omitinfosev"] = eDPF_OmitInfoSev;
1310  flagmap["all"] = eDPF_All;
1311  flagmap["trace"] = eDPF_Trace;
1312  flagmap["log"] = eDPF_Log;
1313  flagmap["errorid"] = eDPF_ErrorID;
1314  flagmap["location"] = eDPF_Location;
1315  flagmap["pid"] = eDPF_PID;
1316  flagmap["tid"] = eDPF_TID;
1317  flagmap["serial"] = eDPF_SerialNo;
1318  flagmap["serial_thr"] = eDPF_SerialNo_Thread;
1319  flagmap["iteration"] = eDPF_RequestId;
1320  flagmap["uid"] = eDPF_UID;
1321  }
1322  list<string> flags;
1323  NStr::Split(format, " ", flags,
1325  ITERATE(list<string>, flag, flags) {
1326  TFlagMap::const_iterator it;
1327  if ((it = flagmap.find(*flag)) != flagmap.end()) {
1328  new_flags |= it->second;
1329  } else if ((*flag)[0] == '!'
1330  && ((it = flagmap.find(flag->substr(1)))
1331  != flagmap.end())) {
1332  new_flags &= ~(it->second);
1333  } else if (*flag == "default") {
1334  new_flags |= defaults;
1335  }
1336  }
1337  SetDiagPostAllFlags(new_flags);
1338 }
1339 
1340 
1342 {
1343  string log = GetConfig().Get("CGI", "Log");
1344 
1346  if ((NStr::CompareNocase(log, "On") == 0) ||
1347  (NStr::CompareNocase(log, "true") == 0)) {
1348  logopt = eLog;
1349  } else if (NStr::CompareNocase(log, "OnError") == 0) {
1350  logopt = eLogOnError;
1351  }
1352 #ifdef _DEBUG
1353  else if (NStr::CompareNocase(log, "OnDebug") == 0) {
1354  logopt = eLog;
1355  }
1356 #endif
1357 
1358  return logopt;
1359 }
1360 
1361 
1363 {
1364  return new CCgiStatistics(*this);
1365 }
1366 
1367 
1370 {
1371  return 0;
1372 }
1373 
1374 
1375 bool CCgiApplication::IsCachingNeeded(const CCgiRequest& /*request*/) const
1376 {
1377  return true;
1378 }
1379 
1380 
1382 {
1383  return NULL;
1384 }
1385 
1386 
1389  const char* const* argv)
1390 {
1391  static const char* s_ArgVersion = "-version";
1392  static const char* s_ArgFullVersion = "-version-full";
1393 
1394  if (argc != 2 || !argv[1]) {
1395  return ePreparse_Continue;
1396  }
1397  if ( NStr::strcmp(argv[1], s_ArgVersion) == 0 ) {
1398  // Print VERSION
1401  return ePreparse_Exit;
1402  }
1403  else if ( NStr::strcmp(argv[1], s_ArgFullVersion) == 0 ) {
1404  // Print full VERSION
1406  return ePreparse_Exit;
1407  }
1408  return ePreparse_Continue;
1409 }
1410 
1411 
1412 void CCgiApplication::SetRequestId(const string& rid, bool is_done)
1413 {
1414  x_GetProcessor().SetRequestId(rid, is_done);
1415 }
1416 
1417 
1419 {
1420  string checksum, content;
1421  if (!request.CalcChecksum(checksum, content))
1422  return false;
1423 
1424  try {
1425  CCacheHashedContent helper(cache);
1426  unique_ptr<IReader> reader( helper.GetHashedContent(checksum, content));
1427  if (reader.get()) {
1428  //cout << "(Read) " << checksum << " --- " << content << endl;
1429  CRStream cache_reader(reader.get());
1430  return NcbiStreamCopy(os, cache_reader);
1431  }
1432  } catch (const exception& ex) {
1433  ERR_POST_X(5, "Couldn't read cached request : " << ex.what());
1434  }
1435  return false;
1436 }
1437 
1438 
1440 {
1441  string checksum, content;
1442  if ( !request.CalcChecksum(checksum, content) )
1443  return;
1444  try {
1445  CCacheHashedContent helper(cache);
1446  unique_ptr<IWriter> writer( helper.StoreHashedContent(checksum, content) );
1447  if (writer.get()) {
1448  // cout << "(Write) : " << checksum << " --- " << content << endl;
1449  CWStream cache_writer(writer.get());
1450  NcbiStreamCopy(cache_writer, is);
1451  }
1452  } catch (const exception& ex) {
1453  ERR_POST_X(6, "Couldn't cache request : " << ex.what());
1454  }
1455 }
1456 
1457 
1458 void CCgiApplication::SaveRequest(const string& rid, const CCgiRequest& request, ICache& cache)
1459 {
1460  if (rid.empty())
1461  return;
1462  try {
1463  unique_ptr<IWriter> writer( cache.GetWriteStream(rid, 0, "NS_JID") );
1464  if (writer.get()) {
1465  CWStream cache_stream(writer.get());
1466  request.Serialize(cache_stream);
1467  }
1468  } catch (const exception& ex) {
1469  ERR_POST_X(7, "Couldn't save request : " << ex.what());
1470  }
1471 }
1472 
1473 
1475 {
1476  if (rid.empty())
1477  return NULL;
1478  try {
1479  unique_ptr<IReader> reader(cache.GetReadStream(rid, 0, "NS_JID"));
1480  if (reader.get()) {
1481  CRStream cache_stream(reader.get());
1482  unique_ptr<CCgiRequest> request(new CCgiRequest);
1483  request->Deserialize(cache_stream, 0);
1484  return request.release();
1485  }
1486  } catch (const exception& ex) {
1487  ERR_POST_X(8, "Couldn't read saved request : " << ex.what());
1488  }
1489  return NULL;
1490 }
1491 
1492 
1494 {
1495  const CNcbiRegistry& reg = GetConfig();
1496 
1497  string cookie_name = GetConfig().Get("CGI-LB", "Name");
1498  if ( cookie_name.empty() )
1499  return;
1500 
1501  int life_span = reg.GetInt("CGI-LB", "LifeSpan", 0, 0,
1503 
1504  string domain = reg.GetString("CGI-LB", "Domain", ".ncbi.nlm.nih.gov");
1505 
1506  if ( domain.empty() ) {
1507  ERR_POST_X(9, "CGI-LB: 'Domain' not specified.");
1508  } else {
1509  if (domain[0] != '.') { // domain must start with dot
1510  domain.insert(0, ".");
1511  }
1512  }
1513 
1514  string path = reg.Get("CGI-LB", "Path");
1515 
1516  bool secure = reg.GetBool("CGI-LB", "Secure", false,
1518 
1519  string host;
1520 
1521  // Getting host configuration can take some time
1522  // for fast CGIs we try to avoid overhead and call it only once
1523  // m_HostIP variable keeps the cached value
1524 
1525  if ( m_HostIP ) { // repeated call
1526  host = m_HostIP;
1527  }
1528  else { // first time call
1529  host = reg.Get("CGI-LB", "Host");
1530  if ( host.empty() ) {
1531  if ( m_Caf.get() ) {
1532  char host_ip[64] = {0,};
1533  m_Caf->GetHostIP(host_ip, sizeof(host_ip));
1534  m_HostIP = m_Caf->Encode(host_ip, 0);
1535  host = m_HostIP;
1536  }
1537  else {
1538  ERR_POST_X(10, "CGI-LB: 'Host' not specified.");
1539  }
1540  }
1541  }
1542 
1543 
1544  CCgiCookie cookie(cookie_name, host, domain, path);
1545  if (life_span > 0) {
1546  CTime exp_time(CTime::eCurrent, CTime::eGmt);
1547  exp_time.AddSecond(life_span);
1548  cookie.SetExpTime(exp_time);
1549  }
1550  cookie.SetSecure(secure);
1551  cookies.Add(cookie);
1552 }
1553 
1554 
1556 {
1557  AddLBCookie(GetContext().GetResponse().Cookies());
1558 }
1559 
1560 
1562 {
1563  string x_moz = context.GetRequest().GetRandomProperty("X_MOZ");
1564  if ( NStr::EqualNocase(x_moz, "prefetch") ) {
1566  "Prefetch is not allowed for CGIs");
1567  ex.SetStatus(CCgiException::e403_Forbidden);
1568  ex.SetSeverity(eDiag_Info);
1570  }
1571 }
1572 
1573 
1575 {
1576  // Print application start message
1579  }
1580 }
1581 
1582 
1583 void CCgiApplication::AppStop(int exit_code)
1584 {
1585  GetDiagContext().SetExitCode(exit_code);
1586 }
1587 
1588 
1589 const char* kToolkitRcPath = "/etc/toolkitrc";
1590 const char* kWebDirToPort = "Web_dir_to_port";
1591 
1593 {
1594  string log_path = "/log/";
1595 
1596  string exe_path = GetProgramExecutablePath();
1597  CNcbiIfstream is(kToolkitRcPath, ios::binary);
1598  CNcbiRegistry reg(is);
1599  list<string> entries;
1601  size_t min_pos = exe_path.length();
1602  string web_dir;
1603  // Find the first dir name corresponding to one of the entries
1604  ITERATE(list<string>, it, entries) {
1605  if (!it->empty() && (*it)[0] != '/') {
1606  // not an absolute path
1607  string mask = "/" + *it;
1608  if (mask[mask.length() - 1] != '/') {
1609  mask += "/";
1610  }
1611  size_t pos = exe_path.find(mask);
1612  if (pos < min_pos) {
1613  min_pos = pos;
1614  web_dir = *it;
1615  }
1616  }
1617  else {
1618  // absolute path
1619  if (exe_path.substr(0, it->length()) == *it) {
1620  web_dir = *it;
1621  break;
1622  }
1623  }
1624  }
1625  if ( !web_dir.empty() ) {
1626  return log_path + reg.GetString(kWebDirToPort, web_dir, kEmptyStr);
1627  }
1628  // Could not find a valid web-dir entry, use port or 'srv'
1629  const char* port = ::getenv("SERVER_PORT");
1630  return port ? log_path + string(port) : log_path + "srv";
1631 }
1632 
1633 
1634 void CCgiApplication::SetHTTPStatus(unsigned int status, const string& reason)
1635 {
1636  if ( x_IsSetProcessor() ) {
1637  x_GetProcessor().SetHTTPStatus(status, reason);
1638  }
1639  else {
1641  }
1642 }
1643 
1644 
1646 {
1647  const CCgiRequest& req = context.GetRequest();
1648  const CCgiResponse& res = context.GetResponse();
1650  !res.IsHeaderWritten() ) {
1651  return false;
1652  }
1653  return true;
1654 }
1655 
1656 
1657 inline
1659 {
1660  // Prefer specific type over wildcard.
1661  bool this_wc = m_Type == "*";
1662  bool other_wc = entry.m_Type == "*";
1663  if (this_wc != other_wc) return !this_wc;
1664  // Prefer specific subtype over wildcard.
1665  this_wc = m_Subtype == "*";
1666  other_wc = entry.m_Subtype == "*";
1667  if (this_wc != other_wc) return !this_wc;
1668  // Prefer more specific media range params.
1669  if (m_MediaRangeParams.empty() != entry.m_MediaRangeParams.empty()) {
1670  return !m_MediaRangeParams.empty();
1671  }
1672  // Prefer higher quality factor.
1673  if (m_Quality != entry.m_Quality) return m_Quality > entry.m_Quality;
1674  // Otherwise sort by type/subtype values.
1675  if (m_Type != entry.m_Type) return m_Type < entry.m_Type;
1676  if (m_Subtype != entry.m_Subtype) return m_Subtype < entry.m_Subtype;
1677  // Otherwise (same type/subtype, quality factor and number of params)
1678  // consider entries equal.
1679  return false;
1680 }
1681 
1682 
1684 {
1686 }
1687 
1688 
1689 NCBI_PARAM_DECL(bool, CGI, EnableHelpRequest);
1690 NCBI_PARAM_DEF_EX(bool, CGI, EnableHelpRequest, true,
1691  eParam_NoThread, CGI_ENABLE_HELP_REQUEST);
1692 typedef NCBI_PARAM_TYPE(CGI, EnableHelpRequest) TEnableHelpRequest;
1693 
1694 
1696 {
1697  if (!TEnableHelpRequest::GetDefault()) return false;
1698  CCgiRequest& request = processor.GetContext().GetRequest();
1699  if (request.GetRequestMethod() != CCgiRequest::eMethod_GET) return false;
1700  bool found = false;
1701  string format = request.GetEntry("ncbi_help", &found);
1702  if ( !found ) return false;
1703  processor.ProcessHelpRequest(format);
1704  return true;
1705 }
1706 
1707 
1708 static const char* kStdFormats[] = { "html", "xml", "json" };
1709 static const char* kStdContentTypes[] = { "text/html", "text/xml", "application/json" };
1710 
1712  for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) {
1713  if (format == kStdFormats[i]) return kStdContentTypes[i];
1714  }
1715  return kEmptyStr;
1716 }
1717 
1718 
1720 {
1722 }
1723 
1724 
1725 NCBI_PARAM_DECL(string, CGI, EnableVersionRequest);
1726 NCBI_PARAM_DEF_EX(string, CGI, EnableVersionRequest, "t",
1727  eParam_NoThread, CGI_ENABLE_VERSION_REQUEST);
1728 typedef NCBI_PARAM_TYPE(CGI, EnableVersionRequest) TEnableVersionRequest;
1729 
1730 
1732 {
1733  CCgiRequest& request = processor.GetContext().GetRequest();
1734  if (request.GetRequestMethod() != CCgiRequest::eMethod_GET) return false;
1735 
1736  // If param value is a bool, enable the default ncbi_version CGI arg.
1737  // Otherwise try to use the value as the arg's name, then fallback to
1738  // ncbi_version.
1739  bool use_alt_name = false;
1740  string vparam = TEnableVersionRequest::GetDefault();
1741  if ( vparam.empty() ) return false;
1742  try {
1743  bool is_enabled = NStr::StringToBool(vparam);
1744  if (!is_enabled) return false;
1745  }
1746  catch (const CStringException&) {
1747  use_alt_name = true;
1748  }
1749 
1750  string ver_type;
1751  bool found = false;
1752  if ( use_alt_name ) {
1753  ver_type = request.GetEntry(vparam, &found);
1754  }
1755  if ( !found ) {
1756  ver_type = request.GetEntry("ncbi_version", &found);
1757  }
1758  if ( !found ) return false;
1759 
1760  EVersionType vt;
1761  if (ver_type.empty() || ver_type == "short") {
1762  vt = eVersion_Short;
1763  }
1764  else if (ver_type == "full") {
1765  vt = eVersion_Full;
1766  }
1767  else {
1769  "Unsupported ncbi_version argument value");
1770  }
1771  processor.ProcessVersionRequest(vt);
1772  return true;
1773 }
1774 
1775 
1777 {
1779 }
1780 
1782 {
1783  CCgiRequest& request = processor.GetContext().GetRequest();
1784  if (request.GetRequestMethod() != CCgiRequest::eMethod_GET) return false;
1785 
1786  bool found = false;
1787  string cmd_name = request.GetEntry("ncbi_admin_cmd", &found);
1788  if ( !found ) {
1789  // Check if PATH_INFO contains a command.
1790  string path_info = request.GetProperty(eCgi_PathInfo);
1791  NStr::TrimSuffixInPlace(path_info, "/");
1792  NStr::TrimPrefixInPlace(path_info, "/");
1793  if ( path_info.empty() ) return false;
1794  cmd_name = path_info;
1795  }
1797  if ( NStr::EqualNocase(cmd_name, "health") ) {
1798  cmd = eAdmin_Health;
1799  }
1800  else if ( NStr::EqualNocase(cmd_name, "deep-health") ) {
1802  }
1803 
1804  // If the overriden method failed or refused to process a command,
1805  // fallback to the default processing which returns true for all known commands.
1806  return processor.ProcessAdminRequest(cmd) || processor.ProcessAdminRequest_Base(cmd);
1807 }
1808 
1809 
1811 {
1813 }
1814 
1815 
1816 NCBI_PARAM_DECL(bool, CGI, ValidateCSRFToken);
1817 NCBI_PARAM_DEF_EX(bool, CGI, ValidateCSRFToken, false, eParam_NoThread,
1818  CGI_VALIDATE_CSRF_TOKEN);
1819 typedef NCBI_PARAM_TYPE(CGI, ValidateCSRFToken) TParamValidateCSRFToken;
1820 
1821 static const char* kCSRFTokenName = "NCBI_CSRF_TOKEN";
1822 
1824 {
1826 }
1827 
1828 
1830 {
1831  string path;
1832  const char* p = getenv("FCGI_STANDALONE_SERVER");
1833  if (p && *p) {
1834  path = p;
1835  } else {
1836  path = GetConfig().Get("FastCGI", "StandaloneServer");
1837  }
1838  return path;
1839 }
1840 
1841 
1843 {
1844  return GetConfig().GetBool("CGI", "StatLog", false, 0, CNcbiRegistry::eReturn);
1845 }
1846 
1847 
1848 unsigned int CCgiApplication::GetFastCGIIterations(unsigned int def_iter) const
1849 {
1850  int ret = def_iter;
1851  int x_iterations = GetConfig().GetInt("FastCGI", "Iterations", (int) def_iter, 0, CNcbiRegistry::eErrPost);
1852  if (x_iterations > 0) {
1853  ret = (unsigned int) x_iterations;
1854  } else {
1855  ERR_POST_X(6, "CCgiApplication::x_RunFastCGI: invalid "
1856  "[FastCGI].Iterations config.parameter value: "
1857  << x_iterations);
1858  _ASSERT(def_iter);
1859  ret = def_iter;
1860  }
1861 
1862  int iterations_rnd_inc = GetConfig().
1863  GetInt("FastCGI", "Iterations_Random_Increase", 0, 0, CNcbiRegistry::eErrPost);
1864  if (iterations_rnd_inc > 0) {
1865  ret += rand() % iterations_rnd_inc;
1866  }
1867 
1868  _TRACE("CCgiApplication::Run: FastCGI limited to "
1869  << ret << " iterations");
1870  return ret;
1871 }
1872 
1873 
1875 {
1876  return GetConfig().GetBool("FastCGI", "Complete_Request_On_Sigterm", false);
1877 }
1878 
1879 
1881 {
1882  const string& orig_filename = GetConfig().Get("FastCGI", "WatchFile.Name");
1883  if ( !orig_filename.empty() ) {
1884  string filename = CDirEntry::CreateAbsolutePath
1885  (orig_filename, CDirEntry::eRelativeToExe);
1886  if (filename != orig_filename) {
1887  _TRACE("Adjusted relative CGI watch file name " << orig_filename
1888  << " to " << filename);
1889  }
1890  int limit = GetConfig().GetInt("FastCGI", "WatchFile.Limit", -1, 0,
1892  if (limit <= 0) {
1893  limit = 1024; // set a reasonable default
1894  }
1895  return new CCgiWatchFile(filename, limit);
1896  }
1897  return nullptr;
1898 }
1899 
1900 
1901 unsigned int CCgiApplication::GetFastCGIWatchFileTimeout(bool have_watcher) const
1902 {
1903  int ret = GetConfig().GetInt("FastCGI", "WatchFile.Timeout", 0, 0, CNcbiRegistry::eErrPost);
1904  if (ret <= 0) {
1905  if ( have_watcher ) {
1906  ERR_POST_X(7, "CCgiApplication::x_RunFastCGI: non-positive "
1907  "[FastCGI].WatchFile.Timeout conf.param. value ignored: " << ret);
1908  }
1909  return 0;
1910  }
1911  return (unsigned int) ret;
1912 }
1913 
1914 
1916 {
1917  int ret = GetConfig().GetInt("FastCGI", "WatchFile.RestartDelay", 0, 0, CNcbiRegistry::eErrPost);
1918  if (ret <= 0) return 0;
1919  // CRandom is higher-quality, but would introduce an extra
1920  // dependency on libxutil; rand() should be good enough here.
1921  srand(CCurrentProcess::GetPid());
1922  double r = rand() / (RAND_MAX + 1.0);
1923  return 1 + (int)(ret * r);
1924 }
1925 
1926 
1928 {
1929  return GetConfig().GetBool("FastCGI", "ChannelErrors", false, 0, CNcbiRegistry::eReturn);
1930 }
1931 
1932 
1934 {
1935  return GetConfig().GetBool("FastCGI", "HonorExitRequest", false, 0, CNcbiRegistry::eErrPost);
1936 }
1937 
1939 {
1940  return GetConfig().GetBool("FastCGI", "Debug", false, 0, CNcbiRegistry::eErrPost);
1941 }
1942 
1943 
1945 {
1946  return GetConfig().GetBool("FastCGI", "StopIfFailed", false, 0, CNcbiRegistry::eErrPost);
1947 }
1948 
1949 
1951 {
1952  const int kDefaultMaxThreads = 8;
1953  int ret = GetConfig().GetInt("FastCGI", "MaxThreads", kDefaultMaxThreads, 0, CNcbiRegistry::eErrPost);
1954  if (ret <= 0) ret = kDefaultMaxThreads;
1955  return (unsigned int)ret;
1956 }
1957 
1958 
1960 {
1961  CTime mtime;
1962  if ( !CDirEntry(filename).GetTime(&mtime) ) {
1963  NCBI_THROW(CCgiErrnoException, eModTime,
1964  "Cannot get modification time of the CGI executable "
1965  + filename);
1966  }
1967  return mtime;
1968 }
1969 
1970 
1972 {
1974  GetConfig().GetString("FastCGI", "TotalMemoryLimit", "0", CNcbiRegistry::eReturn),
1976  if ( limit ) {
1977  CCurrentProcess::SMemoryUsage memory_usage;
1978  if ( !CCurrentProcess::GetMemoryUsage(memory_usage) ) {
1979  ERR_POST("Could not check self memory usage" );
1980  }
1981  else if (memory_usage.total > limit) {
1982  ERR_POST(Warning << "Memory usage (" << memory_usage.total <<
1983  ") is above the configured limit (" <<
1984  limit << ")");
1985  return true;
1986  }
1987  }
1988  return false;
1989 }
1990 
1991 
1992 DEFINE_STATIC_FAST_MUTEX(s_RestartReasonMutex);
1993 
1995 {
1996  static CSafeStatic<CTime> restart_time;
1997  static ERestartReason restart_reason = eSR_None;
1998 
1999  CFastMutexGuard guard(s_RestartReasonMutex);
2000  if (restart_reason != eSR_None) return restart_reason;
2001 
2002  // Check if this CGI executable has been changed
2005  if ( mtimeNew != mtime) {
2006  _TRACE("CCgiApplication::x_RunFastCGI: "
2007  "the program modification date has changed");
2008  restart_reason = eSR_Executable;
2009  } else if ( watcher && watcher->HasChanged()) {
2010  // Check if the file we're watching (if any) has changed
2011  // (based on contents, not timestamp!)
2012  ERR_POST_X(3, Warning <<
2013  "Scheduling restart of Fast-CGI, as its watch file has changed");
2014  restart_reason = eSR_WatchFile;
2015  }
2016 
2017  if (restart_reason != eSR_None) {
2018  if (restart_time->IsEmpty()) {
2019  restart_time->SetTimeZone(CTime::eGmt);
2020  restart_time->SetCurrent();
2021  restart_time->AddSecond(delay);
2022  _TRACE("Will restart Fast-CGI in " << delay << " seconds, at "
2023  << restart_time->GetLocalTime().AsString("h:m:s"));
2024  }
2025  if (CurrentTime(CTime::eGmt) >= *restart_time) {
2026  return restart_reason;
2027  }
2028  }
2029 
2030  return eSR_None;
2031 }
2032 
2033 
2035 {
2036  // Copy cmd-line arg values to CGI args
2037  args.Assign(CParent::GetArgs());
2038  // Add CGI parameters to the CGI version of args
2039  GetArgDescriptions()->ConvertKeys(&args, context.GetRequest().GetEntries(), true /*update=yes*/);
2040 }
2041 
2042 
2043 ///////////////////////////////////////////////////////
2044 // CCgiStatistics
2045 //
2046 
2047 
2049  : m_CgiApp(cgi_app), m_LogDelim(";")
2050 {
2051 }
2052 
2053 
2055 {
2056 }
2057 
2058 
2060  int result,
2061  const std::exception* ex)
2062 {
2064  m_Result = result;
2065  m_ErrMsg = ex ? ex->what() : kEmptyStr;
2066 }
2067 
2068 
2070 {
2071  const CNcbiRegistry& reg = m_CgiApp.GetConfig();
2072  CTime end_time(CTime::eCurrent);
2073 
2074  // Check if it is assigned NOT to log the requests took less than
2075  // cut off time threshold
2076  TSeconds time_cutoff = reg.GetInt("CGI", "TimeStatCutOff", 0, 0,
2078  if (time_cutoff > 0) {
2079  TSeconds diff = end_time.DiffSecond(m_StartTime);
2080  if (diff < time_cutoff) {
2081  return kEmptyStr; // do nothing if it is a light weight request
2082  }
2083  }
2084 
2085  string msg, tmp_str;
2086 
2087  tmp_str = Compose_ProgramName();
2088  if ( !tmp_str.empty() ) {
2089  msg.append(tmp_str);
2090  msg.append(m_LogDelim);
2091  }
2092 
2093  tmp_str = Compose_Result();
2094  if ( !tmp_str.empty() ) {
2095  msg.append(tmp_str);
2096  msg.append(m_LogDelim);
2097  }
2098 
2099  bool is_timing =
2100  reg.GetBool("CGI", "TimeStamp", false, 0, CNcbiRegistry::eErrPost);
2101  if ( is_timing ) {
2102  tmp_str = Compose_Timing(end_time);
2103  if ( !tmp_str.empty() ) {
2104  msg.append(tmp_str);
2105  msg.append(m_LogDelim);
2106  }
2107  }
2108 
2109  tmp_str = Compose_Entries();
2110  if ( !tmp_str.empty() ) {
2111  msg.append(tmp_str);
2112  }
2113 
2114  tmp_str = Compose_ErrMessage();
2115  if ( !tmp_str.empty() ) {
2116  msg.append(tmp_str);
2117  msg.append(m_LogDelim);
2118  }
2119 
2120  return msg;
2121 }
2122 
2123 
2124 void CCgiStatistics::Submit(const string& message)
2125 {
2126  LOG_POST_X(11, message);
2127 }
2128 
2129 
2131 {
2133 }
2134 
2135 
2136 string CCgiStatistics::Compose_Timing(const CTime& end_time)
2137 {
2138  CTimeSpan elapsed = end_time.DiffTimeSpan(m_StartTime);
2139  return m_StartTime.AsString() + m_LogDelim + elapsed.AsString();
2140 }
2141 
2142 
2144 {
2145  if (!m_CgiApp.x_GetProcessor().IsSetContext()) return kEmptyStr;
2146  const CCgiRequest& cgi_req = m_CgiApp.x_GetProcessor().GetContext().GetRequest();
2147 
2148  // LogArgs - list of CGI arguments to log.
2149  // Can come as list of arguments (LogArgs = param1;param2;param3),
2150  // or be supplemented with aliases (LogArgs = param1=1;param2=2;param3).
2151  // When alias is provided we use it for logging purposes (this feature
2152  // can be used to save logging space or reduce the net traffic).
2153  const CNcbiRegistry& reg = m_CgiApp.GetConfig();
2154  string log_args = reg.Get("CGI", "LogArgs");
2155  if ( log_args.empty() )
2156  return kEmptyStr;
2157 
2158  list<string> vars;
2159  NStr::Split(log_args, ",; \t", vars,
2161 
2162  string msg;
2163  ITERATE (list<string>, i, vars) {
2164  bool is_entry_found;
2165  const string& arg = *i;
2166 
2167  size_t pos = arg.find_last_of('=');
2168  if (pos == 0) {
2169  return "<misconf>" + m_LogDelim;
2170  } else if (pos != string::npos) { // alias assigned
2171  string key = arg.substr(0, pos);
2172  const CCgiEntry& entry = cgi_req.GetEntry(key, &is_entry_found);
2173  if ( is_entry_found ) {
2174  string alias = arg.substr(pos+1, arg.length());
2175  msg.append(alias);
2176  msg.append("='");
2177  msg.append(entry.GetValue());
2178  msg.append("'");
2179  msg.append(m_LogDelim);
2180  }
2181  } else {
2182  const CCgiEntry& entry = cgi_req.GetEntry(arg, &is_entry_found);
2183  if ( is_entry_found ) {
2184  msg.append(arg);
2185  msg.append("='");
2186  msg.append(entry.GetValue());
2187  msg.append("'");
2188  msg.append(m_LogDelim);
2189  }
2190  }
2191  }
2192 
2193  return msg;
2194 }
2195 
2196 
2198 {
2199  return NStr::IntToString(m_Result);
2200 }
2201 
2202 
2204 {
2205  return m_ErrMsg;
2206 }
2207 
2208 
2209 /////////////////////////////////////////////////////////////////////////////
2210 // CCgiWatchFile
2211 
2213 {
2214  CNcbiIfstream in(m_Filename.c_str());
2215  if (in) {
2216  in.read(buf, m_Limit);
2217  return (int) in.gcount();
2218  } else {
2219  return -1;
2220  }
2221 }
2222 
2223 CCgiWatchFile::CCgiWatchFile(const string& filename, int limit)
2224  : m_Filename(filename), m_Limit(limit), m_Buf(new char[limit])
2225 {
2226  m_Count = x_Read(m_Buf.get());
2227  if (m_Count < 0) {
2228  ERR_POST_X(2, "Failed to open CGI watch file " << filename);
2229  }
2230 }
2231 
2233 {
2234  TBuf buf(new char[m_Limit]);
2235  if (x_Read(buf.get()) != m_Count) {
2236  return true;
2237  } else if (m_Count == -1) { // couldn't be opened
2238  return false;
2239  } else {
2240  return memcmp(buf.get(), m_Buf.get(), m_Count) != 0;
2241  }
2242  // no need to update m_Count or m_Buf, since the CGI will restart
2243  // if there are any discrepancies.
2244 }
2245 
2246 
2247 ///////////////////////////////////////////////////////
2248 // CCgiRequestProcessor
2249 //
2250 
2251 
2253  : m_App(app)
2254 {
2255 }
2256 
2257 
2259 {
2260 }
2261 
2262 
2264 {
2265  _ASSERT(m_Context.get() == &context);
2266  return m_App.ProcessRequest(context);
2267 }
2268 
2269 
2271 {
2272  string base_name = m_App.GetProgramExecutablePath();
2273  string fname;
2274  string content_type;
2275  // If 'format' is set, try to find <basename>.help.<format> or help.<format> file.
2276  if ( !format.empty() ) {
2277  string fname_fmt = base_name + ".help." + format;
2278  if ( CFile(fname_fmt).Exists() ) {
2279  fname = fname_fmt;
2280  content_type = FindContentType(format);
2281  }
2282  else {
2283  fname_fmt = "help." + format;
2284  if ( CFile(fname_fmt).Exists() ) {
2285  fname = fname_fmt;
2286  content_type = FindContentType(format);
2287  }
2288  }
2289  }
2290 
2291  // If 'format' is not set or there's no file of the specified format, check
2292  // 'Accept:' header.
2293  if ( fname.empty() ) {
2297  string fname_accept = base_name + ".help." + it->m_Subtype + it->m_MediaRangeParams;
2298  if ( CFile(fname_accept).Exists() ) {
2299  fname = fname_accept;
2300  content_type = it->m_Type + "/" + it->m_Subtype;
2301  break;
2302  }
2303  }
2304  if ( fname.empty() ) {
2306  string fname_accept = "help." + it->m_Subtype + it->m_MediaRangeParams;
2307  if ( CFile(fname_accept).Exists() ) {
2308  fname = fname_accept;
2309  content_type = it->m_Type + "/" + it->m_Subtype;
2310  break;
2311  }
2312  }
2313  }
2314  }
2315 
2316  // Finally, check standard formats: html/xml/json
2317  if ( fname.empty() ) {
2318  for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) {
2319  string fname_std = base_name + ".help." + kStdFormats[i];
2320  if ( CFile(fname_std).Exists() ) {
2321  fname = fname_std;
2322  content_type = kStdContentTypes[i];
2323  break;
2324  }
2325  }
2326  }
2327  if ( fname.empty() ) {
2328  for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) {
2329  string fname_std = string("help.") + kStdFormats[i];
2330  if ( CFile(fname_std).Exists() ) {
2331  fname = fname_std;
2332  content_type = kStdContentTypes[i];
2333  break;
2334  }
2335  }
2336  }
2337 
2338  CCgiResponse& response = GetContext().GetResponse();
2339  if ( !fname.empty() ) {
2340  CNcbiIfstream in(fname.c_str());
2341 
2342  // Check if the file starts with "Content-type:" header followed by double-eol.
2343  bool ct_found = false;
2344  string ct;
2345  getline(in, ct);
2346  if ( NStr::StartsWith(ct, "content-type:", NStr::eNocase) ) {
2347  string eol;
2348  getline(in, eol);
2349  if ( eol.empty() ) {
2350  ct_found = true;
2351  content_type = NStr::TruncateSpaces(ct.substr(13));
2352  }
2353  }
2354  if ( !ct_found ) {
2355  in.seekg(0);
2356  }
2357 
2358  if ( !content_type.empty()) {
2359  response.SetContentType(content_type);
2360  }
2361  response.WriteHeader();
2362  NcbiStreamCopy(*response.GetOutput(), in);
2363  }
2364  else {
2365  // Could not find help file, use arg descriptions instead.
2366  const CArgDescriptions* args = m_App.GetArgDescriptions();
2367  if ( args ) {
2368  response.SetContentType("text/xml");
2369  response.WriteHeader();
2370  args->PrintUsageXml(*response.GetOutput());
2371  }
2372  else {
2374  "Can not find help for CGI application");
2375  }
2376  }
2377 }
2378 
2379 
2381 {
2382  string format = "plain";
2383  string content_type = "text/plain";
2387  if (it->m_Subtype == "xml" || it->m_Subtype == "json" ||
2388  (it->m_Type == "text" && it->m_Subtype == "plain")) {
2389  format = it->m_Subtype;
2390  content_type = it->m_Type + "/" + it->m_Subtype;
2391  break;
2392  }
2393  }
2394 
2395  CCgiResponse& response = GetContext().GetResponse();
2396  response.SetContentType(content_type);
2397  response.WriteHeader();
2398  CNcbiOstream& out = *response.GetOutput();
2399  if (format == "plain") {
2400  switch (ver_type) {
2402  out << m_App.GetVersion().Print();
2403  break;
2406  break;
2407  }
2408  }
2409  else if (format == "xml") {
2410  switch (ver_type) {
2413  break;
2416  break;
2417  }
2418  }
2419  else if (format == "json") {
2420  switch (ver_type) {
2423  break;
2426  break;
2427  }
2428  }
2429  else {
2431  "Unsupported version format");
2432  }
2433 }
2434 
2435 
2437 {
2438  return ProcessAdminRequest_Base(cmd);
2439 }
2440 
2441 
2443 {
2444  if (cmd == CCgiApplication::eAdmin_Unknown) return false;
2445 
2446  // By default report status 200 and write headers for any command.
2447  CCgiResponse& response = GetContext().GetResponse();
2448  response.SetContentType("text/plain");
2451  response.WriteHeader();
2452  return true;
2453 }
2454 
2455 
2457 {
2458  if (!TParamValidateCSRFToken::GetDefault()) return true;
2459  const CCgiRequest& req = GetContext().GetRequest();
2460  const string& token = req.GetRandomProperty(kCSRFTokenName, false);
2461  return !token.empty() && token == req.GetTrackingCookie();
2462 }
2463 
2464 
2466 {
2467  string ref = m_Context->GetSelfURL();
2468  if ( !ref.empty() ) {
2469  string args = m_Context->GetRequest().GetProperty(eCgi_QueryString);
2470  if ( !args.empty() ) ref += "?" + args;
2471  }
2472  return ref;
2473 }
2474 
2475 
2476 NCBI_PARAM_DECL(string, CGI, Exception_Message);
2477 NCBI_PARAM_DEF_EX(string, CGI, Exception_Message, "", eParam_NoThread,
2478  CGI_EXCEPTION_MESSAGE);
2479 typedef NCBI_PARAM_TYPE(CGI, Exception_Message) TExceptionMessage;
2480 
2481 
2483 {
2484  // Discriminate between different types of error
2485  string status_str = "500 Server Error";
2486  string message = "";
2487 
2488  // Save current HTTP status. Later it may be changed to 299 or 499
2489  // depending on this value.
2490  SetErrorStatus(CDiagContext::GetRequestContext().GetRequestStatus() >= 400);
2491  SetHTTPStatus(500);
2492 
2493  CException* ce = dynamic_cast<CException*> (&e);
2494  if ( ce ) {
2495  message = ce->GetMsg();
2496  CCgiException* cgi_e = dynamic_cast<CCgiException*>(&e);
2497  if ( cgi_e ) {
2498  if ( cgi_e->GetStatusCode() != CCgiException::eStatusNotSet ) {
2499  SetHTTPStatus(cgi_e->GetStatusCode());
2500  status_str = NStr::IntToString(cgi_e->GetStatusCode()) +
2501  " " + cgi_e->GetStatusMessage();
2502  }
2503  else {
2504  // Convert CgiRequestException and CCgiArgsException
2505  // to error 400
2506  if (dynamic_cast<CCgiRequestException*> (&e) ||
2507  dynamic_cast<CUrlException*> (&e)) {
2508  SetHTTPStatus(400);
2509  status_str = "400 Malformed HTTP Request";
2510  }
2511  }
2512  }
2513  }
2514  else {
2515  message = e.what();
2516  }
2517 
2518  // Don't try to write to a broken output
2519  if (!os.good() || GetOutputBroken()) {
2520  return -1;
2521  }
2522 
2523  string expt_msg = TExceptionMessage::GetDefault();
2524  if ( !expt_msg.empty() ) {
2525  message = expt_msg;
2526  }
2527 
2528  try {
2529  // HTTP header
2530  os << "Status: " << status_str << HTTP_EOL;
2531  os << "Content-Type: text/plain" HTTP_EOL HTTP_EOL;
2532 
2533  // Message
2534  os << "ERROR: " << status_str << " " HTTP_EOL HTTP_EOL;
2535  os << NStr::HtmlEncode(message) << HTTP_EOL HTTP_EOL;
2536 
2537  if ( dynamic_cast<CArgException*> (&e) ) {
2538  string ustr;
2539  const CArgDescriptions* descr = m_App.GetArgDescriptions();
2540  if (descr) {
2541  os << descr->PrintUsage(ustr) << HTTP_EOL HTTP_EOL;
2542  }
2543  }
2544 
2545  // Check for problems in sending the response
2546  if ( !os.good() ) {
2547  ERR_POST_X(4, "CCgiApplication::OnException() failed to send error page"
2548  " back to the client");
2549  return -1;
2550  }
2551  }
2552  catch (const exception& ex) {
2553  NCBI_REPORT_EXCEPTION_X(14, "(CGI) CCgiApplication::Run", ex);
2554  }
2555  return 0;
2556 }
2557 
2558 
2560 {
2561  return;
2562 }
2563 
2564 
2565 void CCgiRequestProcessor::SetHTTPStatus(unsigned int status, const string& reason)
2566 {
2567  if ( m_Context.get() ) {
2568  m_Context->GetResponse().SetStatus(status, reason);
2569  }
2570  else {
2572  }
2573 }
2574 
2575 
2576 void CCgiRequestProcessor::SetRequestId(const string& rid, bool is_done)
2577 {
2578  m_RID = rid;
2579  m_IsResultReady = is_done;
2580 }
2581 
2582 
2584 {
2585  string accept = GetContext().GetRequest().GetProperty(eCgi_HttpAccept);
2586  if (accept.empty()) return;
2587  list<string> types;
2589  ITERATE(list<string>, type_it, types) {
2590  list<string> parts;
2592  if ( parts.empty() ) continue;
2593  entries.push_back(TAcceptEntry());
2594  TAcceptEntry& entry = entries.back();
2595  NStr::SplitInTwo(NStr::TruncateSpaces(parts.front()), "/", entry.m_Type, entry.m_Subtype);
2598  list<string>::const_iterator ext_it = parts.begin();
2599  ++ext_it; // skip type/subtype
2600  bool aparams = false;
2601  while (ext_it != parts.end()) {
2602  string name, value;
2603  NStr::SplitInTwo(NStr::TruncateSpaces(*ext_it), "=", name, value);
2606  if (name == "q") {
2607  entry.m_Quality = NStr::StringToNumeric<float>(value, NStr::fConvErr_NoThrow);
2608  if (entry.m_Quality == 0 && errno != 0) {
2609  entry.m_Quality = 1;
2610  }
2611  aparams = true;
2612  ++ext_it;
2613  continue;
2614  }
2615  if (aparams) {
2616  entry.m_AcceptParams[name] = value;
2617  }
2618  else {
2619  entry.m_MediaRangeParams += ";" + name + "=" + value;
2620  }
2621  ++ext_it;
2622  }
2623  }
2624  entries.sort();
2625 }
2626 
2627 
2629 {
2630  m_CgiArgs.reset(new CArgs());
2632 }
2633 
2634 /////////////////////////////////////////////////////////////////////////////
2635 // Tracking Environment
2636 
2638 NCBI_PARAM_DEF(string, CGI, TrackingCookieName, "ncbi_sid");
2639 NCBI_PARAM_DEF(string, CGI, TrackingTagName, "NCBI-SID");
2642 
2643 
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:1590
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:1589
typedef NCBI_PARAM_TYPE(CGI, Print_Http_Referer) TPrintRefererParam
DEFINE_STATIC_FAST_MUTEX(s_RestartReasonMutex)
static const char * kStdFormats[]
Definition: cgiapp.cpp:1708
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:1711
static void s_CleanupProcessor(CCgiRequestProcessor *processor, void *)
Definition: cgiapp.cpp:845
static const char * kStdContentTypes[]
Definition: cgiapp.cpp:1709
NCBI_PARAM_DECL(bool, CGI, Print_Http_Referer)
void SigTermHandler(int)
Definition: cgiapp.cpp:463
static const char * kCSRFTokenName
Definition: cgiapp.cpp:1821
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:579
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:1604
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:4506
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 string GetAppName(EAppNameType name_type=eBaseName, int argc=0, const char *const *argv=NULL)
Definition: ncbiapp.cpp:1377
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:1184
virtual void SetupArgDescriptions(CArgDescriptions *arg_desc)
Setup the command line argument descriptions.
Definition: ncbiapp.cpp:1195
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:1318
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:1306
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:1189
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:2628
void SetHTTPStatus(unsigned int status, const string &reason=kEmptyStr)
Definition: cgiapp.cpp:2565
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:2143
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:1901
bool GetRequestStartPrinted(void) const
Definition: cgiapp.hpp:657
virtual string Compose_ErrMessage(void)
Definition: cgiapp.cpp:2203
const CCgiResponse & GetResponse(void) const
Definition: cgictx.hpp:388
virtual ~CCgiStatistics()
Definition: cgiapp.cpp:2054
void SetOutputBroken(bool val)
Definition: cgiapp.hpp:655
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:658
bool GetFastCGIComplete_Request_On_Sigterm(void) const
Definition: cgiapp.cpp:1874
TrackingCookieName
Definition: cgiapp.hpp:687
bool CheckMemoryLimit(void)
Definition: cgiapp.cpp:1971
virtual string Compose_Result(void)
Definition: cgiapp.cpp:2197
CCgiStatistics(CCgiApplication &cgi_app)
Definition: cgiapp.cpp:2048
virtual bool x_RunFastCGI(int *result, unsigned int def_iter=10)
Definition: cgi_run.cpp:44
void SetErrorStatus(bool val)
Definition: cgiapp.hpp:661
const CCgiRequest & GetRequest(void) const
Definition: cgictx.hpp:374
unsigned int GetFastCGIIterations(unsigned int def_iter) const
Definition: cgiapp.cpp:1848
string m_Filename
Definition: cgiapp.hpp:533
shared_ptr< CCgiContext > m_Context
Definition: cgiapp.hpp:617
string m_LogDelim
Definition: cgiapp.hpp:510
CCgiStreamWrapperWriter * m_Writer
Definition: cgiapp.hpp:572
bool GetOutputBroken(void) const
Definition: cgiapp.hpp:654
unsigned int GetFastCGIMTMaxThreads(void) const
Definition: cgiapp.cpp:1950
void AbortChunkedTransfer(void)
Definition: cgiapp.cpp:446
string
Definition: cgiapp.hpp:687
friend class CCgiRequestProcessor
Definition: cgiapp.hpp:65
CDiagFactory * FindDiagFactory(const string &key)
Definition: cgiapp.cpp:1216
CAtomicCounter m_Iteration
Definition: cgiapp.hpp:434
virtual void ProcessVersionRequest(CCgiApplication::EVersionType ver_type)
Definition: cgiapp.cpp:2380
virtual void ConfigureDiagFormat(CCgiContext &context)
Definition: cgiapp.cpp:1277
int GetFastCGIWatchFileRestartDelay(void) const
Definition: cgiapp.cpp:1915
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:511
virtual void ConfigureDiagnostics(CCgiContext &context)
Definition: cgiapp.cpp:1225
char * m_HostIP
Definition: cgiapp.hpp:456
virtual int ProcessRequest(CCgiContext &context)
Process request provided by the context. By default calls application's ProcessRequest.
Definition: cgiapp.cpp:2263
int x_Read(char *buf)
Definition: cgiapp.cpp:2212
static CTime GetFileModificationTime(const string &filename)
Definition: cgiapp.cpp:1959
string m_MediaRangeParams
Media range parameters.
Definition: cgiapp.hpp:348
int m_RequestFlags
Bit flags for CCgiRequest.
Definition: cgiapp.hpp:375
CCgiRequestProcessor & x_GetProcessor(void) const
Definition: cgiapp.cpp:828
bool ProcessAdminRequest_Base(CCgiApplication::EAdminCommand cmd)
Definition: cgiapp.cpp:2442
virtual void Exit(void)
This method is called on the CGI application exit.
Definition: cgiapp.cpp:879
bool HasChanged(void)
Definition: cgiapp.cpp:2232
virtual ~CCgiRequestProcessor(void)
Definition: cgiapp.cpp:2258
virtual void ConfigureDiagDestination(CCgiContext &context)
Definition: cgiapp.cpp:1234
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:1369
virtual EPreparseArgs PreparseArgs(int argc, const char *const *argv)
Check the command line arguments before parsing them.
Definition: cgiapp.cpp:1388
CArgs & GetArgs(void)
Definition: cgiapp.hpp:640
virtual bool ProcessAdminRequest(CCgiApplication::EAdminCommand cmd)
Definition: cgiapp.cpp:2436
bool GetFastCGIStatLog(void) const
Definition: cgiapp.cpp:1842
void RegisterDiagFactory(const string &key, CDiagFactory *fact)
Definition: cgiapp.cpp:1209
CCgiApplication::SAcceptEntry TAcceptEntry
Definition: cgiapp.hpp:608
void SetInputStream(CNcbiIstream *in)
Definition: cgiapp.hpp:646
unique_ptr< CNcbiResource > m_Resource
Definition: cgiapp.hpp:450
CCgiWatchFile(const string &filename, int limit=1024)
Definition: cgiapp.cpp:2223
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:1555
bool GetFastCGIStopIfFailed(void) const
Definition: cgiapp.cpp:1944
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:1695
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:1202
CNcbiOstream & GetOutputStream(void)
Definition: cgiapp.hpp:649
virtual void OnEvent(CCgiApplication::EEvent event, int status)
Definition: cgiapp.cpp:2559
virtual void ProcessHelpRequest(const string &format)
Definition: cgiapp.cpp:2270
float m_Quality
Quality factor or "1" if not set (or not numeric).
Definition: cgiapp.hpp:347
virtual void Reset(const CTime &start_time, int result, const std::exception *ex=0)
Definition: cgiapp.cpp:2059
bool GetErrorStatus(void) const
Definition: cgiapp.hpp:660
CCgiApplication & m_App
Definition: cgiapp.hpp:616
EStreamMode GetWriterMode(void)
Definition: cgiapp.cpp:421
virtual void ConfigureDiagThreshold(CCgiContext &context)
Definition: cgiapp.cpp:1251
DisableTrackingCookie
Definition: cgiapp.hpp:685
string GetFastCGIStandaloneServer(void) const
Definition: cgiapp.cpp:1829
static ERestartReason ShouldRestart(CTime &mtime, CCgiWatchFile *watcher, int delay)
Definition: cgiapp.cpp:1994
virtual bool ProcessAdminRequest(EAdminCommand cmd)
Process admin command passed through ncbi_admin_cmd argument.
Definition: cgiapp.cpp:1810
bool operator<(const SAcceptEntry &entry) const
Definition: cgiapp.cpp:1658
CCgiContext & x_GetContext(void) const
Definition: cgiapp.cpp:802
void SetRequestId(const string &rid, bool is_done)
Definition: cgiapp.cpp:2576
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:1634
bool x_ProcessAdminRequest(CCgiRequestProcessor &processor)
Definition: cgiapp.cpp:1781
virtual void AppStart(void)
Prepare properties and print the application start message.
Definition: cgiapp.cpp:1574
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:1645
void ParseAcceptHeader(TAcceptEntries &entries) const
Definition: cgiapp.cpp:2583
virtual ICache * GetCacheStorage(void) const
Definition: cgiapp.cpp:1381
unique_ptr< CCookieAffinity > m_Caf
Definition: cgiapp.hpp:455
virtual string Compose(void)
Definition: cgiapp.cpp:2069
CCgiApplication::TAcceptEntries TAcceptEntries
Definition: cgiapp.hpp:607
virtual int OnException(std::exception &e, CNcbiOstream &os)
Definition: cgiapp.cpp:2482
virtual string Compose_ProgramName(void)
Definition: cgiapp.cpp:2130
void SetWriterMode(EStreamMode mode)
Definition: cgiapp.cpp:427
bool IsSetOutputStream(void) const
Definition: cgiapp.hpp:652
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:689
ELogOpt GetLogOpt(void) const
Definition: cgiapp.cpp:1341
virtual bool ValidateSynchronizationToken(void)
Definition: cgiapp.cpp:2456
string GetRID(void) const
Definition: cgiapp.hpp:663
TDiagFactoryMap m_DiagFactories
Definition: cgiapp.hpp:453
TrackingCookiePath
Definition: cgiapp.hpp:693
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:1823
virtual bool IsCachingNeeded(const CCgiRequest &request) const
Definition: cgiapp.cpp:1375
friend class CCgiStatistics
Definition: cgiapp.hpp:64
string m_DiagPrefixEnv
Definition: cgiapp.hpp:459
virtual void Submit(const string &message)
Definition: cgiapp.cpp:2124
virtual CCgiStatistics * CreateStat()
Class factory for statistics class.
Definition: cgiapp.cpp:1362
void SetRequestId(const string &rid, bool is_done)
Definition: cgiapp.cpp:1412
virtual void ProcessHelpRequest(const string &format)
Process help request: set content type, print usage informations etc.
Definition: cgiapp.cpp:1719
virtual CNcbiResource * LoadResource(void)
Definition: cgiapp.cpp:887
virtual string Compose_Timing(const CTime &end_time)
Definition: cgiapp.cpp:2136
void SaveResultToCache(const CCgiRequest &request, CNcbiIstream &is, ICache &cache)
Definition: cgiapp.cpp:1439
bool x_ProcessVersionRequest(CCgiRequestProcessor &processor)
Definition: cgiapp.cpp:1731
bool IsSetInputStream(void) const
Definition: cgiapp.hpp:647
void InitArgs(CArgs &args, CCgiContext &context) const
Definition: cgiapp.cpp:2034
void SetContext(shared_ptr< CCgiContext > context)
Definition: cgiapp.hpp:637
CCgiApplication & m_CgiApp
Definition: cgiapp.hpp:509
void SaveRequest(const string &rid, const CCgiRequest &request, ICache &cache)
Definition: cgiapp.cpp:1458
CCgiRequestProcessor * x_GetProcessorOrNull(void) const
Definition: cgiapp.cpp:839
string m_ErrMsg
Definition: cgiapp.hpp:513
void SetOutputStream(CNcbiOstream *out)
Definition: cgiapp.hpp:651
bool IsSetContext(void) const
Definition: cgiapp.hpp:638
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:1776
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:635
CCgiRequestProcessor & x_CreateProcessor(void)
Definition: cgiapp.cpp:851
CCgiRequest * GetSavedRequest(const string &rid, ICache &cache)
Definition: cgiapp.cpp:1474
string GetSelfReferer(void) const
Get self-URL to be used as referer.
Definition: cgiapp.cpp:2465
CCgiRequestProcessor(CCgiApplication &app)
Definition: cgiapp.cpp:2252
list< SAcceptEntry > TAcceptEntries
Definition: cgiapp.hpp:354
CRef< CTls< CCgiRequestProcessor > > m_Processor
Definition: cgiapp.hpp:433
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:696
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:1683
void SetCafService(CCookieAffinity *caf)
Attach cookie affinity service interface.
Definition: cgiapp.cpp:987
bool GetFastCGIDebug(void) const
Definition: cgiapp.cpp:1938
CCgiWatchFile * CreateFastCGIWatchFile(void) const
Definition: cgiapp.cpp:1880
unique_ptr< CArgs > m_CgiArgs
Definition: cgiapp.hpp:619
CCgiStreamWrapper(CNcbiOstream &out)
Definition: cgiapp.cpp:414
~CCgiApplication(void)
Definition: cgiapp.cpp:1049
Client_Connection_Interruption_Severity
Definition: cgiapp.hpp:700
virtual string GetDefaultLogPath(void) const
Get default path for the log files.
Definition: cgiapp.cpp:1592
CNcbiIstream & GetInputStream(void)
Definition: cgiapp.hpp:644
bool GetResultReady(void) const
Definition: cgiapp.hpp:666
bool GetResultFromCache(const CCgiRequest &request, CNcbiOstream &os, ICache &cache)
Definition: cgiapp.cpp:1418
virtual void AppStop(int exit_code)
Prepare properties for application stop message.
Definition: cgiapp.cpp:1583
void LogRequest(void) const
Definition: cgiapp.cpp:715
bool GetFastCGIHonorExitRequest(void) const
Definition: cgiapp.cpp:1933
TParams m_AcceptParams
Accept parameters.
Definition: cgiapp.hpp:349
void VerifyCgiContext(CCgiContext &context)
Check CGI context for possible problems, throw exception with HTTP status set if something is wrong.
Definition: cgiapp.cpp:1561
void FinishChunkedTransfer(const TTrailer *trailer)
Definition: cgiapp.cpp:440
bool GetFastCGIChannelErrors(void) const
Definition: cgiapp.cpp:1927
void AddLBCookie(CCgiCookies &cookies)
Definition: cgiapp.cpp:1493
TrackingCookieDomain
Definition: cgiapp.hpp:691
void ProcessHttpReferer(void)
Set CONN_HTTP_REFERER, print self-URL and referer to log.
Definition: cgiapp.cpp:704
CGI
Definition: cgiapp.hpp:685
@ eAdmin_Health
Report health for this CGI only.
Definition: cgiapp.hpp:328
@ eAdmin_Unknown
Unrecognized command.
Definition: cgiapp.hpp:330
@ eAdmin_HealthDeep
Report health for this CGI and any services used by it.
Definition: cgiapp.hpp:329
@ 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
const string & GetValue(void) const
All "const string& GetXXX(...)" methods beneath return reference to "NcbiEmptyString" if the requeste...
Definition: ncbicgi.hpp:1034
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_HttpUserAgent
Definition: ncbicgi.hpp:411
@ eCgi_HttpReferer
Definition: ncbicgi.hpp:410
@ eCgi_HttpAccept
Definition: ncbicgi.hpp:407
@ eCgi_PathInfo
Definition: ncbicgi.hpp:396
@ 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:6109
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:6070
#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 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.
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:6129
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)
string GetHitID(void) const
Get explicit hit id or the default one (from HTTP_NCBI_PHID etc).
#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:6288
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:6226
EDiagSev
Severity level for the posted diagnostics.
Definition: ncbidiag.hpp:650
TDiagPostFlags SetDiagPostAllFlags(TDiagPostFlags flags)
Set global post flags to "flags".
Definition: ncbidiag.cpp:6065
void SetDiagTraceFlag(EDiagPostFlag flag)
Definition: ncbidiag.cpp:6086
@ 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:4038
@ 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:2821
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:3461
static int strcmp(const char *s1, const char *s2)
String compare.
Definition: ncbistr.hpp:5208
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:4122
static Uint8 StringToUInt8_DataSize(const CTempString str, TStringToNumFlags flags=0)
Convert string that can contain "software" qualifiers to Uint8.
Definition: ncbistr.cpp:1539
static void TruncateSpacesInPlace(string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string (in-place)
Definition: ncbistr.cpp:3201
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5084
bool AStrEquiv(const Arg1 &x, const Arg2 &y, Pred pr)
Check equivalence of arguments using predicate.
Definition: ncbistr.hpp:5037
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:5412
static void TrimSuffixInPlace(string &str, const CTempString suffix, ECase use_case=eCase)
Trim suffix from a string (in-place)
Definition: ncbistr.cpp:3278
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:3554
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:5353
static void TrimPrefixInPlace(string &str, const CTempString prefix, ECase use_case=eCase)
Trim prefix from a string (in-place)
Definition: ncbistr.cpp:3242
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:3405
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3186
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:2501
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2498
@ 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:1879
string AsString(const CTimeFormat &format=kEmptyStr, TSeconds out_tz=eCurrentTimeZone) const
Transform time to string.
Definition: ncbitime.cpp:1511
CTime CurrentTime(CTime::ETimeZone tz=CTime::eLocal, CTime::ETimeZonePrecision tzp=CTime::eTZPrecisionDefault)
Definition: ncbitime.hpp:2185
CTimeSpan DiffTimeSpan(const CTime &t) const
Difference in nanoseconds from specified time.
Definition: ncbitime.cpp:2304
TSeconds DiffSecond(const CTime &t) const
Difference in seconds from specified time.
Definition: ncbitime.cpp:2281
string AsString(const CTimeFormat &fmt=kEmptyStr) const
Transform time span to string.
Definition: ncbitime.cpp:2680
@ 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:718
string PrintXml(const string &appname, TPrintFlags flags=fPrintAll) const
Print version data, XML.
Definition: version.cpp:764
string PrintJson(const string &appname, TPrintFlags flags=fPrintAll) const
Print version data, JSON.
Definition: version.cpp:814
@ 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_)
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
Defines CRequestContext class for NCBI C++ diagnostic API.
Reader-writer based streams.
"Accept:" header entry.
Definition: cgiapp.hpp:340
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 Thu Apr 11 15:19:48 2024 by modify_doxy.py rev. 669887