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

Go to the SVN repository for this file.

1 /* $Id: ncbicgi.cpp 103060 2024-09-03 13:27:47Z lavr $
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: Denis Vakatov
27  *
28  * File Description:
29  * NCBI C++ CGI API:
30  * CCgiCookie -- one CGI cookie
31  * CCgiCookies -- set of CGI cookies
32  * CCgiRequest -- full CGI request
33  */
34 
35 #include <ncbi_pch.hpp>
36 #include <corelib/ncbienv.hpp>
37 #include <corelib/ncbitime.hpp>
38 #include <corelib/ncbi_param.hpp>
39 #include <corelib/ncbiapp.hpp>
41 #include <corelib/request_ctx.hpp>
42 #include <corelib/ncbi_strings.h>
43 
44 #include <cgi/cgi_exception.hpp>
45 #include <cgi/cgi_serial.hpp>
46 #include <cgi/cgi_session.hpp>
47 #include <cgi/error_codes.hpp>
49 #include <util/checksum.hpp>
50 #include <util/ncbi_url.hpp>
51 
52 #include "cgi_impl.hpp"
53 
54 #include <algorithm>
55 
56 #include <stdio.h>
57 #include <time.h>
58 #ifdef HAVE_UNISTD_H
59 # include <unistd.h>
60 #else
61 # define STDIN_FILENO 0
62 #endif
63 
64 
65 #define NCBI_USE_ERRCODE_X Cgi_API
66 
67 
69 
70 
71 ///////////////////////////////////////////////////////
72 // CCgiCookie::
73 //
74 
75 
76 // Severity level for cookie errors.
77 NCBI_PARAM_ENUM_DECL(EDiagSev, CGI, Cookie_Error_Severity);
78 NCBI_PARAM_ENUM_ARRAY(EDiagSev, CGI, Cookie_Error_Severity)
79 {
80  {"Info", eDiag_Info},
81  {"Warning", eDiag_Warning},
82  {"Error", eDiag_Error},
83  {"Critical", eDiag_Critical},
84  {"Fatal", eDiag_Fatal},
85  {"Trace", eDiag_Trace}
86 };
87 NCBI_PARAM_ENUM_DEF_EX(EDiagSev, CGI, Cookie_Error_Severity,
89  eParam_NoThread, CGI_COOKIE_ERROR_SEVERITY);
90 typedef NCBI_PARAM_TYPE(CGI, Cookie_Error_Severity) TCookieErrorSeverity;
91 
92 
95 {
98 };
101  eParam_NoThread, CGI_COOKIE_ENCODING);
102 typedef NCBI_PARAM_TYPE(CGI, Cookie_Encoding) TCookieEncoding;
103 
104 
105 NCBI_PARAM_DECL(string, CGI, cookie_auth_token);
106 NCBI_PARAM_DEF(string, CGI, cookie_auth_token, "WebCubbyUser");
107 typedef NCBI_PARAM_TYPE(CGI, cookie_auth_token) TCookieAuthToken;
108 
109 
110 // Helper function for encoding cookie name/value
111 string CCgiCookie::x_EncodeCookie(const string& str,
112  EFieldType ftype,
113  NStr::EUrlEncode flag)
114 {
115  if (flag == NStr::eUrlEnc_SkipMarkChars) {
116  // Force encoding of comma.
117  flag = NStr::eUrlEnc_Cookie;
118  }
119  if (NStr::NeedsURLEncoding(str, flag)) {
120  switch (TCookieEncoding::GetDefault()) {
121  case eCookieEnc_Url:
122  return NStr::URLEncode(str, flag);
123  case eCookieEnc_Quote:
124  // don't encode names
125  if (ftype == eField_Name) {
126  return str;
127  }
128  // escape quotes, quote the value
129  string esc = NStr::Replace(str, "\"", "\\\"");
130  return "\"" + esc + "\"";
131  }
132  }
133  return str;
134 }
135 
136 
137 // auxiliary zero "tm" struct
138 static const tm kZeroTime = { 0 };
139 
140 inline bool s_IsZeroTime(const tm& date)
141 {
142  return ::memcmp(&date, &kZeroTime, sizeof(tm)) == 0 ? true : false;
143 }
144 
145 
147  : m_Name(cookie.m_Name),
148  m_Value(cookie.m_Value),
149  m_Domain(cookie.m_Domain),
150  m_Path(cookie.m_Path),
151  m_InvalidFlag(cookie.m_InvalidFlag)
152 {
153  m_Expires = cookie.m_Expires;
154  m_Secure = cookie.m_Secure;
155  m_HttpOnly = cookie.m_HttpOnly;
156 }
157 
158 
159 CCgiCookie::CCgiCookie(const string& name, const string& value,
160  const string& domain, const string& path)
161  : m_InvalidFlag(fValid)
162 {
163  if ( name.empty() ) {
164  NCBI_THROW2(CCgiCookieException, eValue, "Empty cookie name", 0);
165  }
166  m_Name = name;
167 
168  SetDomain(domain);
169  SetPath(path);
170  SetValue(value);
172  m_Secure = false;
173  m_HttpOnly = false;
174 }
175 
176 
178 {
179  m_Value.erase();
180  m_Domain.erase();
181  m_Path.erase();
183  m_Secure = false;
184  m_HttpOnly = false;
186 }
187 
188 
190 {
191  if (&cookie == this)
192  return;
193 
194  m_Value = cookie.m_Value;
196  SetInvalid(cookie.IsInvalid() & fInvalid_Value);
197 
198  m_Domain = cookie.m_Domain;
199  m_Path = cookie.m_Path;
200  m_Expires = cookie.m_Expires;
201  m_Secure = cookie.m_Secure;
202  m_HttpOnly = cookie.m_HttpOnly;
203 }
204 
205 
206 string CCgiCookie::GetExpDate(void) const
207 {
208  if ( s_IsZeroTime(m_Expires) )
209  return kEmptyStr;
210 
211  char str[30];
212  if ( !::strftime(str, sizeof(str),
213  "%a, %d %b %Y %H:%M:%S GMT", &m_Expires) ) {
215  "CCgiCookie::GetExpDate() -- strftime() failed");
216  }
217  return string(str);
218 }
219 
220 
221 bool CCgiCookie::GetExpDate(tm* exp_date) const
222 {
223  if ( !exp_date )
224  NCBI_THROW(CCgiException, eUnknown, "Null cookie exp.date passed");
225  if ( s_IsZeroTime(m_Expires) )
226  return false;
227  *exp_date = m_Expires;
228  return true;
229 }
230 
231 
233  EWriteMethod wmethod,
234  EUrlEncode flag) const
235 {
236  // Check if name and value are valid
237  if ((m_InvalidFlag & fInvalid_Name) != 0) {
239  "Banned symbol in the cookie's name: "
241  }
242  if ((m_InvalidFlag & fInvalid_Value) != 0) {
244  "Banned symbol in the cookie's value (name: " + m_Name + "): "
246  }
247  if (wmethod == eHTTPResponse) {
248  os << "Set-Cookie: ";
250  NStr::EUrlEncode(flag)).c_str() << '=';
251  if ( !m_Value.empty() ) {
253  NStr::EUrlEncode(flag)).c_str();
254  }
255 
256  if ( !m_Domain.empty() )
257  os << "; domain=" << m_Domain.c_str();
258  if ( !m_Path.empty() )
259  os << "; path=" << m_Path.c_str();
260  string x_ExpDate = GetExpDate();
261  if ( !x_ExpDate.empty() )
262  os << "; expires=" << x_ExpDate.c_str();
263  if ( m_Secure )
264  os << "; secure";
265  if ( m_HttpOnly )
266  os << "; HttpOnly";
267 
268  os << HTTP_EOL;
269 
270  } else {
272  NStr::EUrlEncode(flag)).c_str() << '=';
273  if ( !m_Value.empty() ) {
275  NStr::EUrlEncode(flag)).c_str();
276  }
277  }
278  return os;
279 }
280 
281 
282 // Check if the cookie field is valid
283 void CCgiCookie::x_CheckField(const string& str,
284  EFieldType ftype,
285  const char* banned_symbols,
286  const string* cookie_name)
287 {
288  if ( banned_symbols ) {
289  string::size_type pos = str.find_first_of(banned_symbols);
290  if (pos != NPOS) {
291  string msg = "Banned symbol '" +
292  NStr::PrintableString(string(1, str[pos]))
293  + "' in the cookie";
294  switch ( ftype ) {
295  case eField_Name:
296  msg += " name";
297  break;
298  case eField_Value:
299  msg += " value";
300  break;
301  default:
302  break;
303  }
304  if ( cookie_name ) {
305  msg += " (name: '" + *cookie_name + "')";
306  }
307  msg += ": " + NStr::PrintableString(str);
308  NCBI_THROW2(CCgiCookieException, eValue, msg, pos);
309  }
310  }
311  // Don't check unprintable symbols in value
312  if (ftype == eField_Value) return;
313 
314  for (const char* s = str.c_str(); *s; s++) {
315  if ( !isprint((unsigned char)(*s)) ) {
316  string msg = "Banned symbol '" +
317  NStr::PrintableString(string(1, *s))
318  + "' in the cookie";
319  if (ftype == eField_Name) {
320  msg += " name";
321  }
322  if ( cookie_name ) {
323  msg += " (name: '" + *cookie_name + "')";
324  }
325  msg += ": " + NStr::PrintableString(str);
326  NCBI_THROW2(CCgiCookieException, eValue, msg, s - str.c_str());
327  }
328  }
329 }
330 
331 
332 static bool s_CookieLess
333  (const string& name1, const string& domain1, const string& path1,
334  const string& name2, const string& domain2, const string& path2)
335 {
336  PNocase nocase_less;
337  bool x_less;
338 
339  x_less = nocase_less(name1, name2);
340  if (x_less || nocase_less(name2, name1))
341  return x_less;
342 
343  x_less = nocase_less(domain1, domain2);
344  if (x_less || nocase_less(domain2, domain1))
345  return x_less;
346 
347  if ( path1.empty() )
348  return !path2.empty();
349  if ( path2.empty() )
350  return false;
351  return (path1.compare(path2) > 0);
352 }
353 
354 
356  const
357 {
359  cookie.m_Name, cookie.m_Domain, cookie.m_Path);
360 }
361 
362 
363 void CCgiCookie::SetExpTime(const CTime& exp_time)
364 {
365  _ASSERT(exp_time.IsGmtTime());
366 
367  m_Expires.tm_sec = exp_time.Second();
368  m_Expires.tm_min = exp_time.Minute();
369  m_Expires.tm_hour = exp_time.Hour();
370  m_Expires.tm_mday = exp_time.Day();
371  m_Expires.tm_mon = exp_time.Month()-1;
372  m_Expires.tm_wday = exp_time.DayOfWeek();
373  m_Expires.tm_year = exp_time.Year()-1900;
374  m_Expires.tm_isdst = -1;
375 }
376 
377 
378 
379 ///////////////////////////////////////////////////////
380 // CCgiCookies::
381 //
382 
383 CCgiCookie* CCgiCookies::Add(const string& name, const string& value,
384  const string& domain , const string& path,
385  EOnBadCookie on_bad_cookie)
386 {
387  CCgiCookie* ck = Find(name, domain, path);
388  try {
389  if ( ck ) { // override existing CCgiCookie
390  ck->SetValue(value);
391  }
392  else { // create new CCgiCookie and add it
393  ck = new CCgiCookie(name, value);
394  ck->SetDomain(domain);
395  ck->SetPath(path);
396  _VERIFY( m_Cookies.insert(ck).second );
397  }
398  } catch (const CCgiCookieException& ex) {
399  // This can only happen if cookie has empty name, ignore
400  // Store/StoreAndError flags in this case.
401  switch ( on_bad_cookie ) {
403  throw;
406  const CException& cex = ex; // GCC 3.4.0 can't guess it for ERR_POST
407  ERR_POST_X(1, Severity(TCookieErrorSeverity::GetDefault()) << cex);
408  return NULL;
409  }
410  case eOnBadCookie_Store:
411  case eOnBadCookie_Skip:
412  return NULL;
413  default:
414  _TROUBLE;
415  }
416  }
417  return ck;
418 }
419 
420 
421 CCgiCookie* CCgiCookies::Add(const string& name,
422  const string& value,
423  EOnBadCookie on_bad_cookie)
424 {
425  return Add(name, value, kEmptyStr, kEmptyStr, on_bad_cookie);
426 }
427 
428 
430 {
431  CCgiCookie* ck = Find
432  (cookie.GetName(), cookie.GetDomain(), cookie.GetPath());
433  if ( ck ) { // override existing CCgiCookie
434  ck->CopyAttributes(cookie);
435  } else { // create new CCgiCookie and add it
436  ck = new CCgiCookie(cookie);
437  _VERIFY( m_Cookies.insert(ck).second );
438  }
439  return ck;
440 }
441 
442 
443 void CCgiCookies::Add(const CCgiCookies& cookies)
444 {
445  ITERATE (TSet, cookie, cookies.m_Cookies) {
446  Add(**cookie);
447  }
448 }
449 
450 
451 // Check if the cookie name or value is valid
455  const char* banned_symbols,
456  EOnBadCookie on_bad_cookie,
457  const string* cookie_name)
458 {
459  try {
460  CCgiCookie::x_CheckField(str, ftype, banned_symbols, cookie_name);
461  } catch (const CCgiCookieException& ex) {
462  switch ( on_bad_cookie ) {
464  throw;
466  const CException& cex = ex; // GCC 3.4.0 can't guess it for ERR_POST
467  ERR_POST_X(2, Severity(TCookieErrorSeverity::GetDefault()) << cex);
468  return eCheck_SkipInvalid;
469  }
470  case eOnBadCookie_Skip:
471  return eCheck_SkipInvalid;
473  const CException& cex = ex; // GCC 3.4.0 can't guess it for ERR_POST
474  ERR_POST_X(3, Severity(TCookieErrorSeverity::GetDefault()) << cex);
475  return eCheck_StoreInvalid;
476  }
477  case eOnBadCookie_Store:
478  return eCheck_StoreInvalid;
479  default:
480  _TROUBLE;
481  }
482  }
483  return eCheck_Valid;
484 }
485 
486 
487 NCBI_PARAM_DECL(string, CGI, Cookie_Name_Banned_Symbols);
488 NCBI_PARAM_DEF_EX(string, CGI, Cookie_Name_Banned_Symbols, " ,;=",
489  eParam_NoThread, CGI_COOKIE_NAME_BANNED_SYMBOLS);
490 typedef NCBI_PARAM_TYPE(CGI, Cookie_Name_Banned_Symbols) TCookieNameBannedSymbols;
491 
493 {
494  static CSafeStatic<string> s_BannedSymbols;
495  static bool s_BannedSymbolsSet = false;
496  if ( !s_BannedSymbolsSet ) {
497  *s_BannedSymbols = TCookieNameBannedSymbols::GetDefault();
498  s_BannedSymbolsSet = true;
499  }
500  return s_BannedSymbols.Get().c_str();
501 }
502 
503 
504 void CCgiCookies::Add(const string& str, EOnBadCookie on_bad_cookie)
505 {
508  const char* banned_symbols = s_GetCookieNameBannedSymbols();
509 
510  SIZE_TYPE pos = str.find_first_not_of(" \t\n");
511  for (;;) {
512  bool need_decode = true;
513  SIZE_TYPE pos_beg = str.find_first_not_of(' ', pos);
514  if (pos_beg == NPOS)
515  return; // done
516 
517  SIZE_TYPE pos_mid = str.find_first_of("=;,\r\n", pos_beg);
518  if (pos_mid == NPOS) {
519  string name = str.substr(pos_beg);
520  switch ( x_CheckField(name, CCgiCookie::eField_Name,
521  banned_symbols, on_bad_cookie) ) {
522  case eCheck_Valid:
523  Add(NStr::URLDecode(name, dec_flag), kEmptyStr, on_bad_cookie);
524  break;
525  case eCheck_StoreInvalid:
526  {
527  CCgiCookie* cookie = Add(name, kEmptyStr, on_bad_cookie);
528  if ( cookie ) {
530  }
531  break;
532  }
533  default:
534  break;
535  }
536  return; // done
537  }
538  if (str[pos_mid] != '=') {
539  string name = str.substr(pos_beg, pos_mid - pos_beg);
540  switch ( x_CheckField(name, CCgiCookie::eField_Name,
541  banned_symbols, on_bad_cookie) ) {
542  case eCheck_Valid:
543  Add(NStr::URLDecode(name, dec_flag), kEmptyStr, on_bad_cookie);
544  break;
545  case eCheck_StoreInvalid:
546  {
547  CCgiCookie* cookie = Add(name, kEmptyStr, on_bad_cookie);
548  if ( cookie ) {
550  }
551  break;
552  }
553  default:
554  break;
555  }
556  if ((str[pos_mid] != ';' && str[pos_mid] != ',') ||
557  ++pos_mid == str.length())
558  return; // done
559  pos = pos_mid;
560  continue;
561  }
562  string name = str.substr(pos_beg, pos_mid - pos_beg);
563  bool quoted_value = false;
564  SIZE_TYPE pos_end = str.find_first_of(";,", pos_mid);
565  // Check for quoted value
566  if (pos_mid + 1 < str.length() && str[pos_mid + 1] == '"') {
567  quoted_value = true;
568  // Find the closing quote
569  SIZE_TYPE pos_q = str.find('"', pos_mid + 2);
570  // Skip any escaped quotes
571  while (pos_q != NPOS && str[pos_q - 1] == '\\') {
572  pos_q = str.find('"', pos_q + 1);
573  }
574  bool valid_quotes = (pos_q != NPOS);
575  string msg;
576  if (valid_quotes) {
577  pos_end = str.find_first_of(";,", pos_q + 1);
578  size_t val_end = pos_end;
579  if (val_end == NPOS) {
580  val_end = str.size();
581  }
582  if (val_end > pos_q + 1) {
583  // Make sure there are only spaces between the closing quote
584  // and the semicolon.
585  string extra = str.substr(pos_q + 1, val_end - pos_q - 1);
586  if (extra.find_first_not_of(" \t\n") != NPOS) {
587  valid_quotes = false;
588  msg = "Unescaped quote in cookie value (name: " +
589  name + "): " +
590  NStr::PrintableString(str.substr(pos_mid + 1));
591  }
592  }
593  }
594  else {
595  msg = "Missing closing quote in cookie value (name: " +
596  name + "): " +
597  NStr::PrintableString(str.substr(pos_mid + 1));
598  }
599  if ( valid_quotes ) {
600  need_decode = false;
601  }
602  else {
603  quoted_value = false;
604  // Error - missing closing quote
605  switch ( on_bad_cookie ) {
607  NCBI_THROW2(CCgiCookieException, eValue, msg, pos_mid + 1);
609  ERR_POST_X(9, Severity(TCookieErrorSeverity::GetDefault()) <<
610  msg);
611  // Do not break, proceed to the next case
612  case eOnBadCookie_Skip:
613  return;
615  ERR_POST_X(10, Severity(TCookieErrorSeverity::GetDefault()) <<
616  msg);
617  // Do not break, proceed to the next case
618  case eOnBadCookie_Store:
619  pos_end = NPOS; // Use the whole string
620  break;
621  default:
622  _TROUBLE;
623  }
624  }
625  }
626  if (pos_end != NPOS) {
627  pos = pos_end + 1;
628  pos_end--;
629  } else {
630  pos_end = str.find_last_not_of(" \t\n", str.length());
631  _ASSERT(pos_end != NPOS);
632  pos = NPOS; // about to finish
633  }
635  string val = str.substr(pos_mid + 1, pos_end - pos_mid);
636  if (quoted_value) {
638  _ASSERT(val[0] == '"');
639  _ASSERT(val[val.size() - 1] == '"');
640  val = NStr::Replace(val.substr(1, val.size() - 2), "\\\"", "\"");
641  }
643  banned_symbols, on_bad_cookie);
644  ECheckResult valid_value = quoted_value ? eCheck_Valid :
646  on_bad_cookie, &name);
647  if ( valid_name == eCheck_Valid && valid_value == eCheck_Valid ) {
648  Add(NStr::URLDecode(name, dec_flag),
649  need_decode ? NStr::URLDecode(val, dec_flag) : val,
650  on_bad_cookie);
651  }
652  else if ( valid_name != eCheck_SkipInvalid &&
653  valid_value != eCheck_SkipInvalid ) {
654  // Do not URL-decode bad cookies
655  CCgiCookie* cookie = Add(name, val, on_bad_cookie);
656  if ( cookie ) {
657  if (valid_name == eCheck_StoreInvalid) {
659  }
660  if (valid_value == eCheck_StoreInvalid) {
662  }
663  }
664  }
665  }
666  // ...never reaches here...
667 }
668 
669 
671  CCgiCookie::EWriteMethod wmethod) const
672 {
673  ITERATE (TSet, cookie, m_Cookies) {
674  if (wmethod == CCgiCookie::eHTTPResponse) {
675  // Don't send secure cookies over non-secure connections.
676  if (!m_Secure && (*cookie)->GetSecure()) {
677  continue;
678  }
679  }
680  if (wmethod == CCgiCookie::eHTTPRequest && cookie != m_Cookies.begin())
681  os << "; ";
682  (*cookie)->Write(os, wmethod, EUrlEncode(m_EncodeFlag));
683  // os << **cookie;
684  }
685  return os;
686 }
687 
688 
690 (const string& name, const string& domain, const string& path)
691 {
692  TCIter iter = m_Cookies.begin();
693  while (iter != m_Cookies.end() &&
694  s_CookieLess((*iter)->GetName(), (*iter)->GetDomain(),
695  (*iter)->GetPath(), name, domain, path)) {
696  iter++;
697  }
698 
699  // find exact match
700  if (iter != m_Cookies.end() &&
701  !s_CookieLess(name, domain, path, (*iter)->GetName(),
702  (*iter)->GetDomain(), (*iter)->GetPath())) {
703  _ASSERT( AStrEquiv(name, (*iter)->GetName(), PNocase()) );
704  _ASSERT( AStrEquiv(domain, (*iter)->GetDomain(), PNocase()) );
705  _ASSERT( path.compare((*iter)->GetPath()) == 0 );
706  return *iter;
707  }
708  return 0;
709 }
710 
711 
713 (const string& name, const string& domain, const string& path)
714  const
715 {
716  return const_cast<CCgiCookies*>(this)->Find(name, domain, path);
717 }
718 
719 
720 CCgiCookie* CCgiCookies::Find(const string& name, TRange* range)
721 {
722  PNocase nocase_less;
723 
724  // find the first match
725  TIter beg = m_Cookies.begin();
726  while (beg != m_Cookies.end() && nocase_less((*beg)->GetName(), name))
727  beg++;
728 
729  // get this first match only
730  if ( !range ) {
731  return (beg != m_Cookies.end() &&
732  !nocase_less(name, (*beg)->GetName())) ? *beg : 0;
733  }
734 
735  // get the range of equal names
736  TIter end = beg;
737  while (end != m_Cookies.end() &&
738  !nocase_less(name, (*end)->GetName()))
739  end++;
740  range->first = beg;
741  range->second = end;
742  return (beg == end) ? 0 : *beg;
743 }
744 
745 
746 const CCgiCookie* CCgiCookies::Find(const string& name, TCRange* range)
747  const
748 {
749  CCgiCookies& nonconst_This = const_cast<CCgiCookies&> (*this);
750  if ( range ) {
751  TRange x_range;
752  const CCgiCookie* ck = nonconst_This.Find(name, &x_range);
753  range->first = x_range.first;
754  range->second = x_range.second;
755  return ck;
756  } else {
757  return nonconst_This.Find(name, 0);
758  }
759 }
760 
761 
762 
764  const
765 {
766  return TCRange(m_Cookies.begin(), m_Cookies.end());
767 }
768 
769 
771 {
772  if (!cookie || m_Cookies.erase(cookie) == 0)
773  return false;
774  if ( destroy )
775  delete cookie;
776  return true;
777 }
778 
779 
781 {
782  size_t count = 0;
783  for (TIter iter = range.first; iter != range.second; iter++, count++) {
784  if ( destroy )
785  delete *iter;
786  }
787  m_Cookies.erase(range.first, range.second);
788  return count;
789 }
790 
791 
793 {
794  ITERATE (TSet, cookie, m_Cookies) {
795  delete *cookie;
796  }
797  m_Cookies.clear();
798 }
799 
800 
802 {
803  m_AllSecure = value;
804  NON_CONST_ITERATE (TSet, cookie, m_Cookies) {
805  (*cookie)->SetSecure(value);
806  }
807 }
808 
809 
811 {
813  NON_CONST_ITERATE (TSet, cookie, m_Cookies) {
814  (*cookie)->SetHttpOnly(value);
815  }
816 }
817 
818 
819 ////////////////////////////////////////////////////////
820 // CTrackingEnvHolder
821 //
822 
824 {
825 public:
828 
829  const char* const* GetTrackingEnv(void) const { return m_TrackingEnv; }
830 
831 private:
832  void x_Destroy(void);
835 };
836 
837 
838 // Must be in correspondence with variables checked in NcbiGetCgiClientIP[Ex]()
839 // (header: <connect/ext/ncbi_localnet.h>, source: connect/ext/ncbi_localnet.c,
840 // library: [x]connext)
841 static const char* kTrackingVars[] =
842 {
843  "HTTP_CAF_PROXIED_HOST",
844  "HTTP_X_FORWARDED_FOR",
845  "PROXIED_IP",
846  "HTTP_X_FWD_IP_ADDR",
847  "HTTP_CLIENT_HOST",
848  "HTTP_X_REAL_IP",
849  "REMOTE_HOST",
850  "REMOTE_ADDR",
851  "NI_CLIENT_IPADDR",
852  NULL
853 };
854 
855 
857  : m_Env(env), m_TrackingEnv(NULL)
858 {
859  if (!m_Env)
860  return;
861 
862  try {
863  size_t size = sizeof(kTrackingVars) / sizeof(kTrackingVars[0]);
864  m_TrackingEnv = new char*[size];
865  memset(m_TrackingEnv, 0, sizeof(m_TrackingEnv[0]) * size);
866 
867  int i = 0;
868  for (const char* const* name = kTrackingVars; *name; ++name) {
869  const string& value = m_Env->Get(*name);
870  if (value.empty())
871  continue;
872 
873  string str(*name);
874  str += '=';
875  str += value;
876  size = str.length() + 1;
877  m_TrackingEnv[i] = new char[size];
878  memcpy(m_TrackingEnv[i++], str.c_str(), size);
879  }
880  }
881  catch (...) {
882  x_Destroy();
883  throw;
884  }
885 }
886 
887 
889 {
890  char** env;
891  if (!(env = m_TrackingEnv))
892  return;
893  m_TrackingEnv = 0;
894 
895  for (char** ptr = env; *ptr; ++ptr) {
896  char* del = *ptr;
897  *ptr = 0;
898  delete[] del;
899  }
900  delete[] env;
901 }
902 
903 
905 {
906  x_Destroy();
907 }
908 
909 
910 
911 ////////////////////////////////////////////////////////
912 // CCgiRequest
913 //
914 
915 // Standard property names
916 static const char* s_PropName[eCgi_NProperties + 1] = {
917  "SERVER_SOFTWARE",
918  "SERVER_NAME",
919  "GATEWAY_INTERFACE",
920  "SERVER_PROTOCOL",
921  "SERVER_PORT",
922 
923  "REMOTE_HOST",
924  "REMOTE_ADDR",
925 
926  "CONTENT_TYPE",
927  "CONTENT_LENGTH",
928 
929  "REQUEST_METHOD",
930  "PATH_INFO",
931  "PATH_TRANSLATED",
932  "SCRIPT_NAME",
933  "QUERY_STRING",
934 
935  "AUTH_TYPE",
936  "REMOTE_USER",
937  "REMOTE_IDENT",
938 
939  "HTTP_ACCEPT",
940  "HTTP_COOKIE",
941  "HTTP_IF_MODIFIED_SINCE",
942  "HTTP_REFERER",
943  "HTTP_USER_AGENT",
944 
945  "" // eCgi_NProperties
946 };
947 
948 
950 {
951  if ((unsigned int) eCgi_NProperties <= (unsigned int) prop) {
952  _TROUBLE;
954  "CCgiRequest::GetPropertyName(BadPropIdx)");
955  }
956  return s_PropName[prop];
957 }
958 
959 
960 // Add another entry to the container of entries
961 static void s_AddEntry(TCgiEntries& entries, const string& name,
962  const string& value, unsigned int position,
963  const string& filename = kEmptyStr,
964  const string& type = kEmptyStr)
965 {
967  (name, CCgiEntry(value, filename, position, type)));
968 }
969 
970 
972  TCgiIndexes* indexes,
974  : CUrlArgs_Parser(CCgiRequestTFlagsToTFlags(flags & ~(indexes ? 0 : CCgiRequest::fIndexesNotEntries))),
975  m_Entries(entries),
976  m_Indexes(indexes)
977 {
978  return;
979 }
980 
981 
982 void CCgiEntries_Parser::AddArgument(unsigned int position,
983  const string& name,
984  const string& value,
985  EArgType arg_type)
986 {
987  if (m_Entries &&
990  name, CCgiEntry(value, kEmptyStr, position, kEmptyStr)));
991  }
992  else {
994  m_Indexes->push_back(name);
995  }
996 }
997 
998 
1000 {
1001  SetInputStream(0);
1002 }
1003 
1004 
1006 (const CNcbiArguments* args,
1007  const CNcbiEnvironment* env,
1008  CNcbiIstream* istr,
1009  TFlags flags,
1010  int ifd,
1011  size_t errbuf_size)
1012  : m_Env(0),
1013  m_Entries(PNocase_Conditional((flags & fCaseInsensitiveArgs) ?
1014  NStr::eNocase : NStr::eCase)),
1015  m_Input(0),
1016  m_InputFD(0),
1017  m_OwnInput(false),
1018  m_ErrBufSize(errbuf_size),
1019  m_QueryStringParsed(false),
1020  m_Session(NULL),
1021  m_EntryReaderContext(NULL)
1022 {
1023  x_Init(args, env, istr, flags, ifd);
1024 }
1025 
1026 
1028 (int argc,
1029  const char* const* argv,
1030  const char* const* envp,
1031  CNcbiIstream* istr,
1032  TFlags flags,
1033  int ifd,
1034  size_t errbuf_size)
1035  : m_Env(0),
1036  m_Entries(PNocase_Conditional(
1037  (flags & fCaseInsensitiveArgs) ?
1038  NStr::eNocase : NStr::eCase)),
1039  m_Input(0),
1040  m_InputFD(0),
1041  m_OwnInput(false),
1042  m_ErrBufSize(errbuf_size),
1043  m_QueryStringParsed(false),
1044  m_Session(NULL),
1045  m_EntryReaderContext(NULL)
1046 {
1047  CNcbiArguments args(argc, argv);
1048 
1049  CNcbiEnvironment* env = new CNcbiEnvironment(envp);
1051 
1052  x_Init(&args, env, istr, flags, ifd);
1053 }
1054 
1055 
1057 (CNcbiIstream& is,
1058  TFlags flags,
1059  size_t errbuf_size)
1060  : m_Env(0),
1061  m_Entries(PNocase_Conditional((flags & fCaseInsensitiveArgs) ?
1062  NStr::eNocase : NStr::eCase)),
1063  m_Input(0),
1064  m_InputFD(0),
1065  m_OwnInput(false),
1066  m_ErrBufSize(errbuf_size),
1067  m_QueryStringParsed(false),
1068  m_Session(NULL),
1069  m_EntryReaderContext(NULL)
1070 {
1071  Deserialize(is, flags);
1072 
1073  // XXX Should "standard" properties be cached as in x_Init?
1074 
1076 
1078 }
1079 
1080 
1082 {
1084  {"SkipAndError", CCgiCookies::eOnBadCookie_SkipAndError},
1086  {"StoreAndError", CCgiCookies::eOnBadCookie_StoreAndError},
1088 };
1091  eParam_NoThread, CGI_ON_BAD_COOKIE);
1092 typedef NCBI_PARAM_TYPE(CGI, On_Bad_Cookie) TOnBadCookieParam;
1093 
1095 (const CNcbiArguments* args,
1096  const CNcbiEnvironment* env,
1097  CNcbiIstream* istr,
1098  TFlags flags,
1099  int ifd)
1100 {
1101  // Setup environment variables
1102  _ASSERT( !m_Env );
1103  m_Env = env;
1104  if ( !m_Env ) {
1105  // create a dummy environment, if is not specified
1106  m_OwnEnv.reset(new CNcbiEnvironment);
1107  m_Env = m_OwnEnv.get();
1108  } else if ((flags & fOwnEnvironment) != 0) {
1109  // take ownership over the passed environment object
1110  m_OwnEnv.reset(const_cast<CNcbiEnvironment*>(m_Env));
1111  }
1112 
1113  // Cache "standard" properties
1114  for (size_t prop = 0; prop < (size_t) eCgi_NProperties; prop++) {
1116  }
1117 
1119 
1120  // Parse HTTP cookies
1121  if ((flags & fCookies_Unencoded) != 0) {
1123  }
1124  else if ((flags & fCookies_SpaceAsHex) != 0) {
1126  }
1127  try {
1129  TOnBadCookieParam::GetDefault());
1130  } catch (const CCgiCookieException& e) {
1131  NCBI_RETHROW(e, CCgiRequestException, eCookie,
1132  "Error in parsing HTTP request cookies");
1133  }
1134 
1135  // Parse entries or indexes from "$QUERY_STRING" or cmd.-line args
1136  x_ProcessQueryString(flags, args);
1137 
1138  x_ProcessInputStream(flags, istr, ifd);
1139 
1141 
1142  // Check for an IMAGEMAP input entry like: "Command.x=5&Command.y=3" and
1143  // put them with empty string key for better access
1145  if (empty_it != m_Entries.end()) {
1146  // there is already empty name key
1147  ERR_POST_X(5, Warning << "Encountered query parameter with empty name, "
1148  "its value is: '" << empty_it->second << "'. ATTENTION: "
1149  "Because of this, check for image names will be disabled.");
1150  return;
1151  }
1152  string image_name;
1154  const string& entry = i->first;
1155 
1156  // check for our case ("*.x")
1157  if ( !NStr::EndsWith(entry, ".x") )
1158  continue;
1159 
1160  // get base name of IMAGE, check for the presence of ".y" part
1161  string name = entry.substr(0, entry.size() - 2);
1162  if (m_Entries.find(name + ".y") == m_Entries.end())
1163  continue;
1164 
1165  // it is a correct IMAGE name
1166  if ( !image_name.empty() ) {
1167  ERR_POST_X(6, "duplicated IMAGE name: \"" << image_name <<
1168  "\" and \"" << name << "\"");
1169  return;
1170  }
1171  image_name = name;
1172  }
1173  s_AddEntry(m_Entries, kEmptyStr, image_name, 0);
1174 }
1175 
1176 
1177 static CTempString x_FirstWord(const CTempStringEx& forward)
1178 {
1179  if (forward.empty()) {
1180  return CTempString();
1181  }
1182 
1183  vector<CTempStringEx> words;
1184  NStr::Split(forward, ", \t", words,
1186  for (size_t i = 0; i < words.size(); ++i) {
1187  if (NStr::IsIPAddress(words[i])) {
1188  return words[i];
1189  }
1190  }
1191  return CTempStringEx();
1192 }
1193 
1194 
1195 #if 0 // unused
1196 static CTempString x_LastWord(const CTempStringEx& forward)
1197 {
1198  if ( forward.empty() ) {
1199  return CTempString();
1200  }
1201 
1202  vector<CTempStringEx> words;
1203  NStr::Split(forward, ", \t", words,
1205  if ( !words.size() ) {
1206  return CTempString();
1207  }
1208 
1209  size_t i;
1210  for (i = 0; i < words.size(); ++i) {
1211  if (words[i].find(':') == NPOS || !NStr::IsIPAddress(words[i])) {
1212  break;
1213  }
1214  }
1215  return i ? words[i - 1] : CTempStringEx();
1216 }
1217 #endif // unused
1218 
1219 
1221 {
1222  if ((flags & fSkipDiagProperties) != 0) {
1223  return;
1224  }
1225  // Don't try to change the ip if already set.
1226  if (CDiagContext::GetRequestContext().IsSetClientIP()) {
1227  return;
1228  }
1229  // Set client IP for diagnostics
1230  bool internal = ! x_GetPropertyByName("HTTP_CAF_INTERNAL").empty();
1231  bool external = !(x_GetPropertyByName("HTTP_CAF_EXTERNAL").empty() &&
1232  x_GetPropertyByName("HTTP_NCBI_EXTERNAL").empty());
1233  string client;
1234  if ( internal || !external ) {
1235  client = x_GetPropertyByName("HTTP_CLIENT_HOST");
1236  }
1237  if ( client.empty() ) {
1238  client = x_GetPropertyByName("HTTP_CAF_PROXIED_HOST");
1239  }
1240  if ( client.empty() ) {
1241  client = x_GetPropertyByName("PROXIED_IP");
1242  }
1243  if ( client.empty() ) {
1244  client = x_FirstWord(x_GetPropertyByName("HTTP_X_FORWARDED_FOR"));
1245  }
1246  if (client.empty()) {
1247  client = x_GetPropertyByName("HTTP_X_REAL_IP");
1248  }
1249  if ( client.empty() ) {
1251  }
1252  if ( !client.empty() ) {
1254  }
1255 }
1256 
1257 
1259 {
1260  // NOTE: NCBI_CONTEXT is parsed before individual properties (e.g. NCBI_PHID)
1261  // so that their values can override those from NCBI_CONTEXT.
1263  string pt_data = GetRandomProperty("NCBI_CONTEXT", true);
1264  if ( !pt_data.empty() ) {
1266  }
1267 
1270  if ((flags & fIgnorePageHitId) == 0) {
1271  string phid;
1272  // Check if page hit id is present. If not, generate one.
1274  while (phid_rg.first != phid_rg.second) {
1275  phid = phid_rg.first->second;
1276  ++phid_rg.first;
1277  }
1278  if (phid.empty()) {
1279  // Try HTTP_NCBI_PHID
1281  GetRandomProperty("NCBI_PHID", true));
1282  }
1283  if ( phid.empty() ) {
1284  rctx.SetHitID();
1285  }
1286  else {
1287  rctx.SetHitID(phid);
1288  }
1289  }
1290  }
1291  if ( !rctx.IsSetDtab() ) {
1292  string dtab = x_GetPropertyByName("HTTP_DTAB_LOCAL");
1293  if ( !dtab.empty() ) {
1294  rctx.SetDtab(dtab);
1295  }
1296  }
1297  if (!rctx.IsSetProperty("auth_token")) {
1298  if (auto auth_token = TCookieAuthToken::GetDefault(); !auth_token.empty()) {
1299  if (auto cookie = m_Cookies.Find(auth_token)) {
1300  rctx.SetProperty("auth_token", cookie->GetValue());
1301  }
1302  }
1303  }
1304 }
1305 
1306 
1308 {
1309  // Parse entries or indexes from "$QUERY_STRING" or cmd.-line args
1311  m_QueryStringParsed = true;
1312  const string* query_string = NULL;
1313 
1315  // special case: "$REQUEST_METHOD" undefined, so use cmd.-line args
1316  if (args && args->Size() == 2)
1317  query_string = &(*args)[1];
1318  }
1319  else {
1320  // regular case -- read from "$QUERY_STRING"
1321  query_string = &GetProperty(eCgi_QueryString);
1322  }
1323 
1324  if ( query_string ) {
1326  parser.SetQueryString(*query_string);
1327  }
1328  }
1329 }
1330 
1331 
1333 {
1334  m_Content.reset();
1335  // POST method?
1336  if (AStrEquiv(GetProperty(eCgi_RequestMethod), "POST", PNocase()) ||
1338 
1339  if ( !istr ) {
1340  istr = &NcbiCin; // default input stream
1341  ifd = STDIN_FILENO;
1342  }
1343 
1344  const string& content_type = GetProperty(eCgi_ContentType);
1345  if ((flags & fDoNotParseContent) == 0 &&
1346  (content_type.empty() ||
1347  NStr::StartsWith(content_type,
1348  "application/x-www-form-urlencoded") ||
1349  NStr::StartsWith(content_type,
1350  "multipart/form-data"))) {
1351  // Automagically retrieve and parse content into entries
1352  unique_ptr<string> temp_str;
1353  string* pstr = 0;
1354  // Check if the content must be saved
1355  if (flags & fSaveRequestContent) {
1356  m_Content.reset(new string);
1357  pstr = m_Content.get();
1358  } else if (content_type.empty()
1359  && (flags & fParseInputOnDemand) == 0) {
1360  temp_str.reset(new string);
1361  pstr = temp_str.get();
1362  }
1364  (*istr, m_Entries, content_type, GetContentLength(), pstr);
1365  if ( (flags & fParseInputOnDemand) != 0) {
1366  m_Input = 0;
1367  m_InputFD = -1;
1368  if ( (flags & fIncludePreparsedEntries) != 0 ) {
1370  }
1371  } else if (content_type.empty()) {
1372  // allow interpretation as either application/octet-stream
1373  // or application/x-www-form-urlencoded
1374  try {
1376  } NCBI_CATCH_ALL_X(8, "CCgiRequest: POST/PUT with no content type");
1377  if (pstr) {
1378  CStreamUtils::Pushback(*istr, pstr->data(), pstr->length());
1379  }
1380  m_Input = istr;
1381  // m_InputFD = ifd; // would be exhausted
1382  m_InputFD = -1;
1383  m_OwnInput = false;
1384  } else {
1385  // parse query from the POST content
1387  m_Input = 0;
1388  m_InputFD = -1;
1389  }
1390  }
1391  else {
1392  if ( (flags & fSaveRequestContent) ) {
1393  // Save content to string
1395  if ( !NcbiStreamCopy(buf, *istr) ) {
1397  "Failed read of HTTP request body",
1398  (size_t)istr->gcount());
1399  }
1400  string temp = CNcbiOstrstreamToString(buf);
1401  m_Content.reset(new string);
1402  m_Content->swap(temp);
1403  }
1404  // Let the user to retrieve and parse the content
1405  m_Input = istr;
1406  m_InputFD = ifd;
1407  m_OwnInput = false;
1408  }
1409  } else {
1410  m_Input = 0;
1411  m_InputFD = -1;
1412  }
1413 }
1414 
1415 
1416 const string& CCgiRequest::GetContent(void) const
1417 {
1418  if ( !m_Content.get() ) {
1420  "Request content is not available");
1421  }
1422  return *m_Content;
1423 }
1424 
1425 
1426 const string& CCgiRequest::x_GetPropertyByName(const string& name) const
1427 {
1428  return m_Env->Get(name);
1429 }
1430 
1431 
1432 const string& CCgiRequest::GetProperty(ECgiProp property) const
1433 {
1434  return x_GetPropertyByName(GetPropertyName(property));
1435 }
1436 
1437 
1438 const string& CCgiRequest::GetRandomProperty(const string& key, bool http)
1439  const
1440 {
1441  if ( http ) {
1442  return x_GetPropertyByName("HTTP_" + key);
1443  } else {
1444  return x_GetPropertyByName(key);
1445  }
1446 }
1447 
1448 
1449 const CCgiEntry& CCgiRequest::GetEntry(const string& name, bool* is_found)
1450  const
1451 {
1452  static CSafeStatic<CCgiEntry> s_EmptyCgiEntry;
1453  TCgiEntriesCI it = GetEntries().find(name);
1454  bool x_found = (it != GetEntries().end());
1455  if ( is_found ) {
1456  *is_found = x_found;
1457  }
1458  return x_found ? it->second : s_EmptyCgiEntry.Get();
1459 }
1460 
1461 
1463 {
1465  : m_Entries.end();
1466 }
1467 
1468 
1470 {
1471  TCgiEntriesI it = m_Entries.find(name);
1472  if (it == m_Entries.end()) {
1473  do {
1474  it = GetNextEntry();
1475  if (it == m_Entries.end()) {
1476  return NULL;
1477  }
1478  } while (it->first != name);
1479  }
1480  return &it->second;
1481 }
1482 
1483 
1485 {
1486  while (GetNextEntry() != m_Entries.end())
1487  ;
1488 }
1489 
1490 
1491 const size_t CCgiRequest::kContentLengthUnknown = (size_t)(-1);
1492 
1493 
1495 {
1496  const string& str = GetProperty(eCgi_ContentLength);
1497  if ( str.empty() ) {
1498  return kContentLengthUnknown;
1499  }
1500 
1501  size_t content_length;
1502  try {
1503  content_length = (size_t) NStr::StringToUInt(str);
1504  } catch (const CStringException& e) {
1505  NCBI_RETHROW(e, CCgiRequestException, eFormat,
1506  "Malformed Content-Length value in HTTP request: " + str);
1507  }
1508 
1509  return content_length;
1510 }
1511 
1512 
1513 void CCgiRequest::SetInputStream(CNcbiIstream* is, bool own, int fd)
1514 {
1515  if (is != m_Input || is == NULL) {
1516  if (m_EntryReaderContext) {
1517  delete m_EntryReaderContext;
1519  }
1520  if (m_Input && m_OwnInput) {
1521  delete m_Input;
1522  }
1523  }
1524  m_Input = is;
1525  m_InputFD = fd;
1526  m_OwnInput = own;
1527 }
1528 
1529 
1531 {
1532  CCgiEntries_Parser parser(&entries, 0, 0);
1533  try {
1534  parser.SetQueryString(str);
1535  }
1536  catch (const CUrlParserException& ae) {
1537  return ae.GetPos();
1538  }
1539  return 0;
1540 }
1541 
1542 
1544 {
1545  CCgiEntries_Parser parser(0, &indexes, fIndexesNotEntries);
1546  try {
1547  parser.SetQueryString(str);
1548  }
1549  catch (const CUrlParserException& ae) {
1550  return ae.GetPos();
1551  }
1552  return 0;
1553 }
1554 
1555 
1556 
1557 const char* const* CCgiRequest::GetClientTrackingEnv(void) const
1558 {
1559  if (!m_TrackingEnvHolder.get()) {
1561  }
1562  return m_TrackingEnvHolder->GetTrackingEnv();
1563 }
1564 
1565 
1567 {
1568  WriteMap(os, GetEntries());
1569  WriteCgiCookies(os, GetCookies());
1571  WriteEnvironment(os, env);
1572  // WriteEnvironment(os, *m_Env);
1573  WriteContainer(os, GetIndexes());
1574  os << (int)m_QueryStringParsed;
1575  CNcbiIstream* istrm = GetInputStream();
1576  if (istrm) {
1577  char buf[1024];
1578  while(!istrm->eof()) {
1579  istrm->read(buf, sizeof(buf));
1580  os.write(buf, istrm->gcount());
1581  }
1582  }
1583 
1584 }
1585 
1587 {
1588  ReadMap(is, GetEntries());
1589  ReadCgiCookies(is, GetCookies());
1590  m_OwnEnv.reset(new CNcbiEnvironment(0));
1592  ReadContainer(is, GetIndexes());
1593  if (!is.eof() && is.good()) {
1594  char c;
1595  is.get(c);
1596  m_QueryStringParsed = c == '1' ? true : false;
1597  (void)is.peek();
1598  }
1599  m_Env = m_OwnEnv.get();
1601  if (!is.eof() && is.good())
1602  x_ProcessInputStream(flags, &is, -1);
1603 }
1604 
1606 {
1607  _ASSERT(m_Session);
1608  if (mode == eDontLoad)
1609  return *m_Session;
1610 
1611  try {
1612  m_Session->Load();
1613  } catch (const CCgiSessionException& ex) {
1614  if (ex.GetErrCode() != CCgiSessionException::eSessionId) {
1615  NCBI_RETHROW(ex, CCgiSessionException, eImplException,
1616  "Session implementation error");
1617  }
1618  }
1619  if (!m_Session->Exists()) {
1620  if (mode != eCreateIfNotExist)
1621  NCBI_THROW(CCgiSessionException, eSessionDoesnotExist,
1622  "Session doesn't exist.");
1623  else
1625  }
1626 
1627  return *m_Session;
1628 }
1629 
1630 
1631 // Arguments listed here as 'arg1&arg2...' are completely removed from
1632 // log message. If '*' is listed, all arguments are excluded.
1633 NCBI_PARAM_DECL(string, CGI, LOG_EXCLUDE_ARGS);
1634 NCBI_PARAM_DEF_EX(string, CGI, LOG_EXCLUDE_ARGS, "", eParam_NoThread,
1635  CGI_LOG_EXCLUDE_ARGS);
1636 typedef NCBI_PARAM_TYPE(CGI, LOG_EXCLUDE_ARGS) TCGI_LogExcludeArgs;
1637 
1638 // Arguments to be listed with restructed size.
1639 // Value format is arg1:size1&arg2:size2...&*:size
1640 // The listed arguments are truncated to the size specified.
1641 // '*' may be used to limit size of all unlisted arguments.
1642 NCBI_PARAM_DECL(string, CGI, LOG_LIMIT_ARGS);
1643 NCBI_PARAM_DEF_EX(string, CGI, LOG_LIMIT_ARGS, "*:1000000", eParam_NoThread,
1644  CGI_LOG_LIMIT_ARGS);
1645 typedef NCBI_PARAM_TYPE(CGI, LOG_LIMIT_ARGS) TCGI_LogLimitArgs;
1646 
1647 
1649 {
1650  // If there are any indexes, ignore entries and limits
1651  if ( !m_Indexes.empty() ) {
1652  ITERATE(TCgiIndexes, idx, m_Indexes) {
1653  if ( idx->empty() ) {
1654  continue;
1655  }
1656  collector.AddEntry(*idx, kEmptyStr, kEmptyStr, true);
1657  }
1658  return;
1659  }
1660 
1661  list<string> excluded, limited;
1662  // Map argument name to its limit. Limit of -2 indicates excluded
1663  // arguments, limit = -1 means no limit.
1664  typedef map<string, int> TArgLimits;
1665  TArgLimits arg_limits;
1666  int lim_unlisted = -1;
1667 
1668  NStr::Split(TCGI_LogLimitArgs::GetDefault(), "&", limited,
1670  ITERATE(list<string>, it, limited) {
1671  string arg, val;
1672  NStr::SplitInTwo(*it, ":", arg, val);
1673  if ( arg.empty() ) {
1674  ERR_POST(Error << "Missing argument name before size limit: "
1675  << *it);
1676  continue;
1677  }
1678  if ( val.empty() ) {
1679  ERR_POST(Error << "Missing argument size limit: " << *it);
1680  continue;
1681  }
1682  int ival;
1683  try {
1684  ival = NStr::StringToInt(val);
1685  }
1686  catch (const CStringException&) {
1687  ERR_POST(Error << "Invalid argument size limit: " << *it);
1688  continue;
1689  }
1690  if (arg == "*") {
1691  lim_unlisted = ival;
1692  continue;
1693  }
1694  arg_limits[arg] = ival;
1695  }
1696 
1697  NStr::Split(TCGI_LogExcludeArgs::GetDefault(), "&", excluded,
1699  ITERATE(list<string>, it, excluded) {
1700  if (*it == "*") {
1701  return;
1702  }
1703  arg_limits[*it] = -2;
1704  }
1705 
1706  ITERATE(TCgiEntries, entry, m_Entries) {
1707  if (entry->first.empty() && entry->second.empty()) {
1708  continue;
1709  }
1710  TArgLimits::const_iterator lim_it = arg_limits.find(entry->first);
1711  int lim = (lim_it == arg_limits.end()) ? lim_unlisted : lim_it->second;
1712  if (lim == -2) {
1713  // Excluded argument
1714  continue;
1715  }
1716  collector.AddEntry(entry->first,
1717  lim >= 0 ? entry->second.substr(0, lim) : string(entry->second),
1718  entry->second.GetFilename(),
1719  false);
1720  }
1721 }
1722 
1723 
1725 public:
1727  virtual ~CStringEntryCollector(void) {}
1728 
1729  virtual void AddEntry(const string& name,
1730  const string& value,
1731  const string& filename,
1732  bool is_index);
1733 
1734  const string& GetArgs(void) const { return m_Args; }
1735 
1736 private:
1737  string m_Args;
1738 };
1739 
1740 
1741 void CStringEntryCollector::AddEntry(const string& name,
1742  const string& value,
1743  const string& /*filename*/,
1744  bool is_index)
1745 {
1746  if ( is_index ) {
1747  if ( !m_Args.empty() ) {
1748  m_Args += '+';
1749  }
1751  }
1752  else {
1753  if ( !m_Args.empty() ) {
1754  m_Args += '&';
1755  }
1757  m_Args += '=';
1759  }
1760 }
1761 
1762 
1764 {
1765  CStringEntryCollector collector;
1766  GetCGIEntries(collector);
1767  return collector.GetArgs();
1768 }
1769 
1770 
1771 bool CCgiRequest::CalcChecksum(string& checksum, string& content) const
1772 {
1773  if( AStrEquiv(GetProperty(eCgi_RequestMethod), "POST", PNocase()) )
1774  return false;
1775 
1777  string query_string = GetProperty(eCgi_QueryString);
1778  CCgiRequest::ParseEntries(query_string, entries);
1779 
1780  content.erase();
1781  ITERATE(TCgiEntries, entry, entries) {
1782  content += entry->first + '=' + entry->second;
1783  }
1784  string url = GetProperty(eCgi_ServerName);
1785  url += ':';
1786  url += GetProperty(eCgi_ServerPort);
1787  url += GetProperty(eCgi_ScriptName);
1788  if ( url == ":" ) {
1790  if (app)
1791  url = app->GetProgramDisplayName();
1792  }
1793  content += url;
1794 
1796  cs.AddLine(content);
1797  CNcbiOstrstream oss;
1798  cs.WriteChecksumData(oss);
1799  checksum = CNcbiOstrstreamToString(oss);
1800  return true;
1801 }
1802 
1803 
1804 const string& CCgiRequest::GetRequestMethodName(void) const
1805 {
1807 }
1808 
1809 
1811 {
1812  const char* s_Request_Method_Names[8] = {
1813  "GET",
1814  "POST",
1815  "HEAD",
1816  "PUT",
1817  "DELETE",
1818  "OPTIONS",
1819  "TRACE",
1820  "CONNECT"
1821  };
1822  const ERequestMethod s_Request_Methods[8] = {
1823  eMethod_GET,
1824  eMethod_POST,
1825  eMethod_HEAD,
1826  eMethod_PUT,
1829  eMethod_TRACE,
1831  };
1832  const string& method = GetRequestMethodName();
1833  for (int i = 0; i < 8; i++) {
1834  if ( AStrEquiv(method, s_Request_Method_Names[i], PNocase()) ) {
1835  return s_Request_Methods[i];
1836  }
1837  }
1838  return eMethod_Other;
1839 }
1840 
1841 
1842 string CCgiEntry::x_GetCharset(void) const
1843 {
1844  string type = GetContentType();
1845  SIZE_TYPE pos = NStr::FindNoCase(type, "charset=");
1846  if (pos == NPOS) {
1847  return kEmptyStr;
1848  }
1849  pos += 8;
1850  SIZE_TYPE pos2 = type.find(";", pos);
1851  return type.substr(pos, pos2 == NPOS ? pos2 : pos2 - pos);
1852 }
1853 
1854 
1855 inline
1856 bool s_Is_ISO_8859_1(const string& charset)
1857 {
1858  const char* s_ISO_8859_1_Names[8] = {
1859  "ISO-8859-1",
1860  "iso-ir-100",
1861  "ISO_8859-1",
1862  "latin1",
1863  "l1",
1864  "IBM819",
1865  "CP819",
1866  "csISOLatin1"
1867  };
1868  for (int i = 0; i < 8; i++) {
1869  if (NStr::CompareNocase(s_ISO_8859_1_Names[i], charset) == 0) {
1870  return true;
1871  }
1872  }
1873  return false;
1874 }
1875 
1876 
1877 inline
1878 bool s_Is_Windows_1252(const string& charset)
1879 {
1880  const char* s_Windows_1252_Name = "windows-1252";
1881  return NStr::CompareNocase(s_Windows_1252_Name, charset) == 0;
1882 }
1883 
1884 
1885 inline
1886 bool s_Is_UTF_8(const string& charset)
1887 {
1888  const char* s_UTF_8_Name = "utf-8";
1889  return NStr::CompareNocase(s_UTF_8_Name, charset) == 0;
1890 }
1891 
1892 
1894  CCgiEntry::EOnCharsetError on_error)
1895 {
1896  if ( charset.empty() ) {
1897  return eEncodingForm_Unknown;
1898  }
1899  if ( s_Is_ISO_8859_1(charset) ) {
1900  return eEncodingForm_ISO8859_1;
1901  }
1902  if ( s_Is_Windows_1252(charset) ) {
1904  }
1905  if ( s_Is_UTF_8(charset) ) {
1906  return eEncodingForm_Utf8;
1907  }
1908  // UTF-16BE
1909  // UTF-16LE
1910  // UTF-16
1911  union {
1912  unsigned char u1[2];
1913  Uint2 u2;
1914  } s_BE_test;
1915  s_BE_test.u1[0] = 0xFF;
1916  s_BE_test.u1[1] = 0xFE;
1917  static bool s_BE = (s_BE_test.u2 == 0xFFFE);
1918  if (NStr::CompareNocase(charset, "UTF-16BE") == 0) {
1920  }
1921  if (NStr::CompareNocase(charset, "UTF-16LE") == 0) {
1923  }
1924  if (NStr::CompareNocase(charset, "UTF-16") == 0) {
1925  // Try to autodetect UTF-16 byte order
1926  return eEncodingForm_Unknown;
1927  }
1928  if (on_error == CCgiEntry::eCharsetError_Throw) {
1929  NCBI_THROW(CCgiException, eUnknown, "Unsupported charset: " + charset);
1930  }
1931  return eEncodingForm_Unknown;
1932 }
1933 
1934 
1936 {
1937  CNcbiIstrstream is(GetValue());
1939  CStringUTF8 utf_str;
1940  try {
1941  ReadIntoUtf8(is, &utf_str, enc);
1942  }
1943  catch (const CException&) {
1944  if (on_error == eCharsetError_Throw) {
1945  throw;
1946  }
1947  return CStringUTF8();
1948  }
1949  return utf_str;
1950 }
1951 
1952 
1953 void CExtraEntryCollector::AddEntry(const string& name,
1954  const string& value,
1955  const string& filename,
1956  bool is_index)
1957 {
1958  _ASSERT(!is_index || value.empty());
1959  m_Args.push_back(CDiagContext_Extra::TExtraArg(name,
1960  filename.empty() ? value : filename + "/" + value));
1961 }
1962 
1963 
Support classes for on-demand CGI input parsing.
Exception classes used by the NCBI CGI framework.
CNcbiIstream & ReadMap(CNcbiIstream &is, TMap &cont)
Read a map from a stream.
Definition: cgi_serial.hpp:186
CNcbiIstream & ReadEnvironment(CNcbiIstream &is, CNcbiEnvironment &cont)
Write an environment from a stream.
Definition: cgi_serial.cpp:111
CNcbiIstream & ReadCgiCookies(CNcbiIstream &is, CCgiCookies &cont)
Read cgi cookeis from a stream.
Definition: cgi_serial.cpp:87
CNcbiOstream & WriteContainer(CNcbiOstream &os, const TCont &cont)
Write a container to a stream.
Definition: cgi_serial.hpp:216
CNcbiOstream & WriteEnvironment(CNcbiOstream &os, const CNcbiEnvironment &cont)
Write an environment to a stream.
Definition: cgi_serial.cpp:98
CNcbiOstream & WriteMap(CNcbiOstream &os, const TMap &cont)
Write a map to a stream.
Definition: cgi_serial.hpp:164
CNcbiOstream & WriteCgiCookies(CNcbiOstream &os, const CCgiCookies &cont)
Write cgi cookeis to a stream.
Definition: cgi_serial.cpp:79
CNcbiIstream & ReadContainer(CNcbiIstream &is, TCont &cont)
Read a container from a stream.
Definition: cgi_serial.hpp:234
API to store CGI session data between Web requests.
Checksum and hash calculation classes.
CCgiCookieException –.
CCgiCookie::
Definition: ncbicgi.hpp:67
CCgiCookies::
Definition: ncbicgi.hpp:219
virtual void AddArgument(unsigned int position, const string &name, const string &value, EArgType arg_type)
Process next query argument.
Definition: ncbicgi.cpp:982
CCgiEntries_Parser(TCgiEntries *entries, TCgiIndexes *indexes, CCgiRequest::TFlags flags)
Definition: ncbicgi.cpp:971
static CCgiRequest::TFlags TFlagsToCCgiRequestTFlags(TFlags flags)
Definition: cgi_impl.hpp:49
TCgiIndexes * m_Indexes
Definition: cgi_impl.hpp:53
TCgiEntries * m_Entries
Definition: cgi_impl.hpp:52
CCgiErrnoException –.
CCgiParseException –.
CCgiRequestException –.
CCgiRequest::
Definition: ncbicgi.hpp:685
CCgiSessionException –.
CCgiSession –.
Definition: cgi_session.hpp:62
CChecksum – Checksum calculator.
Definition: checksum.hpp:302
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:264
CNcbiArguments –.
Definition: ncbienv.hpp:236
CNcbiEnvironment –.
Definition: ncbienv.hpp:110
CNcbiOstrstreamToString class helps convert CNcbiOstrstream to a string Sample usage:
Definition: ncbistre.hpp:802
Request context properties passed between tasks.
T & Get(void)
Create the variable if not created yet, return the reference.
virtual void AddEntry(const string &name, const string &value, const string &filename, bool is_index)
Definition: ncbicgi.cpp:1741
const string & GetArgs(void) const
Definition: ncbicgi.cpp:1734
virtual ~CStringEntryCollector(void)
Definition: ncbicgi.cpp:1727
CStringException –.
Definition: ncbistr.hpp:4500
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
CTime –.
Definition: ncbitime.hpp:296
char ** m_TrackingEnv
Definition: ncbicgi.cpp:834
CTrackingEnvHolder(const CNcbiEnvironment *env)
Definition: ncbicgi.cpp:856
void x_Destroy(void)
Definition: ncbicgi.cpp:888
const char *const * GetTrackingEnv(void) const
Definition: ncbicgi.cpp:829
const CNcbiEnvironment * m_Env
Definition: ncbicgi.cpp:833
CUrlArgs_Parser::
Definition: ncbi_url.hpp:170
CUrlParserException –.
Definition: ncbi_url.hpp:539
NStr –.
Definition: ncbistr.hpp:243
Define Case-insensitive string comparison methods.
Definition: ncbistr.hpp:4918
Severity –.
Definition: ncbidiag.hpp:833
const_iterator_pair equal_range(const key_type &key) const
Definition: map.hpp:296
const_iterator find(const key_type &key) const
Definition: map.hpp:293
const_iterator end() const
Definition: map.hpp:292
iterator insert(const value_type &val)
Definition: map.hpp:305
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
const_iterator begin() const
Definition: set.hpp:135
void clear()
Definition: set.hpp:153
void erase(iterator pos)
Definition: set.hpp:151
const_iterator end() const
Definition: set.hpp:136
static uch flags
#define true
Definition: bool.h:35
#define false
Definition: bool.h:36
static const char * str(char *buf, int n)
Definition: stats.c:84
static HENV env
Definition: transaction2.c:38
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
const string & GetProgramDisplayName(void) const
Get the application's "display" name.
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
string
Definition: cgiapp.hpp:690
CGI
Definition: cgiapp.hpp:688
@ eSessionId
SessionId not specified.
bool m_AllSecure
Definition: ncbicgi.hpp:345
const CNcbiEnvironment * m_Env
set of environment variables
Definition: ncbicgi.hpp:930
bool m_OwnInput
Definition: ncbicgi.hpp:944
const TCgiIndexes & GetIndexes(void) const
Get a set of indexes(decoded) received from the client.
Definition: ncbicgi.hpp:1192
void x_ProcessQueryString(TFlags flags, const CNcbiArguments *args)
Parse entries or indexes from "$QUERY_STRING" or cmd.-line args.
Definition: ncbicgi.cpp:1307
pair< TCIter, TCIter > TCRange
Definition: ncbicgi.hpp:225
string m_Domain
Definition: ncbicgi.hpp:158
string m_Path
Definition: ncbicgi.hpp:159
TCgiEntries::iterator TCgiEntriesI
Definition: ncbicgi.hpp:639
TCgiEntries::const_iterator TCgiEntriesCI
Definition: ncbicgi.hpp:640
string GetExpDate(void) const
Day, dd-Mon-yyyy hh:mm:ss GMT (return empty string if not set)
Definition: ncbicgi.cpp:206
bool CalcChecksum(string &checksum, string &content) const
Definition: ncbicgi.cpp:1771
TSet::iterator TIter
Definition: ncbicgi.hpp:222
static ECheckResult x_CheckField(const string &str, CCgiCookie::EFieldType ftype, const char *banned_symbols, EOnBadCookie on_bad_cookie, const string *cookie_name=NULL)
Definition: ncbicgi.cpp:453
const string & x_GetPropertyByName(const string &name) const
retrieve(and cache) a property of given name
Definition: ncbicgi.cpp:1426
int m_InputFD
input file descriptor, if available.
Definition: ncbicgi.hpp:943
string m_Value
Definition: ncbicgi.hpp:157
const TCgiEntries & GetEntries(void) const
Get a set of entries(decoded) received from the client.
Definition: ncbicgi.hpp:1181
NStr::EUrlEncode m_EncodeFlag
Definition: ncbicgi.hpp:342
static string x_EncodeCookie(const string &str, EFieldType ftype, NStr::EUrlEncode flag)
Definition: ncbicgi.cpp:111
static SIZE_TYPE ParseEntries(const string &str, TCgiEntries &entries)
Decode the URL-encoded(FORM or ISINDEX) string "str" into a set of entries <"name",...
Definition: ncbicgi.cpp:1530
bool m_HttpOnly
Definition: ncbicgi.hpp:162
void SetPath(const string &str)
Definition: ncbicgi.hpp:1015
void x_InitRequestContext(TFlags flags)
Set the properties of CRequestContext (HitId, Dtab etc.).
Definition: ncbicgi.cpp:1258
void ParseRemainingContent(void)
Parse any remaining POST content for use by GetEntries() et al.
Definition: ncbicgi.cpp:1484
void SetValue(const string &str)
All SetXXX(const string&) methods beneath:
Definition: ncbicgi.hpp:1007
const string & GetName(void) const
The cookie name cannot be changed during its whole timelife.
Definition: ncbicgi.hpp:1031
CCgiCookie * Find(const string &name, const string &domain, const string &path)
Return NULL if cannot find this exact cookie.
Definition: ncbicgi.cpp:690
CCgiEntryReaderContext * m_EntryReaderContext
Definition: ncbicgi.hpp:981
void AddEntry(const string &name, const string &value, const string &filename, bool is_index) override
Definition: ncbicgi.cpp:1953
void Reset(void)
Reset everything but name to default state like CCgiCookie(m_Name, "")
Definition: ncbicgi.cpp:177
void Serialize(CNcbiOstream &os) const
Serialize/Deserialize a request to/from a stream.
Definition: ncbicgi.cpp:1566
EWriteMethod
Whether the cookie is sent as a part of HTTP request or HTTP response.
Definition: ncbicgi.hpp:85
TCgiIndexes m_Indexes
set of the request ISINDEX-like indexes(already retrieved; cached)
Definition: ncbicgi.hpp:937
TSet::const_iterator TCIter
Definition: ncbicgi.hpp:223
void SetUrlEncodeFlag(EUrlEncode encode_flag)
Definition: ncbicgi.hpp:1107
void GetCGIEntries(CEntryCollector_Base &collector) const
Get full set of arguments (both GET and POST), URL-encoded.
Definition: ncbicgi.cpp:1648
pair< TIter, TIter > TRange
Definition: ncbicgi.hpp:224
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 SetAllCookiesSecure(bool value)
Mark all cookies as secure.
Definition: ncbicgi.cpp:801
void x_ProcessInputStream(TFlags flags, CNcbiIstream *istr, int ifd)
Parse input stream if needed.
Definition: ncbicgi.cpp:1332
On_Bad_Cookie
Definition: ncbicgi.hpp:359
TCgiEntriesI GetNextEntry(void)
void SetExpTime(const CTime &exp_time)
Definition: ncbicgi.cpp:363
ECgiProp
Set of "standard" HTTP request properties.
Definition: ncbicgi.hpp:378
CDiagContext_Extra::TExtraArgs m_Args
Definition: ncbicgi.hpp:673
const CCgiCookies & GetCookies(void) const
Retrieve the request cookies.
Definition: ncbicgi.hpp:1173
bool m_QueryStringParsed
Definition: ncbicgi.hpp:952
CNcbiIstream * m_Input
input stream
Definition: ncbicgi.hpp:941
const char *const * GetClientTrackingEnv(void) const
Return client tracking environment variables These variables are stored in the form "name=value".
Definition: ncbicgi.cpp:1557
bool m_Secure
Definition: ncbicgi.hpp:161
void CopyAttributes(const CCgiCookie &cookie)
Set all attribute values(but name!) to those from "cookie".
Definition: ncbicgi.cpp:189
const string & GetContentType() const
May be available for some fields of POSTed forms.
Definition: ncbicgi.hpp:525
string GetCGIEntriesStr(void) const
Shortcut for collecting arguments into a URL-style string.
Definition: ncbicgi.cpp:1763
CNcbiOstream & Write(CNcbiOstream &os, EWriteMethod wmethod=eHTTPResponse, EUrlEncode flag=eUrlEncode_SkipMarkChars) const
Compose and write to output stream "os":
Definition: ncbicgi.cpp:232
bool Remove(CCgiCookie *cookie, bool destroy=true)
Remove "cookie" from this set; deallocate it if "destroy" is true Return FALSE if can not find "cooki...
Definition: ncbicgi.cpp:770
CCgiEntry * GetPossiblyUnparsedEntry(const string &name)
Get entry value by name, calling GetNextEntry() as needed.
Definition: ncbicgi.cpp:1469
TCgiEntries m_Entries
set of the request FORM-like entries(already retrieved; cached)
Definition: ncbicgi.hpp:935
const string & GetProperty(ECgiProp prop) const
Get value of a "standard" property (return empty string if not defined)
Definition: ncbicgi.cpp:1432
list< string > TCgiIndexes
Definition: ncbicgi.hpp:641
void Clear(void)
Remove all stored cookies.
Definition: ncbicgi.cpp:792
CNcbiOstream & Write(CNcbiOstream &os, CCgiCookie::EWriteMethod wmethod=CCgiCookie::eHTTPResponse) const
Printout all cookies into the stream "os".
Definition: ncbicgi.cpp:670
CCgiCookie(const CCgiCookie &cookie)
Copy constructor.
Definition: ncbicgi.cpp:146
static SIZE_TYPE ParseIndexes(const string &str, TCgiIndexes &indexes)
Decode the URL-encoded string "str" into a set of ISINDEX-like entries and add them to the "indexes" ...
Definition: ncbicgi.cpp:1543
void ResetInvalid(TInvalidFlag flag)
Definition: ncbicgi.hpp:1058
unique_ptr< CTrackingEnvHolder > m_TrackingEnvHolder
Definition: ncbicgi.hpp:979
void x_Init(const CNcbiArguments *args, const CNcbiEnvironment *env, CNcbiIstream *istr, TFlags flags, int ifd)
the real constructor code
Definition: ncbicgi.cpp:1095
bool m_Secure
Definition: ncbicgi.hpp:344
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
unique_ptr< CNcbiEnvironment > m_OwnEnv
Definition: ncbicgi.hpp:931
TCRange GetAll(void) const
Return the full range [begin():end()] on the underlying container.
Definition: ncbicgi.cpp:763
string x_GetCharset(void) const
Definition: ncbicgi.cpp:1842
TCgiEntriesI GetNextEntry(void)
Get next entry when parsing input on demand.
Definition: ncbicgi.cpp:1462
void SetInputStream(CNcbiIstream *is, bool own=false, int fd=-1)
Set input stream to "is".
Definition: ncbicgi.cpp:1513
virtual void AddEntry(const string &name, const string &value, const string &filename, bool is_index=false)=0
CCgiCookies m_Cookies
set of the request cookies(already retrieved; cached)
Definition: ncbicgi.hpp:939
CCgiSession * m_Session
Definition: ncbicgi.hpp:980
const string & GetContent(void) const
Get request content.
Definition: ncbicgi.cpp:1416
void SetAllCookiesHttpOnly(bool value)
Mark all cookies as HTTP_ONLY.
Definition: ncbicgi.cpp:810
tm m_Expires
Definition: ncbicgi.hpp:160
const string & GetPath(void) const
Definition: ncbicgi.hpp:1040
unique_ptr< string > m_Content
Original request content or NULL if fSaveRequestContent is not set.
Definition: ncbicgi.hpp:933
EOnBadCookie
How to handle badly formed cookies.
Definition: ncbicgi.hpp:228
static const size_t kContentLengthUnknown
Get content length using value of the property 'eCgi_ContentLength'.
Definition: ncbicgi.hpp:781
~CCgiRequest(void)
Destructor.
Definition: ncbicgi.cpp:999
TInvalidFlag m_InvalidFlag
Definition: ncbicgi.hpp:163
void SetInvalid(TInvalidFlag flag)
Definition: ncbicgi.hpp:1054
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
CCgiSession & GetSession(ESessionCreateMode mode=eCreateIfNotExist) const
Get session.
Definition: ncbicgi.cpp:1605
void Deserialize(CNcbiIstream &is, TFlags flags=0)
Definition: ncbicgi.cpp:1586
bool operator<(const CCgiCookie &cookie) const
Compare two cookies.
Definition: ncbicgi.cpp:355
TInvalidFlag IsInvalid(void) const
Definition: ncbicgi.hpp:1050
CStringUTF8 GetValueAsUTF8(EOnCharsetError on_error=eCharsetError_Ignore) const
Definition: ncbicgi.cpp:1935
bool m_AllHttpOnly
Definition: ncbicgi.hpp:346
static void x_CheckField(const string &str, EFieldType ftype, const char *banned_symbols, const string *cookie_name=NULL)
Definition: ncbicgi.cpp:283
const CCgiEntry & GetEntry(const string &name, bool *is_found=0) const
Get entry value by name.
Definition: ncbicgi.cpp:1449
ERequestMethod
Standard request methods.
Definition: ncbicgi.hpp:905
int TFlags
Startup initialization.
Definition: ncbicgi.hpp:703
static const string GetPropertyName(ECgiProp prop)
Get name (not value!) of a "standard" property.
Definition: ncbicgi.cpp:949
void x_SetClientIpProperty(TFlags flags) const
Set client-ip property for logging.
Definition: ncbicgi.cpp:1220
string m_Name
Definition: ncbicgi.hpp:156
size_t GetContentLength(void) const
Definition: ncbicgi.cpp:1494
CNcbiIstream * GetInputStream(void) const
Return pointer to the input stream.
Definition: ncbicgi.hpp:1196
const string & GetDomain(void) const
Definition: ncbicgi.hpp:1037
const string & GetRequestMethodName(void) const
Get request method name.
Definition: ncbicgi.cpp:1804
void SetDomain(const string &str)
Definition: ncbicgi.hpp:1011
EOnCharsetError
Action to perform if the explicit charset is not supported.
Definition: ncbicgi.hpp:499
CCgiRequest(const CNcbiArguments *args=0, const CNcbiEnvironment *env=0, CNcbiIstream *istr=0, TFlags flags=0, int ifd=-1, size_t errbuf_size=256)
Definition: ncbicgi.cpp:1006
TSet m_Cookies
Definition: ncbicgi.hpp:343
ERequestMethod GetRequestMethod(void) const
Get request method.
Definition: ncbicgi.cpp:1810
@ eField_Value
Definition: ncbicgi.hpp:167
@ eHTTPResponse
Definition: ncbicgi.hpp:86
@ eHTTPRequest
Definition: ncbicgi.hpp:87
@ eCgi_ContentType
Definition: ncbicgi.hpp:391
@ eCgi_ServerName
Definition: ncbicgi.hpp:381
@ eCgi_RemoteAddr
Definition: ncbicgi.hpp:388
@ eCgi_HttpCookie
Definition: ncbicgi.hpp:408
@ eCgi_ContentLength
Definition: ncbicgi.hpp:392
@ eCgi_RequestMethod
Definition: ncbicgi.hpp:395
@ eCgi_NProperties
Definition: ncbicgi.hpp:415
@ eCgi_QueryString
Definition: ncbicgi.hpp:399
@ eCgi_ServerPort
Definition: ncbicgi.hpp:384
@ eCgi_ScriptName
Definition: ncbicgi.hpp:398
@ fIgnorePageHitId
Do not check if page hit id is present, do not generate one if it's missing.
Definition: ncbicgi.hpp:723
@ fIndexesNotEntries
do not handle indexes as regular FORM entries with empty value
Definition: ncbicgi.hpp:706
@ fOwnEnvironment
own the passed "env" (and destroy it in the destructor)
Definition: ncbicgi.hpp:710
@ fCookies_SpaceAsHex
Use hex code for encoding spaces rather than '+'.
Definition: ncbicgi.hpp:718
@ fSaveRequestContent
Save request content (available through GetContent())
Definition: ncbicgi.hpp:720
@ fCookies_Unencoded
Do not use URL-encoding/decoding for cookies.
Definition: ncbicgi.hpp:716
@ fIncludePreparsedEntries
When parsing input on demand iterate all existing entries (e.g.
Definition: ncbicgi.hpp:738
@ fDoNotParseContent
do not automatically parse the request's content body (from "istr")
Definition: ncbicgi.hpp:712
@ fParseInputOnDemand
Enable on-demand parsing via GetNextEntry()
Definition: ncbicgi.hpp:729
@ fIgnoreQueryString
do not parse $QUERY_STRING (or cmd.line if $REQUEST_METHOD not def)
Definition: ncbicgi.hpp:708
@ fSkipDiagProperties
Set client-ip and session-id properties for logging.
Definition: ncbicgi.hpp:725
@ eCookieEnc_Quote
Definition: ncbicgi.hpp:187
@ eCookieEnc_Url
Definition: ncbicgi.hpp:186
@ eOnBadCookie_StoreAndError
Report error, store bad cookie as-is.
Definition: ncbicgi.hpp:232
@ eOnBadCookie_ThrowException
Throw exception, ignore bad cookie.
Definition: ncbicgi.hpp:229
@ eOnBadCookie_Store
Store bad cookie without URL-decoding.
Definition: ncbicgi.hpp:233
@ eOnBadCookie_SkipAndError
Report error, ignore bad cookie.
Definition: ncbicgi.hpp:230
@ eOnBadCookie_Skip
Silently ignore bad cookie.
Definition: ncbicgi.hpp:231
@ eCreateIfNotExist
If Session does not exist the new one will be created.
Definition: ncbicgi.hpp:837
@ eCheck_SkipInvalid
Definition: ncbicgi.hpp:333
@ eCheck_StoreInvalid
Definition: ncbicgi.hpp:334
@ eMethod_OPTIONS
Definition: ncbicgi.hpp:911
@ eMethod_DELETE
Definition: ncbicgi.hpp:910
@ eMethod_Other
Unknown method, use GetRequestMethodName to read.
Definition: ncbicgi.hpp:914
@ eMethod_CONNECT
Definition: ncbicgi.hpp:913
@ eCharsetError_Throw
Throw exception if charset is not supported.
Definition: ncbicgi.hpp:501
@ fInvalid_Any
Definition: ncbicgi.hpp:147
@ fInvalid_Name
Definition: ncbicgi.hpp:145
@ fInvalid_Value
Definition: ncbicgi.hpp:146
bool Exists(void) const
Check if this session object is valid.
void CreateNewSession(void)
Create new session.
void Load(void)
Load the session.
EUrlEncode
Definition: cgi_util.hpp:56
@ eUrlEncode_None
Definition: cgi_util.hpp:57
@ eUrlEncode_PercentOnly
Definition: cgi_util.hpp:60
#define NULL
Definition: ncbistd.hpp:225
void AddLine(const char *line, size_t len)
Definition: checksum.hpp:609
CNcbiOstream & WriteChecksumData(CNcbiOstream &out) const
Definition: checksum.cpp:340
#define _VERIFY(expr)
Definition: ncbidbg.hpp:161
static string SelectLastHitID(const string &hit_ids)
Select the last hit id from the list of ids separated with commas and optional spaces.
void SetDtab(const string &dtab)
void SetClientIP(const string &client)
void SetProperty(const string &name, const string &value)
Add/change property.
static CRequestContext & GetRequestContext(void)
Shortcut to CDiagContextThreadData::GetThreadData().GetRequestContext()
Definition: ncbidiag.cpp:1901
bool IsSetHitID(EHitIDSource src=eHitID_Any) const
Check if there's an explicit hit id or the default one.
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).
bool IsSetDtab(void) const
Dtab.
void SetHitID(const string &hit)
Set explicit hit id. The id is reset on request end.
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
EDiagSev
Severity level for the posted diagnostics.
Definition: ncbidiag.hpp:650
SDiagMessage::TExtraArg TExtraArg
Definition: ncbidiag.hpp:1863
@ eHitID_Request
Check if per-request hit id is set.
@ eFormat_UrlEncoded
name=value pairs URL-encoded and separated with '&'
@ 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
const string & Get(const string &name, bool *found=NULL) const
Get environment value by name.
Definition: ncbienv.cpp:109
SIZE_TYPE Size(void) const
Get size (number) of arguments.
Definition: ncbienv.hpp:265
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
#define NCBI_CATCH_ALL_X(err_subcode, message)
Definition: ncbiexpt.hpp:619
#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
#define NCBI_THROW2(exception_class, err_code, message, extra)
Throw exception with extra parameter.
Definition: ncbiexpt.hpp:1754
#define NCBI_RETHROW(prev_exception, exception_class, err_code, message)
Generic macro to re-throw an exception.
Definition: ncbiexpt.hpp:737
void destroy(P pT)
@ eUnknown
Definition: app_popup.hpp:72
@ eParam_NoThread
Do not use per-thread values.
Definition: ncbi_param.hpp:418
uint16_t Uint2
2-byte (16-bit) unsigned integer
Definition: ncbitype.h:101
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
std::string CStringUTF8
Definition: ncbistl.hpp:254
EEncodingForm
Helper functions to read plain-text data streams.
Definition: ncbistre.hpp:994
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
static void Pushback(CNcbiIstream &is, CT_CHAR_TYPE *buf, streamsize buf_size, void *del_ptr)
#define NcbiCin
Definition: ncbistre.hpp:542
IO_PREFIX::istream CNcbiIstream
Portable alias for istream.
Definition: ncbistre.hpp:146
EEncodingForm ReadIntoUtf8(CNcbiIstream &input, CStringUTF8 *result, EEncodingForm encoding_form=eEncodingForm_Unknown, EReadUnknownNoBOM what_if_no_bom=eNoBOM_GuessEncoding)
Read all input data from stream and try convert it into UTF8 string.
Definition: ncbistre.cpp:650
bool NcbiStreamCopy(CNcbiOstream &os, CNcbiIstream &is)
Copy the entire contents of stream "is" to stream "os".
Definition: ncbistre.cpp:211
@ eEncodingForm_Utf16Foreign
Stream has UTF16 BOM. Byte order is nonnative for this OS.
Definition: ncbistre.hpp:1006
@ eEncodingForm_Utf8
Stream has UTF8 BOM.
Definition: ncbistre.hpp:1002
@ eEncodingForm_ISO8859_1
Stream has no BOM.
Definition: ncbistre.hpp:998
@ eEncodingForm_Windows_1252
Stream has no BOM.
Definition: ncbistre.hpp:1000
@ eEncodingForm_Unknown
Stream has no BOM.
Definition: ncbistre.hpp:996
@ eEncodingForm_Utf16Native
Stream has UTF16 BOM. Byte order is native for this OS.
Definition: ncbistre.hpp:1004
NCBI_NS_STD::string::size_type SIZE_TYPE
Definition: ncbistr.hpp:132
static string PrintableString(const CTempString str, TPrintableMode mode=fNewLine_Quote|fNonAscii_Passthru)
Get a printable version of the specified string.
Definition: ncbistr.cpp:3944
#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
EUrlEncode
URL-encode flags.
Definition: ncbistr.hpp:3143
static int StringToInt(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to int.
Definition: ncbistr.cpp:630
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
EUrlDecode
URL decode flags.
Definition: ncbistr.hpp:3159
static SIZE_TYPE FindNoCase(const CTempString str, const CTempString pattern, SIZE_TYPE start, SIZE_TYPE end, EOccurrence which=eFirst)
Find the pattern in the specified range of a string using a case insensitive search.
Definition: ncbistr.cpp:2984
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
static string URLDecode(const CTempString str, EUrlDecode flag=eUrlDec_All)
URL-decode string.
Definition: ncbistr.cpp:6205
static void TruncateSpacesInPlace(string &str, ETrunc where=eTrunc_Both)
Truncate whitespace in a string (in-place)
Definition: ncbistr.cpp:3192
string::size_type GetPos(void) const noexcept
Get error position.
Definition: ncbistr.hpp:4457
PNocase_Generic< string > PNocase
Definition: ncbistr.hpp:4902
bool empty(void) const
Return true if the represented string is empty (i.e., the length is zero)
Definition: tempstr.hpp:334
bool AStrEquiv(const Arg1 &x, const Arg2 &y, Pred pr)
Check equivalence of arguments using predicate.
Definition: ncbistr.hpp:5031
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 bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5406
static bool SplitInTwo(const CTempString str, const CTempString delim, string &str1, string &str2, TSplitFlags flags=0)
Split a string into two pieces using the specified delimiters.
Definition: ncbistr.cpp:3545
static unsigned int StringToUInt(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to unsigned int.
Definition: ncbistr.cpp:642
static bool NeedsURLEncoding(const CTempString str, EUrlEncode flag=eUrlEnc_SkipMarkChars)
Check if the string needs the requested URL-encoding.
Definition: ncbistr.cpp:6219
static bool IsIPAddress(const CTempStringEx str)
Check if the string contains a valid IP address.
Definition: ncbistr.cpp:6387
static string URLEncode(const CTempString str, EUrlEncode flag=eUrlEnc_SkipMarkChars)
URL-encode string.
Definition: ncbistr.cpp:6053
@ eNcbiStrings_PHID
Definition: ncbi_strings.h:56
@ fSplit_Truncate
Definition: ncbistr.hpp:2503
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2500
@ eUrlEnc_URIQueryValue
Encode query part of an URI, arg value.
Definition: ncbistr.hpp:3153
@ eUrlEnc_PercentOnly
Convert all non-alphanumeric chars including space and '' to %## format.
Definition: ncbistr.hpp:3146
@ eUrlEnc_URIQueryName
Encode query part of an URI, arg name.
Definition: ncbistr.hpp:3152
@ eUrlEnc_SkipMarkChars
Do not convert chars like '!', '(' etc.
Definition: ncbistr.hpp:3144
@ eUrlEnc_Cookie
Same as SkipMarkChars with encoded ','.
Definition: ncbistr.hpp:3155
@ eUrlDec_All
Decode '+' to space.
Definition: ncbistr.hpp:3160
@ eUrlDec_Percent
Decode only XX.
Definition: ncbistr.hpp:3161
@ eTrunc_End
Truncate trailing whitespace only.
Definition: ncbistr.hpp:2241
int Minute(void) const
Get minute.
Definition: ncbitime.hpp:2277
int DayOfWeek(void) const
Get day of week.
Definition: ncbitime.cpp:1186
bool IsGmtTime(void) const
Definition: ncbitime.hpp:1108
int Year(void) const
Get year.
Definition: ncbitime.hpp:2265
int Day(void) const
Get day.
Definition: ncbitime.hpp:2271
int Hour(void) const
Get hour.
Definition: ncbitime.hpp:2274
int Second(void) const
Get second.
Definition: ncbitime.hpp:2280
int Month(void) const
Get month.
Definition: ncbitime.hpp:2268
void SetQueryString(const string &query, NStr::EUrlEncode encode)
Parse query string, call AddArgument() to store each value.
Definition: ncbi_url.cpp:49
EArgType
Query type flag.
Definition: ncbi_url.hpp:203
@ eArg_Value
Query contains name=value pairs.
Definition: ncbi_url.hpp:204
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
if(yy_accept[yy_current_state])
range(_Ty, _Ty) -> range< _Ty >
constexpr bool empty(list< Ts... >) noexcept
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::SIZE size
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.
Defines the CNcbiApplication and CAppException classes for creating NCBI applications.
static const char * s_PropName[eCgi_NProperties+1]
Definition: ncbicgi.cpp:916
bool s_Is_UTF_8(const string &charset)
Definition: ncbicgi.cpp:1886
static const char * kTrackingVars[]
Definition: ncbicgi.cpp:841
NCBI_PARAM_DECL(string, CGI, cookie_auth_token)
bool s_Is_Windows_1252(const string &charset)
Definition: ncbicgi.cpp:1878
NCBI_PARAM_DEF_EX(string, CGI, Cookie_Name_Banned_Symbols, " ,;=", eParam_NoThread, CGI_COOKIE_NAME_BANNED_SYMBOLS)
static void s_AddEntry(TCgiEntries &entries, const string &name, const string &value, unsigned int position, const string &filename=kEmptyStr, const string &type=kEmptyStr)
Definition: ncbicgi.cpp:961
NCBI_PARAM_DEF(string, CGI, cookie_auth_token, "WebCubbyUser")
bool s_IsZeroTime(const tm &date)
Definition: ncbicgi.cpp:140
EEncodingForm GetCharsetEncodingForm(const string &charset, CCgiEntry::EOnCharsetError on_error)
Definition: ncbicgi.cpp:1893
NCBI_PARAM_ENUM_ARRAY(EDiagSev, CGI, Cookie_Error_Severity)
Definition: ncbicgi.cpp:78
typedef NCBI_PARAM_TYPE(CGI, Cookie_Error_Severity) TCookieErrorSeverity
static bool s_CookieLess(const string &name1, const string &domain1, const string &path1, const string &name2, const string &domain2, const string &path2)
Definition: ncbicgi.cpp:333
bool s_Is_ISO_8859_1(const string &charset)
Definition: ncbicgi.cpp:1856
NCBI_PARAM_ENUM_DEF_EX(EDiagSev, CGI, Cookie_Error_Severity, eDiag_Error, eParam_NoThread, CGI_COOKIE_ERROR_SEVERITY)
const char * s_GetCookieNameBannedSymbols(void)
Definition: ncbicgi.cpp:492
static const tm kZeroTime
Definition: ncbicgi.cpp:138
NCBI_PARAM_ENUM_DECL(EDiagSev, CGI, Cookie_Error_Severity)
static CTempString x_FirstWord(const CTempStringEx &forward)
Definition: ncbicgi.cpp:1177
#define STDIN_FILENO
Definition: ncbicgi.cpp:61
int isprint(Uchar c)
Definition: ncbictype.hpp:67
Defines unified interface to application:
#define HTTP_EOL
Definition: ncbistre.hpp:120
Defines: CTimeFormat - storage class for time format.
@ eRead
Definition: ns_types.hpp:56
#define count
Defines CRequestContext class for NCBI C++ diagnostic API.
static SLJIT_INLINE sljit_ins msg(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
static CNamedPipeClient * client
Definition: type.c:6
#define _TROUBLE
#define _ASSERT
static wxAcceleratorEntry entries[3]
Modified on Fri Sep 20 14:57:23 2024 by modify_doxy.py rev. 669887