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 103157 2024-09-16 18:33:36Z grichenk $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * 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  m_SpanKind(ITracerSpan::eKind_NotSet)
181 {
183 }
184 
185 
187 {
188 }
189 
190 
192 {
193  static CAtomicCounter s_RequestCount;
194  return s_RequestCount.Add(1);
195 }
196 
197 
198 void CRequestContext::x_LogHitID(bool ignore_app_state) const
199 {
200  if ((m_HitIDLoggedFlag & fLoggedOnRequest) || m_HitID.Empty()) return;
201 
202  // ignore_app_state can be set by CDiagContext in case if hit-id
203  // was set for request context only (no default one), but request
204  // start/stop never happened and the hit id may be lost. If this
205  // happens, CDiagContext may force logging of the request's hit id
206  // on application stop.
207 
208  if (!ignore_app_state &&
213  m_HitID.GetHitId());
215 }
216 
217 
218 const string& CRequestContext::SetHitID(void)
219 {
220  if (x_CanModify()) {
221  SetHitID(GetDiagContext().GetNextHitID());
222  }
223  return m_HitID.GetHitId();
224 }
225 
226 
228 {
229  if ( x_IsSetProp(eProp_HitID) ) {
230  x_LogHitID();
231  return m_HitID.GetHitId();
232  }
233  if (!x_CanModify()) return kEmptyStr;
235  if (!phid.Empty()) {
236  const_cast<CRequestContext*>(this)->x_SetHitID(phid);
237  return phid.GetHitId();
238  }
239  if (flag != CDiagContext::eHitID_NoCreate) {
240  // If there's no hit id available, create (and log) a new one.
241  return const_cast<CRequestContext*>(this)->SetHitID();
242  }
243  return kEmptyStr;
244 }
245 
246 
247 const string& CRequestContext::SetSessionID(void)
248 {
249  CNcbiOstrstream oss;
251  oss << ctx.GetStringUID(ctx.UpdateUID()) << '_' << setw(4) << setfill('0')
252  << GetRequestID() << "SID";
255 }
256 
257 
259 {
262 }
263 
264 
266 {
267  if (!x_CanModify()) return;
268  m_AppState = state;
269 }
270 
271 
273 {
274  if (!x_CanModify()) return;
275  m_AppState = eDiagAppState_NotSet; // Use global AppState
276  UnsetRequestID();
277  UnsetClientIP();
278  UnsetSessionID();
279  UnsetHitID();
281  UnsetBytesRd();
282  UnsetBytesWr();
283  m_ReqTimer.Reset();
286 }
287 
288 
289 void CRequestContext::SetProperty(const string& name, const string& value)
290 {
291  if (!x_CanModify()) return;
292  m_Properties[name] = value;
293 }
294 
295 
296 const string& CRequestContext::GetProperty(const string& name) const
297 {
299  return it != m_Properties.end() ? it->second : kEmptyStr;
300 }
301 
302 
303 bool CRequestContext::IsSetProperty(const string& name) const
304 {
305  return m_Properties.find(name) != m_Properties.end();
306 }
307 
308 
309 void CRequestContext::UnsetProperty(const string& name)
310 {
311  if (!x_CanModify()) return;
312  m_Properties.erase(name);
313 }
314 
315 
316 static const char* kBadIP = "0.0.0.0";
317 
318 
320 {
321  if (!x_CanModify()) return;
323 
324  // Verify IP (tolerating optional enclosing square brackets, [...])
326  size_t len = ip.size();
327  bool bad;
328  if (!len) {
329  bad = true;
330  } else if (ip[0] != '[') {
331  bad = false;
332  } else if (len < 3 || ip[len - 1] != ']') {
333  bad = true;
334  } else {
335  ip = ip.substr(1, len - 2);
336  bad = false;
337  }
338  if (!bad && !NStr::IsIPAddress(ip)) {
339  bad = true;
340  }
341  if ( bad ) {
342  m_ClientIP = kBadIP;
343  x_Modify();
344  ERR_POST_X(25, "Bad client IP value: " << ip);
345  return;
346  }
347 
348  m_ClientIP = ip;
349  x_Modify();
350 }
351 
352 
354 {
355  if (!x_CanModify()) return;
357  if (m_Flags & fResetOnStart) {
359  SetBytesRd(0);
360  SetBytesWr(0);
361  }
363  m_IsRunning = true;
364  x_LogHitID();
365  // Save the tracer to make sure the same one is used to stop request.
367  if (m_Tracer) {
368  m_Tracer->OnRequestStart(*this);
369  }
370 }
371 
372 
374 {
375  if (!x_CanModify()) return;
376  if (m_Tracer) {
377  m_Tracer->OnRequestStop(*this);
378  m_Tracer.reset();
379  }
380  if ((m_HitIDLoggedFlag & fLoggedOnRequest) == 0) {
381  // Hit id has not been set or logged yet. Try to log the default one.
383  }
384  Reset();
385  m_IsRunning = false;
386 }
387 
388 
390 {
391  static bool s_DefaultAutoIncRequestIDOnPostFlag = false;
392  return s_DefaultAutoIncRequestIDOnPostFlag;
393 }
394 
395 
397 {
399 }
400 
401 
403 {
405 }
406 
407 
408 
409 
410 
412 {
413  if (!x_CanModify()) return;
414 
415  const string& hit = hit_id.GetHitId();
417  // Show warning when changing hit id after is has been logged.
418  ERR_POST_X(28, Warning << "Changing hit ID after one has been logged. New hit id is: " << hit);
419  }
421  m_SubHitIDCache.clear();
422  m_HitID = hit_id;
423  x_Modify();
424  m_HitIDLoggedFlag = 0;
425  x_LogHitID();
426 }
427 
428 
429 void CRequestContext::SetHitID(const string& hit)
430 {
431  if (!x_CanModify()) return;
432  x_SetHitID(CSharedHitId(hit));
433 }
434 
435 
436 // Use old output format if the flag is set
437 NCBI_PARAM_DECL(unsigned int, Log, Issued_SubHit_Limit);
438 NCBI_PARAM_DEF_EX(unsigned int, Log, Issued_SubHit_Limit, 200, eParam_NoThread,
439  LOG_ISSUED_SUBHIT_LIMIT);
440 typedef NCBI_PARAM_TYPE(Log, Issued_SubHit_Limit) TIssuedSubHitLimitParam;
441 
442 
443 void CRequestContext::x_UpdateSubHitID(bool increment, CTempString prefix)
444 {
445  _ASSERT(IsSetHitID());
446 
447  // Use global sub-hit counter for default hit id to prevent
448  // duplicate phids in different threads.
449  string hit_id = GetHitID();
450 
451  unsigned int sub_hit_id;
452  if (increment) {
453  sub_hit_id = m_HitID.GetNextSubHitId();
454  x_Modify();
455  }
456  else {
457  sub_hit_id = m_HitID.GetCurrentSubHitId();
458  }
459 
460  // Cache the string so that C code can use it.
461  string subhit = prefix + NStr::NumericToString(sub_hit_id);
462  hit_id += "." + subhit;
463  m_SubHitIDCache = hit_id;
464  if (increment && sub_hit_id <= TIssuedSubHitLimitParam::GetDefault()) {
465  GetDiagContext().Extra().Print("issued_subhit", subhit);
466  }
467 }
468 
469 
470 void CRequestContext::SetSessionID(const string& session)
471 {
472  if (!x_CanModify()) return;
473  if ( !IsValidSessionID(session) ) {
475  switch ( action ) {
476  case eOnBadSID_Ignore:
477  return;
479  ERR_POST_X(26, Warning << "Bad session ID format: " << session);
480  break;
482  ERR_POST_X(26, Warning << "Bad session ID format: " << session);
483  return;
484  case eOnBadSID_Throw:
486  "Bad session ID format: " + session);
487  break;
488  case eOnBadSID_Allow:
489  break;
490  }
491  }
493  m_SessionID.SetString(session);
494  x_Modify();
495 }
496 
497 
498 bool CRequestContext::IsValidSessionID(const string& session_id)
499 {
500  switch ( GetAllowedSessionIDFormat() ) {
501  case eSID_Ncbi:
502  {
503  if (session_id.size() < 24) return false;
504  if (session_id[16] != '_') return false;
505  if ( !NStr::EndsWith(session_id, "SID") ) return false;
506  CTempString uid(session_id, 0, 16);
507  if (NStr::StringToUInt8(uid, NStr::fConvErr_NoThrow, 16) == 0 && errno !=0) {
508  return false;
509  }
510  CTempString rqid(session_id, 17, session_id.size() - 20);
511  if (NStr::StringToUInt(rqid, NStr::fConvErr_NoThrow) == 0 && errno != 0) {
512  return false;
513  }
514  break;
515  }
516  case eSID_Standard:
517  {
518  if ( session_id.empty() ) {
519  return false;
520  }
521  string id_std = kAllowedIdMarkchars;
522  ITERATE (string, c, session_id) {
523  if (!isalnum(*c) && id_std.find(*c) == NPOS) {
524  return false;
525  }
526  }
527  break;
528  }
529  case eSID_Other:
530  return true;
531  }
532  return true;
533 }
534 
535 
538 {
540  {"AllowAndReport", CRequestContext::eOnBadSID_AllowAndReport},
542  {"IgnoreAndReport", CRequestContext::eOnBadSID_IgnoreAndReport},
544 };
548  LOG_ON_BAD_SESSION_ID);
549 typedef NCBI_PARAM_TYPE(Log, On_Bad_Session_Id) TOnBadSessionId;
550 
551 
554 {
555  {"Ncbi", CRequestContext::eSID_Ncbi},
556  {"Standard", CRequestContext::eSID_Standard},
557  {"Other", CRequestContext::eSID_Other}
558 };
562  LOG_SESSION_ID_FORMAT);
563 typedef NCBI_PARAM_TYPE(Log, Session_Id_Format) TSessionIdFormat;
564 
565 
567 {
568  return TOnBadSessionId::GetDefault();
569 }
570 
571 
573 {
574  TOnBadSessionId::SetDefault(action);
575 }
576 
577 
579 {
580  return TSessionIdFormat::GetDefault();
581 }
582 
583 
585 {
586  TSessionIdFormat::SetDefault(fmt);
587 }
588 
589 
591 {
593  ret->m_RequestID = m_RequestID;
594  ret->m_AppState = m_AppState;
595  ret->m_ClientIP = m_ClientIP;
597  m_HitID.SetShared();
598  ret->m_HitID = m_HitID;
601  ret->m_Dtab = m_Dtab;
602  ret->m_ReqStatus = m_ReqStatus;
603  ret->m_ReqTimer = m_ReqTimer;
604  ret->m_BytesRd = m_BytesRd;
605  ret->m_BytesWr = m_BytesWr;
606  ret->m_Properties = m_Properties;
607  ret->m_PropSet = m_PropSet;
608  ret->m_IsRunning = m_IsRunning;
610  ret->m_Flags = m_Flags;
611  ret->m_IsReadOnly = m_IsReadOnly;
612  // NOTE: Do not clone m_Version - the new context gets its own unique version.
613  return ret;
614 }
615 
616 
617 string CRequestContext::SelectLastHitID(const string& hit_ids)
618 {
619  // Empty string or single value - return as-is.
620  if (hit_ids.empty() || hit_ids.find_first_of(", ") == NPOS) {
621  return hit_ids;
622  }
623  list<string> ids;
624  // '+' is a temporary workaround for mismatched encoding/decoding of spaces.
625  NStr::Split(hit_ids, ", +", ids,
627  return ids.empty() ? kEmptyStr : ids.back();
628 }
629 
630 
631 string CRequestContext::SelectLastSessionID(const string& session_ids)
632 {
633  // Empty string or single value - return as-is.
634  if (session_ids.empty() || session_ids.find_first_of(", ") == NPOS) {
635  return session_ids;
636  }
637  list<string> ids;
638  NStr::Split(session_ids, ", ", ids,
640  REVERSE_ITERATE(list<string>, it, ids) {
641  if (*it != "UNK_SESSION") {
642  return *it;
643  }
644  }
645  return kEmptyStr;
646 }
647 
648 
650 {
651  if ( update ) x_UpdateStdPassThroughProp(name);
653  return found != m_PassThroughProperties.end();
654 }
655 
656 
657 const string& CRequestContext::x_GetPassThroughProp(CTempString name, bool update) const
658 {
659  if ( update ) x_UpdateStdPassThroughProp(name);
661  return found != m_PassThroughProperties.end() ? found->second : kEmptyStr;
662 }
663 
664 
667  bool update) const
668 {
669  if (!x_CanModify()) return;
671  if ( update ) x_UpdateStdContextProp(name);
672 }
673 
674 
676 {
677  if (!x_CanModify()) return;
679  if (found != m_PassThroughProperties.end()) {
681  if ( update ) x_UpdateStdContextProp(name);
682  }
683 }
684 
685 
687 {
688  if (name.empty() || NStr::EqualNocase(name, kPassThrough_Sid)) {
689  if ( IsSetSessionID() ) {
691  }
692  else {
694  }
695  }
696  if (name.empty() || NStr::EqualNocase(name, kPassThrough_ClientIp)) {
697  if ( IsSetClientIP() ) {
699  }
700  else {
702  }
703  }
704  if (name.empty() || NStr::EqualNocase(name, kPassThrough_Dtab)) {
705  if ( IsSetDtab() ) {
707  }
708  else {
710  }
711  }
712  if (name.empty() || NStr::EqualNocase(name, kPassThrough_Phid)) {
713  if ( IsSetHitID() ) {
714  string sub_phid = const_cast<CRequestContext&>(*this).GetCurrentSubHitID();
715  if ( sub_phid.empty() ) {
716  sub_phid = const_cast<CRequestContext&>(*this).GetNextSubHitID();
717  }
718  x_SetPassThroughProp(kPassThrough_Phid, sub_phid, false);
719  }
720  else {
722  }
723  }
724 }
725 
726 
728 {
729  CRequestContext& ctx = const_cast<CRequestContext&>(*this);
730 
732  if (name.empty() || match) {
734  ctx.SetSessionID(x_GetPassThroughProp(kPassThrough_Sid, false));
735  }
736  // Reset property only if explicit name is provided
737  else if ( match ) {
738  ctx.UnsetSessionID();
739  }
740  // Explicit name provided - skip other checks.
741  if ( match ) return;
742  }
743 
745  if (name.empty() || match) {
747  ctx.SetHitID(x_GetPassThroughProp(kPassThrough_Phid, false));
748  }
749  // Reset property only if explicit name is provided
750  else if ( match ) {
751  ctx.UnsetHitID();
752  }
753  // Explicit name provided - skip other checks.
754  if ( match ) return;
755  }
756 
758  if (name.empty() || match) {
760  ctx.SetClientIP(x_GetPassThroughProp(kPassThrough_ClientIp, false));
761  }
762  // Reset property only if explicit name is provided
763  else if ( match ) {
764  ctx.UnsetClientIP();
765  }
766  // Explicit name provided - skip other checks.
767  if ( match ) return;
768  }
769 
771  if (name.empty() || match) {
773  ctx.SetDtab(x_GetPassThroughProp(kPassThrough_Dtab, false));
774  }
775  // Reset property only if explicit name is provided
776  else if ( match ) {
777  ctx.UnsetDtab();
778  }
779  // Explicit name provided - skip other checks.
780  if ( match ) return;
781  }
782 }
783 
784 
785 
786 shared_ptr<IRequestTracer> CRequestContext::sm_Tracer;
787 
788 void CRequestContext::SetRequestTracer(const shared_ptr<IRequestTracer>& tracer)
789 {
790  sm_Tracer = tracer;
791 }
792 
793 
794 NCBI_PARAM_DECL(string, Context, Fields);
795 NCBI_PARAM_DEF_EX(string, Context, Fields, "",
797  NCBI_CONTEXT_FIELDS);
798 typedef NCBI_PARAM_TYPE(Context, Fields) TNcbiContextFields;
799 
800 DEFINE_STATIC_MUTEX(s_ContextFieldsMutex);
801 unique_ptr<CMaskFileName> CRequestContext::sm_ContextFields;
802 unique_ptr<CRequestContext::TPassThroughProperties> CRequestContext::sm_EnvContextProperties;
803 
804 
806 {
807  if ( !sm_ContextFields.get() ) {
808  CMutexGuard guard(s_ContextFieldsMutex);
809  if ( !sm_ContextFields.get() ) {
810  sm_ContextFields.reset(new CMaskFileName());
811  string fields_var = TNcbiContextFields::GetDefault();
812  if ( !fields_var.empty() ) {
813  list<string> fields;
814  NStr::Split(fields_var, " ", fields, NStr::fSplit_MergeDelimiters);
815  ITERATE(list<string>, field, fields) {
816  string norm_field = sx_NormalizeContextPropertyName(*field);
817  sm_ContextFields->Add(norm_field);
818  }
819  }
820  else {
821  // By default exclude everything.
822  sm_ContextFields->AddExclusion("*");
823  }
824  }
825  }
826  return *sm_ContextFields;
827 }
828 
829 
831 {
832  return NStr::Replace(name, "_", "-");
833 }
834 
835 
837 {
838  if (!x_CanModify()) return;
839  // Parse environment only once.
840  if ( !sm_EnvContextProperties.get() ) {
842  {
844  if ( !app ) return;
845  const CNcbiEnvironment& env = app->GetEnvironment();
846  list<string> names;
847  env.Enumerate(names);
848  ITERATE(list<string>, it, names) {
849  props[*it] = env.Get(*it);
850  }
851  }
852 
853  CMutexGuard guard(s_ContextFieldsMutex);
854  if ( !sm_EnvContextProperties.get() ) {
857  ITERATE(TPassThroughProperties, it, props) {
858  string norm_prop = sx_NormalizeContextPropertyName(it->first);
859  if ( mask.Match(norm_prop, NStr::eNocase) ) {
860  (*sm_EnvContextProperties)[norm_prop] = it->second;
861  }
862  }
863  }
864  }
866 }
867 
868 
869 void CRequestContext::AddPassThroughProperty(const string& name, const string& value)
870 {
871  if (!x_CanModify()) return;
873  string norm_prop = sx_NormalizeContextPropertyName(name);
874  if ( mask.Match(norm_prop, NStr::eNocase) ) {
875  m_PassThroughProperties[norm_prop] = value;
876  }
877 }
878 
879 
881 {
883 
884  switch (format) {
885  case eFormat_UrlEncoded:
886  return x_SerializeUrlEncoded();
887  }
888  return kEmptyStr;
889 }
890 
891 
893 {
894  switch (format) {
895  case eFormat_UrlEncoded:
897  break;
898  }
899 
901 }
902 
903 
905 {
908 }
909 
910 
912 {
915  "&", "=", new CStringDecoder_Url());
916 }
917 
918 
920 {
921  switch (GetErrCode()) {
922  case eBadSession: return "eBadSession";
923  case eBadHit: return "eBadHit";
924  default: return CException::GetErrCodeString();
925  }
926 }
927 
928 
930  : m_Flags(flags)
931 {
932  m_OriginatesFromThrow = uncaught_exceptions();
934  if ( context ) {
935  m_SavedContext.Reset(&ctx.GetRequestContext());
937  ctx.SetRequestContext(context);
938  }
939  else {
940  m_RequestContext.Reset(&ctx.GetRequestContext());
941  }
942 
943  if (m_Flags & fPrintRequestStart) {
944  // This also updates app state to RB/R
945  ctx.PrintRequestStart();
946  }
947 }
948 
949 
951 {
952  // If released, do not perform any actions.
953  if ( !m_RequestContext ) return;
954 
955  if ( uncaught_exceptions() && !m_OriginatesFromThrow ) {
957  }
958  else if ( !m_RequestContext->IsSetRequestStatus() ) {
960  }
961 
963  // This also updates app state to RE/P
964  ctx.PrintRequestStop();
965 
966  if ( m_SavedContext ) {
967  ctx.SetRequestContext(m_SavedContext.GetNonNullPointer());
968  }
969 }
970 
971 
973 {
974  if ( m_SavedContext ) {
977  }
979 }
980 
981 
983 {
984  // If the guard has been released throw null pointer exception.
986  m_ErrorStatus = status;
987 }
988 
989 
ncbi::TMaskedQueryRegions mask
CAtomicCounter –.
Definition: ncbicntr.hpp:71
CMaskFileName –.
Definition: ncbi_mask.hpp:107
CMask –.
Definition: ncbi_mask.hpp:59
CNcbiEnvironment –.
Definition: ncbienv.hpp:110
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:1937
URL-decoder for string pairs parser.
Definition: ncbistr.hpp:4559
URL-encoder for string pairs parser.
Definition: ncbistr.hpp:4572
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
static uch flags
static const char ip[]
Definition: des.c:75
CS_CONTEXT * ctx
Definition: t0006.c:12
static const struct name_t names[]
#define false
Definition: bool.h:36
static HENV env
Definition: transaction2.c:38
char data[12]
Definition: iconv.c:80
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
static void SetRequestTracer(const shared_ptr< IRequestTracer > &tracer)
Set request tracer to be called on context events (start/stop etc.).
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 shared_ptr< IRequestTracer > sm_Tracer
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:3944
void Parse(const CTempString str, NStr::EMergeDelims merge_argsep=NStr::eMergeDelims)
Parse the string.
Definition: ncbistr.hpp:4692
static CTempString TruncateSpaces_Unsafe(const CTempString str, ETrunc where=eTrunc_Both)
Truncate whitespace in a string.
Definition: ncbistr.cpp:3182
string Merge(void) const
Merge name-value pairs into a single string using the currently set separators and the provided encod...
Definition: ncbistr.hpp:4747
#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:3452
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:5424
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:4830
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:3305
static Uint8 StringToUInt8(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to Uint8.
Definition: ncbistr.cpp:871
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:2878
static bool IsIPAddress(const CTempStringEx str)
Check if the string contains a valid IP address.
Definition: ncbistr.cpp:6387
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5347
void SetString(const CTempString s, NStr::EUrlEncode flag=NStr::eUrlEnc_SkipMarkChars)
Set new original string.
Definition: ncbistr.cpp:7298
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
@ eNcbiStrings_PHID
Definition: ncbi_strings.h:56
@ fSS_NoMerge
Do not merge adjacent spaces (rejected chars)
Definition: ncbistr.hpp:2850
@ fSS_alnum
Check on isalnum()
Definition: ncbistr.hpp:2839
@ fConvErr_NoThrow
Do not throw an exception on error.
Definition: ncbistr.hpp:285
@ fSplit_Truncate
Definition: ncbistr.hpp:2503
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2500
@ eUrlEnc_Cookie
Same as SkipMarkChars with encoded ','.
Definition: ncbistr.hpp:3155
@ 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:2816
void Reset(void)
Stop (if running) and reset the timer.
Definition: ncbitime.hpp:2807
Definition of all error codes used in corelib (xncbi.lib).
int len
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
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(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2_SIZE frame_size, pcre2_match_data *match_data, match_block *mb)
Definition: pcre2_match.c:594
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 CS_CONTEXT * context
Definition: will_convert.c:21
Modified on Fri Sep 20 14:58:04 2024 by modify_doxy.py rev. 669887