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

Go to the SVN repository for this file.

1 /* $Id: request_ctx.cpp 99307 2023-03-08 14:20:02Z ivanov $
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  * Authors: Aleksey Grichenko, Denis Vakatov
27  *
28  * File Description:
29  * Request context for diagnostic framework.
30  *
31  */
32 
33 
34 #include <ncbi_pch.hpp>
35 
36 #include <corelib/request_ctx.hpp>
37 #include <corelib/ncbi_param.hpp>
38 #include <corelib/ncbi_strings.h>
39 #include <corelib/error_codes.hpp>
40 #include <corelib/ncbi_mask.hpp>
41 
42 
43 #define NCBI_USE_ERRCODE_X Corelib_Diag
44 
46 
47 
48 static const char* kPassThrough_Sid = "ncbi_sid";
49 static const char* kPassThrough_Phid = "ncbi_phid";
50 static const char* kPassThrough_ClientIp = "ncbi_client_ip";
51 static const char* kPassThrough_Dtab = "ncbi_dtab";
52 
53 
55 
56 
57 // What to do on a bad hit ID -- allow-and-report by default
58 
65 };
66 
67 NCBI_PARAM_ENUM_DECL(EOnBadHitID, Log, On_Bad_Hit_Id);
68 NCBI_PARAM_ENUM_ARRAY(EOnBadHitID, Log, On_Bad_Hit_Id)
69 {
70  {"Allow", eOnBadPHID_Allow},
71  {"AllowAndReport", eOnBadPHID_AllowAndReport},
72  {"Ignore", eOnBadPHID_Ignore},
73  {"IgnoreAndReport", eOnBadPHID_IgnoreAndReport},
74  {"Throw", eOnBadPHID_Throw}
75 };
76 NCBI_PARAM_ENUM_DEF_EX(EOnBadHitID, Log, On_Bad_Hit_Id,
79  LOG_ON_BAD_HIT_ID);
80 typedef NCBI_PARAM_TYPE(Log, On_Bad_Hit_Id) TOnBadHitId;
81 
82 
83 static const char* kAllowedIdMarkchars = "_-.:@";
84 
85 
86 static bool IsValidHitID(const string& hit)
87 {
88  string id_std = kAllowedIdMarkchars;
89  size_t pos = 0;
90  size_t sep_pos = NPOS;
91  // Allow aphanumeric and some markup before the first separator (dot).
92  for (; pos < hit.size(); pos++) {
93  char c = hit[pos];
94  if (c == '.') {
95  sep_pos = pos;
96  break;
97  }
98  if (!isalnum(c) && id_std.find(c) == NPOS) {
99  return false;
100  }
101  }
102  // Hit id must be present before the first separator.
103  // Note that empty hit id is still allowed if there are no sub-hit ids.
104  if (sep_pos == 0) return false;
105  if (sep_pos == NPOS) return true;
106  // Separator found - make sure the rest of the id contains only separators
107  // and valid sub-hit ids: a prefix consisting of allowed chars and some
108  // digits (XYZ.1.J2.T34).
109  size_t last_digit = sep_pos;
110  for (pos = sep_pos + 1; pos < hit.size(); pos++) {
111  char c = hit[pos];
112  if (c == '.') {
113  // Need at least one char between separators.
114  if (pos == sep_pos + 1) return false;
115  // Need at least one digit before separator.
116  if (last_digit + 1 != pos) return false;
117  sep_pos = pos;
118  continue;
119  }
120  if (!isalnum(c) && id_std.find(c) == NPOS) {
121  return false;
122  }
123  if ( isdigit(c) ) last_digit = pos;
124  }
125  // Make sure the last char is digit.
126  return pos > sep_pos + 1;
127 }
128 
129 
130 void CSharedHitId::x_SetHitId(const string& hit_id)
131 {
132  if (GetHitId() == hit_id) {
133  return;
134  }
135  if (IsValidHitID(hit_id)) {
136  m_HitId = hit_id;
137  } else {
138  static CSafeStatic<TOnBadHitId> action;
139  switch (action->Get()) {
140  case eOnBadPHID_Allow:
142  // Regardless of the allow status lets sanitize bad value,
143  // allow letters, digits and selected marks only, remlace all bad chars with '_'.
144  // Resulting PHID still can be invalid, see CXX-12891
146  if (action->Get() == eOnBadPHID_AllowAndReport) {
147  ERR_POST_X(27, Warning << "Bad hit ID format: " << NStr::PrintableString(hit_id)
148  << ", sanitized value will be used: " << m_HitId);
149  }
150  break;
151  case eOnBadPHID_Ignore:
152  return;
154  ERR_POST_X(27, Warning << "Bad hit ID format: " << NStr::PrintableString(hit_id));
155  return;
156  case eOnBadPHID_Throw:
157  NCBI_THROW(CRequestContextException, eBadHit, "Bad hit ID format: " + NStr::PrintableString(hit_id));
158  break;
159  }
160  }
161 }
162 
163 
164 
166  : m_RequestID(0),
167  m_AppState(eDiagAppState_NotSet),
168  m_HitIDLoggedFlag(0),
169  m_ReqStatus(0),
170  m_ReqTimer(CStopWatch::eStop),
171  m_BytesRd(0),
172  m_BytesWr(0),
173  m_PropSet(0),
174  m_IsRunning(false),
175  m_AutoIncOnPost(false),
176  m_Flags(flags),
177  m_OwnerTID(-1),
178  m_IsReadOnly(false),
179  m_Version(sm_VersionCounter.Add(1))
180 {
182 }
183 
184 
186 {
187 }
188 
189 
191 {
192  static CAtomicCounter s_RequestCount;
193  return s_RequestCount.Add(1);
194 }
195 
196 
197 void CRequestContext::x_LogHitID(bool ignore_app_state) const
198 {
199  if ((m_HitIDLoggedFlag & fLoggedOnRequest) || m_HitID.Empty()) return;
200 
201  // ignore_app_state can be set by CDiagContext in case if hit-id
202  // was set for request context only (no default one), but request
203  // start/stop never happened and the hit id may be lost. If this
204  // happens, CDiagContext may force logging of the request's hit id
205  // on application stop.
206 
207  if (!ignore_app_state &&
212  m_HitID.GetHitId());
214 }
215 
216 
217 const string& CRequestContext::SetHitID(void)
218 {
219  if (x_CanModify()) {
220  SetHitID(GetDiagContext().GetNextHitID());
221  }
222  return m_HitID.GetHitId();
223 }
224 
225 
227 {
228  if ( x_IsSetProp(eProp_HitID) ) {
229  x_LogHitID();
230  return m_HitID.GetHitId();
231  }
232  if (!x_CanModify()) return kEmptyStr;
234  if (!phid.Empty()) {
235  const_cast<CRequestContext*>(this)->x_SetHitID(phid);
236  return phid.GetHitId();
237  }
238  if (flag != CDiagContext::eHitID_NoCreate) {
239  // If there's no hit id available, create (and log) a new one.
240  return const_cast<CRequestContext*>(this)->SetHitID();
241  }
242  return kEmptyStr;
243 }
244 
245 
246 const string& CRequestContext::SetSessionID(void)
247 {
248  CNcbiOstrstream oss;
250  oss << ctx.GetStringUID(ctx.UpdateUID()) << '_' << setw(4) << setfill('0')
251  << GetRequestID() << "SID";
254 }
255 
256 
258 {
261 }
262 
263 
265 {
266  if (!x_CanModify()) return;
267  m_AppState = state;
268 }
269 
270 
272 {
273  if (!x_CanModify()) return;
274  m_AppState = eDiagAppState_NotSet; // Use global AppState
275  UnsetRequestID();
276  UnsetClientIP();
277  UnsetSessionID();
278  UnsetHitID();
280  UnsetBytesRd();
281  UnsetBytesWr();
282  m_ReqTimer.Reset();
285 }
286 
287 
288 void CRequestContext::SetProperty(const string& name, const string& value)
289 {
290  if (!x_CanModify()) return;
291  m_Properties[name] = value;
292 }
293 
294 
295 const string& CRequestContext::GetProperty(const string& name) const
296 {
298  return it != m_Properties.end() ? it->second : kEmptyStr;
299 }
300 
301 
302 bool CRequestContext::IsSetProperty(const string& name) const
303 {
304  return m_Properties.find(name) != m_Properties.end();
305 }
306 
307 
308 void CRequestContext::UnsetProperty(const string& name)
309 {
310  if (!x_CanModify()) return;
311  m_Properties.erase(name);
312 }
313 
314 
315 static const char* kBadIP = "0.0.0.0";
316 
317 
319 {
320  if (!x_CanModify()) return;
322 
323  // Verify IP
324  string ip = NStr::TruncateSpaces(client);
325  if ( !NStr::IsIPAddress(ip) ) {
326  m_ClientIP = kBadIP;
327  x_Modify();
328  ERR_POST_X(25, "Bad client IP value: " << ip);
329  return;
330  }
331 
332  m_ClientIP = ip;
333  x_Modify();
334 }
335 
336 
338 {
339  if (!x_CanModify()) return;
341  if (m_Flags & fResetOnStart) {
343  SetBytesRd(0);
344  SetBytesWr(0);
345  }
347  m_IsRunning = true;
348  x_LogHitID();
349  if (m_Tracer) {
350  m_Tracer->OnRequestStart(*this);
351  }
352 }
353 
354 
356 {
357  if (!x_CanModify()) return;
358  if (m_Tracer) {
359  m_Tracer->OnRequestStop(*this);
360  }
361  if ((m_HitIDLoggedFlag & fLoggedOnRequest) == 0) {
362  // Hit id has not been set or logged yet. Try to log the default one.
364  }
365  Reset();
366  m_IsRunning = false;
367 }
368 
369 
371 {
372  static bool s_DefaultAutoIncRequestIDOnPostFlag = false;
373  return s_DefaultAutoIncRequestIDOnPostFlag;
374 }
375 
376 
378 {
380 }
381 
382 
384 {
386 }
387 
388 
389 
390 
391 
393 {
394  if (!x_CanModify()) return;
395 
396  const string& hit = hit_id.GetHitId();
398  // Show warning when changing hit id after is has been logged.
399  ERR_POST_X(28, Warning << "Changing hit ID after one has been logged. New hit id is: " << hit);
400  }
402  m_SubHitIDCache.clear();
403  m_HitID = hit_id;
404  x_Modify();
405  m_HitIDLoggedFlag = 0;
406  x_LogHitID();
407 }
408 
409 
410 void CRequestContext::SetHitID(const string& hit)
411 {
412  if (!x_CanModify()) return;
413  x_SetHitID(CSharedHitId(hit));
414 }
415 
416 
417 // Use old output format if the flag is set
418 NCBI_PARAM_DECL(unsigned int, Log, Issued_SubHit_Limit);
419 NCBI_PARAM_DEF_EX(unsigned int, Log, Issued_SubHit_Limit, 200, eParam_NoThread,
420  LOG_ISSUED_SUBHIT_LIMIT);
421 typedef NCBI_PARAM_TYPE(Log, Issued_SubHit_Limit) TIssuedSubHitLimitParam;
422 
423 
425 {
426  _ASSERT(IsSetHitID());
427 
428  // Use global sub-hit counter for default hit id to prevent
429  // duplicate phids in different threads.
430  string hit_id = GetHitID();
431 
432  unsigned int sub_hit_id;
433  if (increment) {
434  sub_hit_id = m_HitID.GetNextSubHitId();
435  x_Modify();
436  }
437  else {
438  sub_hit_id = m_HitID.GetCurrentSubHitId();
439  }
440 
441  // Cache the string so that C code can use it.
442  string subhit = prefix + NStr::NumericToString(sub_hit_id);
443  hit_id += "." + subhit;
444  m_SubHitIDCache = hit_id;
445  if (increment && sub_hit_id <= TIssuedSubHitLimitParam::GetDefault()) {
446  GetDiagContext().Extra().Print("issued_subhit", subhit);
447  }
448 }
449 
450 
451 void CRequestContext::SetSessionID(const string& session)
452 {
453  if (!x_CanModify()) return;
454  if ( !IsValidSessionID(session) ) {
456  switch ( action ) {
457  case eOnBadSID_Ignore:
458  return;
460  ERR_POST_X(26, Warning << "Bad session ID format: " << session);
461  break;
463  ERR_POST_X(26, Warning << "Bad session ID format: " << session);
464  return;
465  case eOnBadSID_Throw:
467  "Bad session ID format: " + session);
468  break;
469  case eOnBadSID_Allow:
470  break;
471  }
472  }
474  m_SessionID.SetString(session);
475  x_Modify();
476 }
477 
478 
479 bool CRequestContext::IsValidSessionID(const string& session_id)
480 {
481  switch ( GetAllowedSessionIDFormat() ) {
482  case eSID_Ncbi:
483  {
484  if (session_id.size() < 24) return false;
485  if (session_id[16] != '_') return false;
486  if ( !NStr::EndsWith(session_id, "SID") ) return false;
487  CTempString uid(session_id, 0, 16);
488  if (NStr::StringToUInt8(uid, NStr::fConvErr_NoThrow, 16) == 0 && errno !=0) {
489  return false;
490  }
491  CTempString rqid(session_id, 17, session_id.size() - 20);
492  if (NStr::StringToUInt(rqid, NStr::fConvErr_NoThrow) == 0 && errno != 0) {
493  return false;
494  }
495  break;
496  }
497  case eSID_Standard:
498  {
499  if ( session_id.empty() ) {
500  return false;
501  }
502  string id_std = kAllowedIdMarkchars;
503  ITERATE (string, c, session_id) {
504  if (!isalnum(*c) && id_std.find(*c) == NPOS) {
505  return false;
506  }
507  }
508  break;
509  }
510  case eSID_Other:
511  return true;
512  }
513  return true;
514 }
515 
516 
519 {
521  {"AllowAndReport", CRequestContext::eOnBadSID_AllowAndReport},
523  {"IgnoreAndReport", CRequestContext::eOnBadSID_IgnoreAndReport},
525 };
529  LOG_ON_BAD_SESSION_ID);
530 typedef NCBI_PARAM_TYPE(Log, On_Bad_Session_Id) TOnBadSessionId;
531 
532 
535 {
536  {"Ncbi", CRequestContext::eSID_Ncbi},
537  {"Standard", CRequestContext::eSID_Standard},
538  {"Other", CRequestContext::eSID_Other}
539 };
543  LOG_SESSION_ID_FORMAT);
544 typedef NCBI_PARAM_TYPE(Log, Session_Id_Format) TSessionIdFormat;
545 
546 
548 {
549  return TOnBadSessionId::GetDefault();
550 }
551 
552 
554 {
555  TOnBadSessionId::SetDefault(action);
556 }
557 
558 
560 {
561  return TSessionIdFormat::GetDefault();
562 }
563 
564 
566 {
567  TSessionIdFormat::SetDefault(fmt);
568 }
569 
570 
572 {
574  ret->m_RequestID = m_RequestID;
575  ret->m_AppState = m_AppState;
576  ret->m_ClientIP = m_ClientIP;
578  m_HitID.SetShared();
579  ret->m_HitID = m_HitID;
582  ret->m_Dtab = m_Dtab;
583  ret->m_ReqStatus = m_ReqStatus;
584  ret->m_ReqTimer = m_ReqTimer;
585  ret->m_BytesRd = m_BytesRd;
586  ret->m_BytesWr = m_BytesWr;
587  ret->m_Properties = m_Properties;
588  ret->m_PropSet = m_PropSet;
589  ret->m_IsRunning = m_IsRunning;
591  ret->m_Flags = m_Flags;
592  ret->m_IsReadOnly = m_IsReadOnly;
593  // NOTE: Do not clone m_Version - the new context gets its own unique version.
594  return ret;
595 }
596 
597 
598 string CRequestContext::SelectLastHitID(const string& hit_ids)
599 {
600  // Empty string or single value - return as-is.
601  if (hit_ids.empty() || hit_ids.find_first_of(", ") == NPOS) {
602  return hit_ids;
603  }
604  list<string> ids;
605  // '+' is a temporary workaround for mismatched encoding/decoding of spaces.
606  NStr::Split(hit_ids, ", +", ids,
608  return ids.empty() ? kEmptyStr : ids.back();
609 }
610 
611 
612 string CRequestContext::SelectLastSessionID(const string& session_ids)
613 {
614  // Empty string or single value - return as-is.
615  if (session_ids.empty() || session_ids.find_first_of(", ") == NPOS) {
616  return session_ids;
617  }
618  list<string> ids;
619  NStr::Split(session_ids, ", ", ids,
621  REVERSE_ITERATE(list<string>, it, ids) {
622  if (*it != "UNK_SESSION") {
623  return *it;
624  }
625  }
626  return kEmptyStr;
627 }
628 
629 
631 {
632  if ( update ) x_UpdateStdPassThroughProp(name);
634  return found != m_PassThroughProperties.end();
635 }
636 
637 
638 const string& CRequestContext::x_GetPassThroughProp(CTempString name, bool update) const
639 {
640  if ( update ) x_UpdateStdPassThroughProp(name);
642  return found != m_PassThroughProperties.end() ? found->second : kEmptyStr;
643 }
644 
645 
648  bool update) const
649 {
650  if (!x_CanModify()) return;
652  if ( update ) x_UpdateStdContextProp(name);
653 }
654 
655 
657 {
658  if (!x_CanModify()) return;
660  if (found != m_PassThroughProperties.end()) {
662  if ( update ) x_UpdateStdContextProp(name);
663  }
664 }
665 
666 
668 {
669  if (name.empty() || NStr::EqualNocase(name, kPassThrough_Sid)) {
670  if ( IsSetSessionID() ) {
672  }
673  else {
675  }
676  }
677  if (name.empty() || NStr::EqualNocase(name, kPassThrough_ClientIp)) {
678  if ( IsSetClientIP() ) {
680  }
681  else {
683  }
684  }
685  if (name.empty() || NStr::EqualNocase(name, kPassThrough_Dtab)) {
686  if ( IsSetDtab() ) {
688  }
689  else {
691  }
692  }
693  if (name.empty() || NStr::EqualNocase(name, kPassThrough_Phid)) {
694  if ( IsSetHitID() ) {
695  string sub_phid = const_cast<CRequestContext&>(*this).GetCurrentSubHitID();
696  if ( sub_phid.empty() ) {
697  sub_phid = const_cast<CRequestContext&>(*this).GetNextSubHitID();
698  }
699  x_SetPassThroughProp(kPassThrough_Phid, sub_phid, false);
700  }
701  else {
703  }
704  }
705 }
706 
707 
709 {
710  CRequestContext& ctx = const_cast<CRequestContext&>(*this);
711 
713  if (name.empty() || match) {
715  ctx.SetSessionID(x_GetPassThroughProp(kPassThrough_Sid, false));
716  }
717  // Reset property only if explicit name is provided
718  else if ( match ) {
719  ctx.UnsetSessionID();
720  }
721  // Explicit name provided - skip other checks.
722  if ( match ) return;
723  }
724 
726  if (name.empty() || match) {
728  ctx.SetHitID(x_GetPassThroughProp(kPassThrough_Phid, false));
729  }
730  // Reset property only if explicit name is provided
731  else if ( match ) {
732  ctx.UnsetHitID();
733  }
734  // Explicit name provided - skip other checks.
735  if ( match ) return;
736  }
737 
739  if (name.empty() || match) {
741  ctx.SetClientIP(x_GetPassThroughProp(kPassThrough_ClientIp, false));
742  }
743  // Reset property only if explicit name is provided
744  else if ( match ) {
745  ctx.UnsetClientIP();
746  }
747  // Explicit name provided - skip other checks.
748  if ( match ) return;
749  }
750 
752  if (name.empty() || match) {
754  ctx.SetDtab(x_GetPassThroughProp(kPassThrough_Dtab, false));
755  }
756  // Reset property only if explicit name is provided
757  else if ( match ) {
758  ctx.UnsetDtab();
759  }
760  // Explicit name provided - skip other checks.
761  if ( match ) return;
762  }
763 }
764 
765 
766 NCBI_PARAM_DECL(string, Context, Fields);
767 NCBI_PARAM_DEF_EX(string, Context, Fields, "",
769  NCBI_CONTEXT_FIELDS);
770 typedef NCBI_PARAM_TYPE(Context, Fields) TNcbiContextFields;
771 
772 DEFINE_STATIC_MUTEX(s_ContextFieldsMutex);
773 unique_ptr<CMaskFileName> CRequestContext::sm_ContextFields;
774 unique_ptr<CRequestContext::TPassThroughProperties> CRequestContext::sm_EnvContextProperties;
775 
776 
778 {
779  if ( !sm_ContextFields.get() ) {
780  CMutexGuard guard(s_ContextFieldsMutex);
781  if ( !sm_ContextFields.get() ) {
782  sm_ContextFields.reset(new CMaskFileName());
783  string fields_var = TNcbiContextFields::GetDefault();
784  if ( !fields_var.empty() ) {
785  list<string> fields;
786  NStr::Split(fields_var, " ", fields, NStr::fSplit_MergeDelimiters);
787  ITERATE(list<string>, field, fields) {
788  string norm_field = sx_NormalizeContextPropertyName(*field);
789  sm_ContextFields->Add(norm_field);
790  }
791  }
792  else {
793  // By default exclude everything.
794  sm_ContextFields->AddExclusion("*");
795  }
796  }
797  }
798  return *sm_ContextFields;
799 }
800 
801 
803 {
804  return NStr::Replace(name, "_", "-");
805 }
806 
807 
809 {
810  if (!x_CanModify()) return;
811  // Parse environment only once.
812  if ( !sm_EnvContextProperties.get() ) {
814  {
816  if ( !app ) return;
817  const CNcbiEnvironment& env = app->GetEnvironment();
818  list<string> names;
819  env.Enumerate(names);
820  ITERATE(list<string>, it, names) {
821  props[*it] = env.Get(*it);
822  }
823  }
824 
825  CMutexGuard guard(s_ContextFieldsMutex);
826  if ( !sm_EnvContextProperties.get() ) {
829  ITERATE(TPassThroughProperties, it, props) {
830  string norm_prop = sx_NormalizeContextPropertyName(it->first);
831  if ( mask.Match(norm_prop, NStr::eNocase) ) {
832  (*sm_EnvContextProperties)[norm_prop] = it->second;
833  }
834  }
835  }
836  }
838 }
839 
840 
841 void CRequestContext::AddPassThroughProperty(const string& name, const string& value)
842 {
843  if (!x_CanModify()) return;
845  string norm_prop = sx_NormalizeContextPropertyName(name);
846  if ( mask.Match(norm_prop, NStr::eNocase) ) {
847  m_PassThroughProperties[norm_prop] = value;
848  }
849 }
850 
851 
853 {
855 
856  switch (format) {
857  case eFormat_UrlEncoded:
858  return x_SerializeUrlEncoded();
859  }
860  return kEmptyStr;
861 }
862 
863 
865 {
866  switch (format) {
867  case eFormat_UrlEncoded:
869  break;
870  }
871 
873 }
874 
875 
877 {
880 }
881 
882 
884 {
887  "&", "=", new CStringDecoder_Url());
888 }
889 
890 
892 {
893  switch (GetErrCode()) {
894  case eBadSession: return "eBadSession";
895  case eBadHit: return "eBadHit";
896  default: return CException::GetErrCodeString();
897  }
898 }
899 
900 
902  : m_Flags(flags)
903 {
904  m_OriginatesFromThrow = uncaught_exceptions();
906  if ( context ) {
907  m_SavedContext.Reset(&ctx.GetRequestContext());
908  m_RequestContext.Reset(context);
909  ctx.SetRequestContext(context);
910  }
911  else {
912  m_RequestContext.Reset(&ctx.GetRequestContext());
913  }
914 
915  if (m_Flags & fPrintRequestStart) {
916  // This also updates app state to RB/R
917  ctx.PrintRequestStart();
918  }
919 }
920 
921 
923 {
924  // If released, do not perform any actions.
925  if ( !m_RequestContext ) return;
926 
927  if ( uncaught_exceptions() && !m_OriginatesFromThrow ) {
929  }
930  else if ( !m_RequestContext->IsSetRequestStatus() ) {
932  }
933 
935  // This also updates app state to RE/P
936  ctx.PrintRequestStop();
937 
938  if ( m_SavedContext ) {
939  ctx.SetRequestContext(m_SavedContext.GetNonNullPointer());
940  }
941 }
942 
943 
945 {
946  if ( m_SavedContext ) {
949  }
951 }
952 
953 
955 {
956  // If the guard has been released throw null pointer exception.
958  m_ErrorStatus = status;
959 }
960 
961 
ncbi::TMaskedQueryRegions mask
#define false
Definition: bool.h:36
CAtomicCounter –.
Definition: ncbicntr.hpp:71
CMaskFileName –.
Definition: ncbi_mask.hpp:107
CMask –.
Definition: ncbi_mask.hpp:59
CNcbiEnvironment –.
Definition: ncbienv.hpp:104
CNcbiOstrstreamToString class helps convert CNcbiOstrstream to a string Sample usage:
Definition: ncbistre.hpp:802
CSafeStatic<>::
T & Get(void)
Create the variable if not created yet, return the reference.
Helper class to hold hit id and sub-hit counter which can be shared between multiple request contexts...
Definition: request_ctx.hpp:65
CStopWatch –.
Definition: ncbitime.hpp:1938
URL-decoder for string pairs parser.
Definition: ncbistr.hpp:4564
URL-encoder for string pairs parser.
Definition: ncbistr.hpp:4577
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
void erase(iterator pos)
Definition: map.hpp:167
container_type::const_iterator const_iterator
Definition: map.hpp:53
const_iterator end() const
Definition: map.hpp:152
iterator_bool insert(const value_type &val)
Definition: map.hpp:165
void clear()
Definition: map.hpp:169
const_iterator find(const key_type &key) const
Definition: map.hpp:153
char value[7]
Definition: config.c:431
static uch flags
CS_CONTEXT * ctx
Definition: t0006.c:12
static const char ip[]
Definition: des.c:75
static const struct name_t names[]
const CNcbiEnvironment & GetEnvironment(void) const
Get the application's cached environment.
static CNcbiApplicationGuard InstanceGuard(void)
Singleton method.
Definition: ncbiapp.cpp:133
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define REVERSE_ITERATE(Type, Var, Cont)
ITERATE macro to reverse sequence through container elements.
Definition: ncbimisc.hpp:827
TValue Add(int delta) THROWS_NONE
Atomically add value (=delta), and return new counter value.
Definition: ncbicntr.hpp:278
void x_Modify(void)
void StartRequest(void)
static string SelectLastHitID(const string &hit_ids)
Select the last hit id from the list of ids separated with commas and optional spaces.
TSubHitId GetNextSubHitId(void)
Get next sub-hit id value.
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 UnsetRequestStatus(void)
ESessionIDFormat
Session ID format.
string x_GetHitID(CDiagContext::EDefaultHitIDFlags flag) const
void SetBytesWr(Int8 bytes)
CEncodedString m_SessionID
EDiagAppState GetGlobalAppState(void) const
Always returns global application state.
Definition: ncbidiag.cpp:2796
CDiagContext & GetDiagContext(void)
Get diag context instance.
Definition: logging.cpp:818
void x_SetHitID(const CSharedHitId &hit_id)
static const CMask & sx_GetContextFieldsMask(void)
void SetAppState(EDiagAppState state)
static void SetRequestContext(CRequestContext *ctx)
Shortcut to CDiagContextThreadData::GetThreadData().SetRequestContext()
Definition: ncbidiag.cpp:1907
TSubHitId GetCurrentSubHitId(void) const
Get current sub-hit id value.
CRef< CRequestContext > m_SavedContext
static void SetBadSessionIDAction(EOnBadSessionID action)
void x_SetProp(EProperty prop)
static string sx_NormalizeContextPropertyName(const string &name)
void UnsetBytesWr(void)
string GetSessionID(void) const
Session ID.
string Serialize(EFormat format) const
Serialize current values using the specified format.
void UnsetClientIP(void)
CDiagContext_Extra Extra(void) const
Create a temporary CDiagContext_Extra object.
Definition: ncbidiag.hpp:2095
bool IsSetRequestStatus(void) const
const string & GetProperty(const string &name) const
Get property value or empty string.
bool x_IsSetProp(EProperty prop) const
const string & GetNextSubHitID(CTempString prefix=CTempString())
Get current hit id appended with auto-incremented sub-hit id.
static unique_ptr< TPassThroughProperties > sm_EnvContextProperties
void SetClientIP(const string &client)
static TCount GetNextRequestID(void)
Return the next available application-wide request ID.
const string & SetHitID(void)
Generate unique hit id, assign it to this request, return the hit id value.
CRequestContextGuard_Base(CRequestContext *context, TFlags flags=0)
Initialize guard.
static string SelectLastSessionID(const string &session_ids)
Select the last session id from the list of ids separated with commas and optional spaces,...
void SetProperty(const string &name, const string &value)
Add/change property.
void x_DeserializeUrlEncoded(CTempString data)
bool IsSetSessionID(void) const
void SetStatus(int status)
Set request context status.
TCount GetRequestID(void) const
Get request ID (or zero if not set).
TPropSet m_PropSet
string GetClientIP(void) const
Client IP/hostname.
static bool & sx_GetDefaultAutoIncRequestIDOnPost(void)
void StopRequest(void)
CRef< CRequestContext > Clone(void) const
Copy current request context to a new one.
void UnsetProperty(const string &name)
Remove property from the map.
string x_SerializeUrlEncoded(void) const
void x_SetPassThroughProp(CTempString name, CTempString value, bool update) const
static ESessionIDFormat GetAllowedSessionIDFormat(void)
Get/set allowed session id format.
void SetRequestStatus(int status)
EDiagAppState m_AppState
bool IsSetHitID(EHitIDSource src=eHitID_Any) const
Check if there's an explicit hit id or the default one.
void x_UpdateStdContextProp(CTempString name) const
static bool IsValidSessionID(const string &session_id)
Check if session id fits the allowed format.
void UnsetRequestID(void)
Reset request ID.
CStopWatch m_ReqTimer
const string & GetDtab(void) const
static bool GetDefaultAutoIncRequestIDOnPost(void)
Get default auto-increment flag.
static CAtomicCounter sm_VersionCounter
bool x_IsSetPassThroughProp(CTempString name, bool update) const
void Deserialize(CTempString data, EFormat format)
Deserialize values using the specified format.
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
bool IsSetProperty(const string &name) const
Check if the property has a value (even if it's an empty string).
static EOnBadSessionID GetBadSessionIDAction(void)
Get/set session id error action.
const CStopWatch & GetRequestTimer(void) const
Request execution timer.
EFormat
Supported serialization/deserialization formats.
CRef< CRequestContext > m_Context
static unique_ptr< CMaskFileName > sm_ContextFields
bool IsSetDtab(void) const
Dtab.
void UnsetSessionID(void)
string m_SubHitIDCache
void x_SetHitId(const string &hit_id)
Set new hit id, checks its validity.
const string & x_GetPassThroughProp(CTempString name, bool update) const
void x_ResetPassThroughProp(CTempString name, bool update) const
void x_LoadEnvContextProperties(void)
const string & SetSessionID(void)
Create and set new session ID.
void SetBytesRd(Int8 bytes)
virtual ~CRequestContext(void)
static void SetAllowedSessionIDFormat(ESessionIDFormat fmt)
CSharedHitId x_GetDefaultHitID(EDefaultHitIDFlags flag) const
Definition: ncbidiag.cpp:2997
EDiagAppState
Application execution states shown in the std prefix.
Definition: ncbidiag.hpp:789
bool IsSetClientIP(void) const
void UnsetBytesRd(void)
TProperties m_Properties
SDiagMessage::TCount TCount
EOnBadSessionID
Session ID error actions.
void AddPassThroughProperty(const string &name, const string &value)
Add pass-through value if it matches a pattern from NCBI_CONTEXT_FIELDS.
bool Empty(void) const
Definition: request_ctx.hpp:77
void UnsetHitID(void)
Reset explicit hit id.
string GetHitID(void) const
Get explicit hit id or the default one (from HTTP_NCBI_PHID etc).
void Reset(void)
Reset all properties to the initial state.
TPassThroughProperties m_PassThroughProperties
static void SetDefaultAutoIncRequestIDOnPost(bool enable)
Set default auto-increment flag used for each default request context.
void SetShared(void) const
Mark this hit id as a shared one and start using shared counter.
Definition: request_ctx.hpp:80
CSharedHitId m_HitID
CRequestContext(TContextFlags flags=fDefault)
TContextFlags m_Flags
shared_ptr< IRequestTracer > m_Tracer
const string & GetHitId(void) const
Get hit id value.
Definition: request_ctx.hpp:91
void x_UpdateStdPassThroughProp(CTempString name) const
void Release(void)
Release the guarded context, restore the saved context if any, do not perform any other actions (logg...
const string & GetCurrentSubHitID(CTempString prefix=CTempString())
Get the last generated sub-hit id.
void x_UpdateSubHitID(bool increment, CTempString prefix)
void x_LogHitID(bool ignore_app_state=false) const
~CRequestContextGuard_Base(void)
Destroy guard.
CRef< CRequestContext > m_RequestContext
EDiagAppState GetAppState(void) const
Application state.
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
bool x_CanModify(void) const
void SetDefaultErrorStatus(int status)
Set default error status, which will be used if an uncaught exception is detected.
@ fResetOnStart
Reset values when printing request-start.
@ eSID_Other
Any other format.
@ eSID_Ncbi
Strict NCBI format: (UID:16)_(RqID:4+)SID.
@ eSID_Standard
Alpanum, underscore, -.:@, (default)
@ eBadSession
Invalid session id.
@ eBadHit
Invalid hit id.
@ fPrintRequestStart
Print request-start automatically in the constructor.
@ eFormat_UrlEncoded
name=value pairs URL-encoded and separated with '&'
@ eDiagAppState_RequestEnd
RE.
Definition: ncbidiag.hpp:796
@ eDiagAppState_RequestBegin
RB.
Definition: ncbidiag.hpp:794
@ eDiagAppState_NotSet
Reserved value, never used in messages.
Definition: ncbidiag.hpp:790
@ eDiagAppState_Request
R.
Definition: ncbidiag.hpp:795
@ eOnBadSID_Allow
Don't validate session id.
@ eOnBadSID_IgnoreAndReport
Ignore and show warning.
@ eOnBadSID_AllowAndReport
Accept but show warning (default).
@ eOnBadSID_Throw
Throw on bad session id.
@ eOnBadSID_Ignore
Ignore bad session id.
#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
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:444
TObjectType * GetNonNullPointer(void)
Get pointer value and throw a null pointer exception if pointer is null.
Definition: ncbiobj.hpp:968
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
@ eParam_NoThread
Do not use per-thread values.
Definition: ncbi_param.hpp:418
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static string PrintableString(const CTempString str, TPrintableMode mode=fNewLine_Quote|fNonAscii_Passthru)
Get a printable version of the specified string.
Definition: ncbistr.cpp:3949
void Parse(const CTempString str, NStr::EMergeDelims merge_argsep=NStr::eMergeDelims)
Parse the string.
Definition: ncbistr.hpp:4697
string Merge(void) const
Merge name-value pairs into a single string using the currently set separators and the provided encod...
Definition: ncbistr.hpp:4752
#define kEmptyStr
Definition: ncbistr.hpp:123
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:3457
static bool EndsWith(const CTempString str, const CTempString end, ECase use_case=eCase)
Check if a string ends with a specified suffix value.
Definition: ncbistr.hpp:5429
const char * g_GetNcbiString(ENcbiStrings what)
Definition: ncbi_strings.c:42
#define NPOS
Definition: ncbistr.hpp:133
const string & GetOriginalString(void) const
Get the original unencoded string.
Definition: ncbistr.hpp:4835
bool empty(void) const
Return true if the represented string is empty (i.e., the length is zero)
Definition: tempstr.hpp:334
static string & Replace(const string &src, const string &search, const string &replace, string &dst, 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:3310
static Uint8 StringToUInt8(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to Uint8.
Definition: ncbistr.cpp:873
static unsigned int StringToUInt(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to unsigned int.
Definition: ncbistr.cpp:642
static string Sanitize(CTempString str, TSS_Flags flags=fSS_print)
Sanitize a string, allowing only specified classes of characters.
Definition: ncbistr.hpp:2876
static bool IsIPAddress(const CTempStringEx str)
Check if the string contains a valid IP address.
Definition: ncbistr.cpp:6392
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:5352
void SetString(const CTempString s, NStr::EUrlEncode flag=NStr::eUrlEnc_SkipMarkChars)
Set new original string.
Definition: ncbistr.cpp:7303
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 TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3182
@ eNcbiStrings_PHID
Definition: ncbi_strings.h:56
@ fSS_NoMerge
Do not merge adjacent spaces (rejected chars)
Definition: ncbistr.hpp:2848
@ fSS_alnum
Check on isalnum()
Definition: ncbistr.hpp:2837
@ 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
@ eUrlEnc_Cookie
Same as SkipMarkChars with encoded ','.
Definition: ncbistr.hpp:3153
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
double Restart(void)
Return time elapsed since first Start() or last Restart() call (in seconds).
Definition: ncbitime.hpp:2817
void Reset(void)
Stop (if running) and reset the timer.
Definition: ncbitime.hpp:2808
Definition of all error codes used in corelib (xncbi.lib).
Classes to match a string against a set of masks.
String constants used in NCBI C/C++ toolkit.
int isalnum(Uchar c)
Definition: ncbictype.hpp:62
int isdigit(Uchar c)
Definition: ncbictype.hpp:64
static Format format
Definition: njn_ioutil.cpp:53
static int match(register const pcre_uchar *eptr, register const pcre_uchar *ecode, const pcre_uchar *mstart, int offset_top, match_data *md, eptrblock *eptrb, unsigned int rdepth)
Definition: pcre_exec.c:513
static const char * prefix[]
Definition: pcregrep.c:405
NCBI_PARAM_DECL(unsigned int, Log, Issued_SubHit_Limit)
static const char * kAllowedIdMarkchars
Definition: request_ctx.cpp:83
static const char * kPassThrough_Sid
Definition: request_ctx.cpp:48
NCBI_PARAM_ENUM_DEF_EX(EOnBadHitID, Log, On_Bad_Hit_Id, eOnBadPHID_AllowAndReport, eParam_NoThread, LOG_ON_BAD_HIT_ID)
static const char * kPassThrough_ClientIp
Definition: request_ctx.cpp:50
static const char * kBadIP
NCBI_PARAM_ENUM_ARRAY(EOnBadHitID, Log, On_Bad_Hit_Id)
Definition: request_ctx.cpp:68
NCBI_PARAM_ENUM_DECL(EOnBadHitID, Log, On_Bad_Hit_Id)
static bool IsValidHitID(const string &hit)
Definition: request_ctx.cpp:86
typedef NCBI_PARAM_TYPE(Log, On_Bad_Hit_Id) TOnBadHitId
DEFINE_STATIC_MUTEX(s_ContextFieldsMutex)
EOnBadHitID
Definition: request_ctx.cpp:59
@ eOnBadPHID_Allow
Definition: request_ctx.cpp:60
@ eOnBadPHID_Throw
Definition: request_ctx.cpp:64
@ eOnBadPHID_AllowAndReport
Definition: request_ctx.cpp:61
@ eOnBadPHID_IgnoreAndReport
Definition: request_ctx.cpp:63
@ eOnBadPHID_Ignore
Definition: request_ctx.cpp:62
static const char * kPassThrough_Phid
Definition: request_ctx.cpp:49
NCBI_PARAM_DEF_EX(unsigned int, Log, Issued_SubHit_Limit, 200, eParam_NoThread, LOG_ISSUED_SUBHIT_LIMIT)
static const char * kPassThrough_Dtab
Definition: request_ctx.cpp:51
Defines CRequestContext class for NCBI C++ diagnostic API.
static CNamedPipeClient * client
#define _ASSERT
static HENV env
Definition: transaction2.c:38
Modified on Tue Dec 05 02:09:50 2023 by modify_doxy.py rev. 669887