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

Go to the SVN repository for this file.

1 /* $Id: user_agent.cpp 86566 2019-05-24 13:56:42Z ivanov $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Vladimir Ivanov
27  *
28  * File Description: API to parse user agent strings
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <cgi/user_agent.hpp>
34 #include <cgi/cgiapp.hpp>
35 #include <cgi/cgictx.hpp>
36 
37 
39 
40 
41 //////////////////////////////////////////////////////////////////////////////
42 //
43 // CCgiUserAgent
44 //
45 
46 // Macro to check flags bits
47 #define F_ISSET(mask) ((m_Flags & (mask)) == (mask))
48 
49 // Conversion macro for compare/find strings
50 #define USTR(str) (F_ISSET(fNoCase) ? s_ToLower(str) : (str))
51 
52 // Delimiters to separate pattern values (see IsBot(), IsMobileDevice(), IsTableDevice())
53 const char* kSingleLinePatternDelimiters = " ;\t|~";
54 const char* kMultiLinePatternDelimiters = "\n";
55 
56 inline string s_ToLower(string str)
57 {
59  return str;
60 }
61 
63 {
64  m_Flags = flags;
67  string user_agent;
68  if (cgi_app) {
69  user_agent = cgi_app->GetContext().GetRequest()
71  } else if (ncbi_app) {
72  user_agent = ncbi_app->GetEnvironment().Get("HTTP_USER_AGENT");
73  } else {
74  user_agent = getenv("HTTP_USER_AGENT");
75  }
76  if ( !user_agent.empty() ) {
77  x_Parse(user_agent);
78  }
79 }
80 
81 CCgiUserAgent::CCgiUserAgent(const string& user_agent, TFlags flags)
82 {
83  m_Flags = flags;
84  x_Parse(user_agent);
85 }
86 
88 {
89  m_UserAgent.erase();
92  m_BrowserVersion.SetVersion(-1, -1, -1);
94  m_EngineVersion.SetVersion(-1, -1, -1);
95  m_MozillaVersion.SetVersion(-1, -1, -1);
97  m_DeviceFlags = 0;
98 }
99 
100 void CCgiUserAgent::Reset(const string& user_agent)
101 {
102  x_Parse(user_agent);
103 }
104 
105 
106 bool CCgiUserAgent::IsBrowser(void) const
107 {
108  switch ( GetEngine() ) {
109  case eEngine_IE:
110  case eEngine_Edge:
111  case eEngine_Gecko:
112  case eEngine_KHTML:
113  case eEngine_WebKit:
114  case eEngine_Blink:
115  return true;
116  case eEngine_Bot:
117  return false;
118  case eEngine_Unknown:
119  ; // check browser, see below
120  }
121  switch ( GetBrowser() ) {
122  // Browsers
123  case eiCab:
124  case eKonqueror:
125  case eLynx:
126  case ePapers:
127  case eOregano:
128  case eOpera:
129  case eW3m:
130  // Mobile devices
131  case eAirEdge:
132  case eAvantGo:
133  case eBlackberry:
134  case eDoCoMo:
135  case eEudoraWeb:
136  case eMinimo:
137  case eNetFront:
138  case eOpenWave:
139  case eOperaMini:
140  case eOperaMobile:
141  case ePIE:
142  case ePlucker:
143  case ePocketLink:
144  case ePolaris:
145  case eReqwireless:
146  case eSEMCBrowser:
147  case eTelecaObigo:
148  case euZardWeb:
149  case eVodafone:
150  case eXiino:
151  return true;
152  default:
153  ; // false
154  }
155  return false;
156 }
157 
158 
159 // Declare parameters to get additional bots/devices names,
160 // or names that should be excluded from the check.
161 
162 NCBI_PARAM_DECL(string, CGI, Bots);
163 NCBI_PARAM_DEF (string, CGI, Bots, "");
164 NCBI_PARAM_DECL(string, CGI, NotBots);
165 NCBI_PARAM_DEF (string, CGI, NotBots, "");
166 
167 NCBI_PARAM_DECL(string, CGI, PhoneDevices);
168 NCBI_PARAM_DEF (string, CGI, PhoneDevices, "");
169 NCBI_PARAM_DECL(string, CGI, NotPhoneDevices);
170 NCBI_PARAM_DEF (string, CGI, NotPhoneDevices, "");
171 
172 NCBI_PARAM_DECL(string, CGI, TabletDevices);
173 NCBI_PARAM_DEF (string, CGI, TabletDevices, "");
174 NCBI_PARAM_DECL(string, CGI, NotTabletDevices);
175 NCBI_PARAM_DEF (string, CGI, NotTabletDevices, "");
176 
177 NCBI_PARAM_DECL(string, CGI, MobileDevices);
178 NCBI_PARAM_DEF (string, CGI, MobileDevices, "");
179 NCBI_PARAM_DECL(string, CGI, NotMobileDevices);
180 NCBI_PARAM_DEF (string, CGI, NotMobileDevices, "");
181 
182 
183 // Helper method to check devices/bots against external patterns.
184 // @sa x_Parse, IsPhoneDevice, IsMobileDevice, IsTabletDevice, IsBot
185 
186 enum EPattern {
190  eBot
191 };
192 
193 
194 // NOTE: Tablets must be checked before phones!!!
195 // Phones -- almost all other mobile devices, that are not tablets
196 
197 bool CCgiUserAgent::x_CheckPattern(int /*EPattern*/ what,
198  bool current_status, bool use_patterns,
199  const string& include_patterns,
200  const string& exclude_patterns) const
201 {
202  string external_patterns;
203 
204  // Default check
205 
206  switch (what) {
207  //------------------------------------------------------------------------
208  case ePhone:
209  switch ( GetPlatform() ) {
210  case ePlatform_Palm:
211  case ePlatform_Symbian:
212  case ePlatform_WindowsCE:
213  current_status = true;
214  break;
215  default:
216  if (m_UserAgent.find(USTR("iPhone")) != NPOS || // Apple iPhone
217  m_UserAgent.find(USTR("iPod")) != NPOS || // Apple iPod
218  m_UserAgent.find(USTR("Nokia")) != NPOS || // Nokia
219  m_UserAgent.find(USTR("SonyEricsson")) != NPOS || // SonyEricsson
220  m_UserAgent.find(USTR("J-PHONE")) != NPOS ) { // Ex J-Phone, now Vodafone Live!
221  current_status = true;
222  }
223  break;
224  }
225  if (!current_status) {
226  // Some browsers developed especially for phones on PDA
227  switch ( GetBrowser() ) {
228  case eBlackberry:
229  case eDoCoMo:
230  case eOperaMini:
231  case ePIE:
232  case eReqwireless:
233  case eSEMCBrowser:
234  current_status = true;
235  default:
236  break;
237  }
238  }
239  break;
240 
241  //------------------------------------------------------------------------
242  case eTablet:
243  if (m_UserAgent.find(USTR("Tablet;")) != NPOS || // Tablet device
244  m_UserAgent.find(USTR(" Tablet ")) != NPOS || // Tablet device
245  m_UserAgent.find(USTR("iPad;")) != NPOS || // Apple iPad
246  m_UserAgent.find(USTR("Nexus 7")) != NPOS || // Google Nexus 7
247  m_UserAgent.find(USTR("Nexus 10")) != NPOS ) { // Google Nexus 10
248  current_status = true;
249  }
250  // Google Chrome on tablet devices
252  m_UserAgent.find(USTR("Mobile")) == NPOS ) {
253  current_status = true;
254  }
255  break;
256 
257  //------------------------------------------------------------------------
258  case eMobile:
259  switch ( GetPlatform() ) {
260  case ePlatform_Android:
261  case ePlatform_Palm:
262  case ePlatform_Symbian:
263  case ePlatform_WindowsCE:
265  current_status = true;
266  break;
267  default:
268  if (m_UserAgent.find(USTR("Mobile;")) != NPOS || // Mobile device
269  m_UserAgent.find(USTR("LGE-")) != NPOS || // LG
270  m_UserAgent.find(USTR("LG/U")) != NPOS || // LG
271  m_UserAgent.find(USTR("Maemo")) != NPOS || // Maemo
272  m_UserAgent.find(USTR("MOT-")) != NPOS || // Motorola
273  m_UserAgent.find(USTR("Samsung")) != NPOS || // Samsung
274  m_UserAgent.find(USTR("HP iPAQ")) != NPOS ||
275  m_UserAgent.find(USTR("UP.Link")) != NPOS ||
276  m_UserAgent.find(USTR("PlayStation Portable")) != NPOS) {
277  current_status = true;
278  }
279  break;
280  }
281  break;
282 
283  //------------------------------------------------------------------------
284  case eBot:
285  // Just check external patterns below
286  break;
287 
288  default:
289  _TROUBLE;
290  }
291 
292  // Use check against patterns only if specified
293 
294  if (!use_patterns) {
295  return current_status;
296  }
297  switch ((EPattern)what) {
298  case ePhone:
299  external_patterns = current_status ?
300  USTR(NCBI_PARAM_TYPE(CGI,NotPhoneDevices)::GetDefault()) :
301  USTR(NCBI_PARAM_TYPE(CGI,PhoneDevices)::GetDefault());
302  break;
303  case eTablet:
304  external_patterns = current_status ?
305  USTR(NCBI_PARAM_TYPE(CGI,NotTabletDevices)::GetDefault()) :
306  USTR(NCBI_PARAM_TYPE(CGI,TabletDevices)::GetDefault());
307  break;
308  case eMobile:
309  external_patterns = current_status ?
310  USTR(NCBI_PARAM_TYPE(CGI,NotMobileDevices)::GetDefault()) :
311  USTR(NCBI_PARAM_TYPE(CGI,MobileDevices)::GetDefault());
312  break;
313  case eBot:
314  external_patterns = current_status ?
315  USTR(NCBI_PARAM_TYPE(CGI,NotBots)::GetDefault()) :
316  USTR(NCBI_PARAM_TYPE(CGI,Bots)::GetDefault());
317  break;
318  default:
319  // unreachable
320  return current_status;
321  }
322 
323  list<string> patterns;
324  // External patterns
325  if ( !external_patterns.empty() ) {
326  if (external_patterns.find_first_of(kMultiLinePatternDelimiters) != NPOS) {
329  } else {
332  }
333  }
334  // User-defined patterns
335  if (current_status) {
336  if ( !exclude_patterns.empty() ) {
337  if (external_patterns.find_first_of(kMultiLinePatternDelimiters) != NPOS) {
340  } else {
343  }
344  }
345  } else {
346  if ( !include_patterns.empty() ) {
347  if (external_patterns.find_first_of(kMultiLinePatternDelimiters) != NPOS) {
350  } else {
353  }
354  }
355  }
356  // Search patterns
357  ITERATE(list<string>, i, patterns) {
358  if ( m_UserAgent.find(*i) != NPOS ) {
359  return !current_status;
360  }
361  }
362  return current_status;
363 }
364 
365 
367  const string& include_patterns,
368  const string& exclude_patterns) const
369 {
370  bool is_bot = false;
371 
372  // Default check
373  if (GetEngine() == eEngine_Bot) {
374  if (flags == fBotAll) {
375  is_bot = true;
376  } else {
377  TBotFlags need_flag = 0;
378  switch ( GetBrowser() ) {
379  case eCrawler:
380  need_flag = fBotCrawler;
381  break;
382  case eOfflineBrowser:
383  need_flag = fBotOfflineBrowser;
384  break;
385  case eScript:
386  need_flag = fBotScript;
387  break;
388  case eLinkChecker:
389  need_flag = fBotLinkChecker;
390  break;
391  case eWebValidator:
392  need_flag = fBotWebValidator;
393  break;
394  default:
395  break;
396  }
397  if ( flags & need_flag ) {
398  is_bot = true;
399  }
400  }
401  }
402 
403  // Make additional checks
405  include_patterns.empty() && exclude_patterns.empty()) {
406  // Already got result on parsing step
407  return GetEngine() == eEngine_Bot;
408  }
409  is_bot = x_CheckPattern(eBot, is_bot, true, include_patterns, exclude_patterns);
410  return is_bot;
411 }
412 
413 
415  const string& exclude_patterns) const
416 {
418  include_patterns.empty() && exclude_patterns.empty()) {
419  // Already got result on parsing step
420  return (m_DeviceFlags & fDevice_Mobile) > 0;
421  }
422  bool is_phone = (m_DeviceFlags & fDevice_Phone) > 0;
423  is_phone = x_CheckPattern(ePhone, is_phone, true, include_patterns, exclude_patterns);
424  return is_phone;
425 }
426 
427 
429  const string& exclude_patterns) const
430 {
432  include_patterns.empty() && exclude_patterns.empty()) {
433  // Already got result on parsing step
434  return (m_DeviceFlags & fDevice_Tablet) > 0;
435  }
436  bool is_tablet = (m_DeviceFlags & fDevice_Tablet) > 0;
437  is_tablet = x_CheckPattern(eTablet, is_tablet, true, include_patterns, exclude_patterns);
438  return is_tablet;
439 }
440 
441 
443  const string& exclude_patterns) const
444 {
446  include_patterns.empty() && exclude_patterns.empty()) {
447  // Already have an result
448  return (m_DeviceFlags & fDevice_Mobile) > 0;
449  }
450  bool is_mobile = (m_DeviceFlags & fDevice_Mobile) > 0;
451  // Check on phones and tablets first (almost to check external patterns)
452  is_mobile = x_CheckPattern(ePhone, is_mobile, true);
453  is_mobile = x_CheckPattern(eTablet, is_mobile, true);
454  is_mobile = x_CheckPattern(eMobile, is_mobile, true, include_patterns, exclude_patterns);
455  return is_mobile;
456 }
457 
458 
459 //
460 // Mozilla-compatible user agent always have next format:
461 // AppProduct (AppComment) * VendorProduct [(VendorComment)]
462 //
463 
464 // Search flags
466  fAppProduct = (1<<1),
467  fAppComment = (1<<2),
468  fVendorProduct = (1<<3),
469  fVendorComment = (1<<4),
473  fAny = fApp | fVendor
474 };
475 typedef int TUASearchFlags; // Binary OR of "ESearchFlags"
476 
477 
478 // Browser search information
479 struct SBrowser {
480  CCgiUserAgent::EBrowser type; // Browser type
481  const char* name; // Browser name
482  const char* key; // Search key
484  CCgiUserAgent::EBrowserPlatform platform; // Platform type (almost for mobile devices)
485  TUASearchFlags flags; // Search flags
486 };
487 
488 
489 // Browser search table (the order does matter!)
490 const SBrowser s_Browsers[] = {
491 
492  // Bots (crawlers, offline-browsers, checkers, validators, ...)
493  // Check bots first, because they often sham to be IE or Mozilla.
494 
495  // type name key engine platform search flags
499  { CCgiUserAgent::eCrawler, "Advanced Email Extractor", "Advanced Email Extractor", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppComment },
535  { CCgiUserAgent::eCrawler, "EmeraldShield.com", "www.emeraldshield.com", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppComment },
540  { CCgiUserAgent::eCrawler, "Facebook External Hit", "facebookexternalhit", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fApp },
541  { CCgiUserAgent::eCrawler, "FAST Enterprise Crawler", "FAST Enterprise Crawler", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
546  { CCgiUserAgent::eCrawler, "FusionBot", "www.galaxy.com/info/crawler", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppComment },
556  { CCgiUserAgent::eCrawler, "Google AdSense", "Mediapartners-Google", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAny },
565  { CCgiUserAgent::eCrawler, "Iltrovatore-Setaccio", "Iltrovatore-Setaccio", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
566  { CCgiUserAgent::eCrawler, "InfoSeek Sidewinder", "InfoSeek Sidewinder", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
578  { CCgiUserAgent::eCrawler, "Maxamine Web Analyst", "maxamine.com", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAny },
587  { CCgiUserAgent::eCrawler, "MS Sharepoint Portal Server","MS Search", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fApp },
609  { CCgiUserAgent::eCrawler, "Screaming Frog SEO Spider","Screaming Frog SEO Spider",CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAny },
615  { CCgiUserAgent::eCrawler, "Sensis Web Crawler", "Sensis Web Crawler", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
633  { CCgiUserAgent::eCrawler, "Thumbnail.CZ robot", "Thumbnail.CZ robot", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
650  { CCgiUserAgent::eCrawler, "Xaldon_WebSpider", "Xaldon_WebSpider", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAny },
659 
663 
670 
674  { CCgiUserAgent::eLinkChecker, "Html Link Validator", "www.lithopssoft.com", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAny },
679  { CCgiUserAgent::eLinkChecker, "LinksManager.com_bot", "linksmanager.com", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fApp },
683  { CCgiUserAgent::eLinkChecker, "REL Link Checker Lite", "REL Link Checker Lite", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
684  { CCgiUserAgent::eLinkChecker, "SafariBookmarkChecker", "SafariBookmarkChecker", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
686  { CCgiUserAgent::eLinkChecker, "Vivante Link Checker", "www.vivante.com", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAny },
690 
697 
701  { CCgiUserAgent::eScript, "Jakarta Commons HttpClient","Apache-HttpClient", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAny },
702  { CCgiUserAgent::eScript, "Jakarta Commons HttpClient","Jakarta Commons-HttpClient",CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAny },
709  { CCgiUserAgent::eScript, "Microsoft Data Access", "Microsoft Data Access", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
710  { CCgiUserAgent::eScript, "Microsoft URL Control", "Microsoft URL Control", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
711  { CCgiUserAgent::eScript, "Microsoft-ATL-Native", "Microsoft-ATL-Native", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct },
715 
716  // Mobile devices
717 
745 
746  // ???
747 
749 
750  // Gecko-based
751 
773 
774  // IE-based
775 
777  { CCgiUserAgent::eAOL, "AOL Browser", "America Online Browser", CCgiUserAgent::eEngine_IE, CCgiUserAgent::ePlatform_Unknown, fAppComment },
786 
787  // Check IE last, after all IE-based browsers
788  { CCgiUserAgent::eIE, "Internet Explorer", "Internet Explorer", CCgiUserAgent::eEngine_IE, CCgiUserAgent::ePlatform_Unknown, fProduct },
790 
791  // AppleWebKit/KHTML-based (engine detected automatically)
792 
804 
805  // Other
806 
818  { CCgiUserAgent::eNagios, "check_http (nagios-plugins)","check_http", CCgiUserAgent::eEngine_Bot, CCgiUserAgent::ePlatform_Unknown, fAppProduct }
819 
820  // We have special case to detect Mozilla/Mozilla-based
821 };
822 const size_t kBrowsers = sizeof(s_Browsers)/sizeof(s_Browsers[0]);
823 
824 
825 // Returns position first non-digit in the string, or string length.
826 SIZE_TYPE s_SkipDigits(const string& str, SIZE_TYPE pos)
827 {
828  SIZE_TYPE len = str.length();
829  while ( pos < len && isdigit((unsigned char)str[pos]) ) {
830  pos++;
831  }
832  _ASSERT( pos <= len );
833  return pos;
834 }
835 
836 void s_ParseVersion(const string& token, SIZE_TYPE start_pos,
838 {
839  SIZE_TYPE len = token.length();
840  if ( start_pos >= len ) {
841  return;
842  }
843  // Some browsers have 'v' before version number
844  if ( token[start_pos] == 'v' ) {
845  start_pos++;
846  }
847  if ( (start_pos >= len) ||
848  !isdigit((unsigned char)token[start_pos]) ) {
849  return;
850  }
851  // Init version numbers
852  int major = -1;
853  int minor = -1;
854  int patch = -1;
855 
856  // Parse version
857  SIZE_TYPE pos = s_SkipDigits(token, start_pos + 1);
858  if ( (pos < len-1) && (token[pos] == '.') ) {
859  minor = atoi(token.c_str() + pos + 1);
860  pos = s_SkipDigits(token, pos + 1);
861  if ( (pos < len-1) && (token[pos] == '.') ) {
862  patch = atoi(token.c_str() + pos + 1);
863  }
864  }
865  major = atoi(token.c_str() + start_pos);
866  // Store version
867  version->SetVersion(major, minor, patch);
868 }
869 
870 
871 void CCgiUserAgent::x_Parse(const string& user_agent)
872 {
873  string search;
874 
875  // Initialization
876  x_Init();
877  m_UserAgent = USTR(NStr::TruncateSpaces(user_agent));
878  SIZE_TYPE len = m_UserAgent.length();
879 
880  // Check on bots using user-provided external patterns
881  if ( F_ISSET(fUseBotPatterns) ) {
882  if (x_CheckPattern(eBot, false, true)) {
884  return;
885  }
886  }
887  // Check on bots using internal table
889  return;
890  }
891 
892  // Expecting regular non-bot user agent below.
893  // NOTE:
894  // For bots we don't parse any additional info like platform or OS anymore,
895  /// because modern user agent strings spammed with keywords in all departments,
896  // even by Google.
897 
898  // Check VendorProduct first
899 
900  string vendor_product;
901  SIZE_TYPE pos;
902 
903  if (m_Browser == eUnknown) {
904  pos = m_UserAgent.rfind(")", NPOS);
905  if (pos != NPOS) {
906  // Have VendorProduct only
907  if (pos < len - 1) {
908  vendor_product = m_UserAgent.substr(pos + 1);
909  x_ParseToken(vendor_product, fVendorProduct);
910  }
911  // Have VendorComment also, cut it off before parsing VendorProduct token
912  else if ((pos == len - 1) &&
913  (len >= 5 /* min possible for string with VendorComment */)) {
914  // AppComment token should be present also
915  pos = m_UserAgent.rfind(")", pos - 1);
916  if (pos != NPOS) {
917  pos++;
918  SIZE_TYPE pos_comment = m_UserAgent.find("(", pos);
919  if (pos_comment != NPOS) {
920  vendor_product = m_UserAgent.substr(pos, pos_comment - pos);
921  x_ParseToken(vendor_product, fVendorProduct);
922  }
923  }
924  }
925  }
926  }
927 
928  // Probably we already have browser name and version, but
929  // try to tune up it, and detect Mozilla and engine versions (below).
930 
931  // eSafariMobile -- special case.
932  // Sometimes Mobile Safari can be specified as "... Version/x.x.x Mobile/xxxxxx Safari/x.x.x".
933  if ( m_Browser == eSafari ) {
934  search = USTR(" Mobile/");
935  if (m_UserAgent.find(search) != NPOS) {
938  }
939  }
940 
941  // Handles browsers declaring Mozilla-compatible
942  if ( NStr::MatchesMask(m_UserAgent, USTR("Mozilla/*")) ) {
943  // Get Mozilla version
944  search = "Mozilla/";
945  s_ParseVersion(m_UserAgent, search.length(), &m_MozillaVersion);
946 
947  // Get Mozilla engine version
948  search = "; rv:";
949  pos = m_UserAgent.find(search);
950  if (pos != NPOS) {
952  pos += search.length();
954  }
955 
956  // Ignore next code if the browser type already detected
957  if ( m_Browser == eUnknown ) {
958 
959  // Check Mozilla-compatible
960  if ( NStr::MatchesMask(m_UserAgent, USTR("Mozilla/*(compatible;*")) ) {
961  // Browser.
963  // Try to determine real browser using second entry
964  // in the AppComment token.
965  search = "(compatible;";
966  pos = m_UserAgent.find(search);
967  if (pos != NPOS) {
968  pos += search.length();
969  // Extract remains of AppComment
970  // (can contain nested parenthesis)
971  int par = 1;
972  SIZE_TYPE end = pos;
973  while (end < len && par) {
974  if ( m_UserAgent[end] == ')' )
975  par--;
976  else if ( m_UserAgent[end] == '(' )
977  par++;
978  end++;
979  }
980  if ( end <= len ) {
981  string token = m_UserAgent.substr(pos, end-pos-1);
982  x_ParseToken(token, fAppComment);
983  }
984  }
985  // Real browser name not found,
986  // continue below to check product name
987  }
988 
989  // Handles the real Mozilla (or old Netscape if version < 5.0)
990  else {
992  // If product version < 5.0 -- we have Netscape
993  int major = m_BrowserVersion.GetMajor();
994  if ( (major < 0) || (major < 5) ) {
996  m_BrowserName = "Netscape";
997  } else {
999  m_BrowserName = "Mozilla";
1001  }
1002  }
1003  }
1004  }
1005 
1006  // If none of the above matches, use first product token in list
1007 
1008  if ( m_Browser == eUnknown ) {
1010  }
1011 
1012  // Check Trident engine version and IE v11 and up
1013  search = USTR(" Trident/");
1014  pos = m_UserAgent.find(search);
1015  if (pos != NPOS) {
1016  m_Browser = eIE;
1017  m_Engine = eEngine_IE;
1018  m_BrowserName = "Internet Explorer";
1020  pos += search.length();
1022  }
1023 
1024  // Microsoft Edge
1025  // Temporary: set browser/engine version to the same value
1026  if (m_Engine == eEngine_Edge) {
1028  }
1029 
1030  // Try to get browser version for IE-based browsers or old IE
1031  if (m_Engine == eEngine_IE &&
1032  m_BrowserVersion.GetMajor() == -1) {
1034  search = USTR(" MSIE ");
1035  pos = m_UserAgent.find(search);
1036  if (pos != NPOS) {
1037  pos += search.length();
1038  s_ParseVersion(m_UserAgent, pos, &v);
1039  }
1040  // Set browser version for IE only, don't change for IE-based browsers
1041  if (m_Browser == eIE) {
1042  m_BrowserVersion = v;
1043  }
1044  }
1045 
1046  // Determine engine for new Netscape's
1047  if ( m_Browser == eNetscape ) {
1048  // Netscape 6.0 November 14, 2000 (based on Mozilla 0.7)
1049  // Netscape 6.01 February 9, 2001(based on Mozilla 0.7)
1050  // Netscape 6.1 August 8, 2001 (based on Mozilla 0.9.2.1)
1051  // Netscape 6.2 October 30, 2001 (based on Mozilla 0.9.4.1)
1052  // Netscape 6.2.1 (based on Mozilla 0.9.4.1)
1053  // Netscape 6.2.2 (based on Mozilla 0.9.4.1)
1054  // Netscape 6.2.3 May 15, 2002 (based on Mozilla 0.9.4.1)
1055  // Netscape 7.0 August 29, 2002 (based on Mozilla 1.0.1)
1056  // Netscape 7.01 December 10, 2002 (based on Mozilla 1.0.2)
1057  // Netscape 7.02 February 18, 2003 (based on Mozilla 1.0.2)
1058  // Netscape 7.1 June 30, 2003 (based on Mozilla 1.4)
1059  // Netscape 7.2 August 17, 2004 (based on Mozilla 1.7)
1060  // Netscape Browser 0.5.6+ November 30, 2004 (based on Mozilla Firefox 0.9.3)
1061  // Netscape Browser 0.6.4 January 7, 2005 (based on Mozilla Firefox 1.0)
1062  // Netscape Browser 0.9.4 (8.0 Pre-Beta) February 17, 2005 (based on Mozilla Firefox 1.0)
1063  // Netscape Browser 0.9.5 (8.0 Pre-Beta) February 23, 2005 (based on Mozilla Firefox 1.0)
1064  // Netscape Browser 0.9.6 (8.0 Beta) March 3, 2005 (based on Mozilla Firefox 1.0)
1065  // Netscape Browser 8.0 May 19, 2005 (based on Mozilla Firefox 1.0.3)
1066  // Netscape Browser 8.0.1 May 19, 2005 (based on Mozilla Firefox 1.0.4)
1067  // Netscape Browser 8.0.2 June 17, 2005 (based on Mozilla Firefox 1.0.4)
1068  // Netscape Browser 8.0.3.1 July 25, 2005 (based on Mozilla Firefox 1.0.6)
1069  // Netscape Browser 8.0.3.3 August 8, 2005 (based on Mozilla Firefox 1.0.6)
1070  // Netscape Browser 8.0.4 October 19, 2005 (based on Mozilla Firefox 1.0.7)
1071 
1072  int major = m_BrowserVersion.GetMajor();
1073  if ( major > 0 ) {
1074  if ( (major < 1) || (major > 5) ) {
1076  }
1077  }
1078  }
1079 
1080  // Try to get engine version for KHTML/WebKit-based browsers
1081 
1082  if (m_Engine != eEngine_IE && m_Engine != eEngine_Edge)
1083  {
1084  search = USTR(" AppleWebKit/");
1085  pos = m_UserAgent.find(search);
1086  if (pos == NPOS) {
1087  search = USTR(" WebKit/");
1088  pos = m_UserAgent.find(search);
1089  }
1090  if (pos != NPOS) {
1092  pos += search.length();
1094  // AppleWebKit/537.36
1095  if (m_EngineVersion == CVersionInfo(537,36,-1) ) {
1097  }
1098  } else {
1099  search = USTR(" KHTML/");
1100  pos = m_UserAgent.find(search);
1101  if (pos != NPOS) {
1103  pos += search.length();
1105  } else {
1106  search = USTR("KHTML,");
1107  pos = m_UserAgent.find(search);
1108  if (pos != NPOS) {
1110  m_EngineVersion.SetVersion(-1, -1, -1);
1111  }
1112  }
1113  }
1114  }
1115 
1116  // Hack for some browsers (like Safari) that use Version/x.x.x rather than
1117  // Safari/x.x.x for real browser version (for Safari, numbers after browser
1118  // name represent a build version).
1119  //
1120  // Check its VendorProduct only!
1121 
1122  if ( m_Browser != eUnknown && !vendor_product.empty() ) {
1123  // VendorProduct token is not empty
1124  search = USTR(" Version/");
1125  pos = vendor_product.find(search);
1126  if (pos != NPOS) {
1127  pos += search.length();
1128  s_ParseVersion(vendor_product, pos, &m_BrowserVersion);
1129  } else {
1130  // Safari (old version) -- try to get browser version
1131  // depending on engine (WebKit) version (very approximately).
1132  if ( m_Browser == eSafari &&
1134  // See http://www.useragentstring.com/pages/Safari/
1135  int rev = m_EngineVersion.GetMajor();
1136  if (rev < 85 ) {
1137  m_BrowserVersion.SetVersion(-1,-1,-1); // too early version
1138  } else if (rev < 124 ) {
1139  m_BrowserVersion.SetVersion(1,0,-1); // 1.0
1140  } else if (rev < 312 ) {
1141  m_BrowserVersion.SetVersion(1,2,-1); // 1.2
1142  } else if (rev < 412 ) {
1143  m_BrowserVersion.SetVersion(1,3,-1); // 1.3
1144  } else if (rev < 420 ) {
1145  m_BrowserVersion.SetVersion(2,0,-1); // 2.0.x
1146  } else if (rev < 525 ) {
1147  m_BrowserVersion.SetVersion(3,0,-1); // 3.0.x
1148  } else if (rev < 528 ) {
1149  // We should never get here, because all Safari
1150  // newer that 3.x should have "Version/" tag.
1151  m_BrowserVersion.SetVersion(3,-1,-1); // 3.x
1152  }
1153  }
1154  }
1155  }
1156 
1157  // Very crude algorithm to get platform and device types...
1158  // See also x_ParseToken() for specific platform types from the table.
1159 
1160  // Check mobile devices first (more precise for ePlatform_MobileDevice)
1161  if ( m_Platform == ePlatform_Unknown ||
1163  if (m_UserAgent.find(USTR("Android")) != NPOS) {
1165  } else
1166  if (m_UserAgent.find(USTR("PalmSource")) != NPOS ||
1167  m_UserAgent.find(USTR("PalmOS")) != NPOS ||
1168  m_UserAgent.find(USTR("webOS")) != NPOS) {
1170  } else
1171  if (m_UserAgent.find(USTR("Symbian")) != NPOS) {
1173  } else
1174  if (m_UserAgent.find(USTR("Windows CE")) != NPOS ||
1175  m_UserAgent.find(USTR("IEMobile")) != NPOS ||
1176  m_UserAgent.find(USTR("Window Mobile"))!= NPOS) {
1178  }
1179  }
1180  // Make additional check if platform is still undefined
1181  if ( m_Platform == ePlatform_Unknown ) {
1182  if (m_UserAgent.find(USTR("MacOS")) != NPOS ||
1183  m_UserAgent.find(USTR("Mac OS")) != NPOS ||
1184  m_UserAgent.find(USTR("Macintosh")) != NPOS ||
1185  m_UserAgent.find(USTR("Mac_PowerPC")) != NPOS) {
1187  } else
1188  if (m_UserAgent.find(USTR("SunOS")) != NPOS ||
1189  m_UserAgent.find(USTR("Linux")) != NPOS ||
1190  m_UserAgent.find(USTR("FreeBSD")) != NPOS ||
1191  m_UserAgent.find(USTR("NetBSD")) != NPOS ||
1192  m_UserAgent.find(USTR("OpenBSD")) != NPOS ||
1193  m_UserAgent.find(USTR("IRIX")) != NPOS ||
1194  // ??? could be iOS as well
1195  //m_UserAgent.find(USTR("Darwin")) != NPOS ||
1196  m_UserAgent.find(USTR("nagios-plugins")) != NPOS) {
1198  } else
1199  // Check Windows last, its signature is too short
1200  if (m_UserAgent.find(USTR("Win")) != NPOS) {
1202  }
1203  }
1204 
1205  // Check device type.
1206 
1207  // Tablet or phone
1210  } else
1213  }
1214  // And separate check on "mobile device" if not a phone/tablet
1217  }
1218  // If detected some mobile device via patterns, set platform type accordingly
1219  if ( m_DeviceFlags & fDevice_Mobile ) {
1220  switch (m_Platform) {
1221  case ePlatform_Unknown:
1222  case ePlatform_Windows:
1223  case ePlatform_Mac:
1224  case ePlatform_Unix:
1226  //break;
1227  default:
1228  break;
1229  }
1230  }
1231 
1232  return;
1233 }
1234 
1235 
1236 bool CCgiUserAgent::x_ParseToken(const string& token, int where, EBrowserEngine engine)
1237 {
1238  SIZE_TYPE len = token.length();
1239  // Check all user agent signatures
1240  for (size_t i = 0; i < kBrowsers; i++) {
1241  if ( !(s_Browsers[i].flags & where) ) {
1242  continue;
1243  }
1244  if ( engine != eEngine_Unknown) {
1245  // check specific engine only
1246  if (!(s_Browsers[i].engine == engine) ) {
1247  continue;
1248  }
1249  }
1250  string key = USTR(s_Browsers[i].key);
1251  SIZE_TYPE pos = token.find(key);
1252  if ( pos != NPOS ) {
1253  pos += key.length();
1254  // Browser
1258  // Set platform only if it is unambiguously defined for this browser
1259  if (s_Browsers[i].platform != ePlatform_Unknown) {
1261  }
1262  // Version.
1263  // Second entry in token after space or '/'.
1264  if ( (pos < len-1 /* have at least 1 symbol before EOL */) &&
1265  ((token[pos] == ' ') || (token[pos] == '/')) ) {
1266  s_ParseVersion(token, pos+1, &m_BrowserVersion);
1267  }
1268  // User agent found and parsed
1269  return true;
1270  }
1271  }
1272  // Not found
1273  return false;
1274 }
1275 
1276 
1278 {
1279  switch ( GetEngine() ) {
1280  case eEngine_Unknown : return "Unknown";
1281  case eEngine_IE : return "Trident";
1282  case eEngine_Edge : return "Edge";
1283  case eEngine_Gecko : return "Gecko";
1284  case eEngine_KHTML : return "KHTML";
1285  case eEngine_WebKit : return "WebKit";
1286  case eEngine_Blink : return "Blink";
1287  case eEngine_Bot : return "Bot";
1288  }
1289  _TROUBLE;
1290  return kEmptyStr;
1291 }
1292 
1293 
1295 {
1296  switch ( GetPlatform() ) {
1297  case ePlatform_Unknown : return "Unknown";
1298  case ePlatform_Windows : return "Windows";
1299  case ePlatform_Mac : return "Mac";
1300  case ePlatform_Unix : return "Unix";
1301  case ePlatform_Android : return "Android";
1302  case ePlatform_Palm : return "Palm";
1303  case ePlatform_Symbian : return "Symbian";
1304  case ePlatform_WindowsCE : return "WindowsCE";
1305  case ePlatform_MobileDevice : return "MobileDevice";
1306  }
1307  _TROUBLE;
1308  return kEmptyStr;
1309 }
1310 
1311 
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:264
CVersionInfo –.
static uch flags
static const char * str(char *buf, int n)
Definition: stats.c:84
const CNcbiEnvironment & GetEnvironment(void) const
Get the application's cached environment.
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
const CCgiContext & GetContext(void) const
Get current server context. Throw exception if the context is not set.
Definition: cgiapp.hpp:78
const CCgiRequest & GetRequest(void) const
Definition: cgictx.hpp:374
static CCgiApplication * Instance(void)
Singleton.
Definition: cgiapp.cpp:457
CGI
Definition: cgiapp.hpp:685
const string & GetProperty(ECgiProp prop) const
Get value of a "standard" property (return empty string if not defined)
Definition: ncbicgi.cpp:1432
@ eCgi_HttpUserAgent
Definition: ncbicgi.hpp:411
EBrowserPlatform m_Platform
Platform type.
Definition: user_agent.hpp:481
void x_Parse(const string &user_agent)
Parse user agent string.
Definition: user_agent.cpp:871
bool x_CheckPattern(int what, bool current_status, bool use_patterns, const string &include_patterns=kEmptyStr, const string &exclude_patterns=kEmptyStr) const
Helper method to check UA-string against external pattern lists.
Definition: user_agent.cpp:197
TUserAgentVersion m_EngineVersion
Browser engine version.
Definition: user_agent.hpp:479
bool IsBrowser(void) const
Check that this is known browser.
Definition: user_agent.cpp:106
bool x_ParseToken(const string &token, int where, EBrowserEngine engine=eEngine_Unknown)
Parse token with browser name and version.
EBrowserEngine GetEngine(void) const
Get browser engine type and name.
Definition: user_agent.hpp:235
EBrowserEngine m_Engine
Browser engine type.
Definition: user_agent.hpp:478
void Reset(const string &user_agent)
Parse new user agent string.
Definition: user_agent.cpp:100
string GetPlatformName(void) const
TFlags m_Flags
Comparison and parsing flags.
Definition: user_agent.hpp:474
EBrowserEngine
Browser engine types.
Definition: user_agent.hpp:191
EBrowser GetBrowser(void) const
Get browser type.
Definition: user_agent.hpp:222
TUserAgentVersion m_MozillaVersion
Browser mozilla version.
Definition: user_agent.hpp:480
bool IsMobileDevice(const string &include_patterns=kEmptyStr, const string &exclude_patterns=kEmptyStr) const
Check that this is a known mobile device.
Definition: user_agent.cpp:442
EBrowserPlatform GetPlatform(void) const
Get platform (OS) type and name.
Definition: user_agent.hpp:241
bool IsPhoneDevice(const string &include_patterns=kEmptyStr, const string &exclude_patterns=kEmptyStr) const
Check that this is a known phone-size device.
Definition: user_agent.cpp:414
EBrowser m_Browser
Browser type.
Definition: user_agent.hpp:475
unsigned int TFlags
Binary OR of "EFlags".
Definition: user_agent.hpp:72
string GetEngineName(void) const
bool IsTabletDevice(const string &include_patterns=kEmptyStr, const string &exclude_patterns=kEmptyStr) const
Check that this is a known tablet device.
Definition: user_agent.cpp:428
TUserAgentVersion m_BrowserVersion
Browser version info.
Definition: user_agent.hpp:477
unsigned int TBotFlags
Binary OR of "EBotFlags".
Definition: user_agent.hpp:267
CCgiUserAgent(TFlags flags=0)
Default constructor.
Definition: user_agent.cpp:62
void x_Init(void)
Init class members.
Definition: user_agent.cpp:87
string m_UserAgent
User-Agent string.
Definition: user_agent.hpp:473
EBrowserPlatform
Platform types.
Definition: user_agent.hpp:203
TDeviceFlags m_DeviceFlags
Device type flags.
Definition: user_agent.hpp:482
EBrowser
Browser types.
Definition: user_agent.hpp:91
string m_BrowserName
Browser name.
Definition: user_agent.hpp:476
bool IsBot(TBotFlags flags=fBotAll, const string &include_patterns=kEmptyStr, const string &exclude_patterns=kEmptyStr) const
Check that this is known search robot/bot.
Definition: user_agent.cpp:366
@ fUseBotPatterns
Use external pattern list from registry/environment to check on bots, off by default.
Definition: user_agent.hpp:67
@ fUseDevicePatterns
Use external pattern lists from registry/environment to check on phone/tablet/mobile device when pars...
Definition: user_agent.hpp:70
@ eEngine_Bot
Search robot/bot/checker/...
Definition: user_agent.hpp:199
@ eEngine_Unknown
Unknown engine.
Definition: user_agent.hpp:192
@ eEngine_KHTML
KHTML-based.
Definition: user_agent.hpp:196
@ eEngine_Gecko
Gecko-based.
Definition: user_agent.hpp:195
@ eEngine_Blink
Google Blink (WebKit/537.36 fork)
Definition: user_agent.hpp:198
@ eEngine_WebKit
Apple WebKit (KHTML fork)
Definition: user_agent.hpp:197
@ eEngine_Edge
Microsoft Edge.
Definition: user_agent.hpp:194
@ eEngine_IE
Microsoft Internet Explorer (Trident and etc)
Definition: user_agent.hpp:193
@ fDevice_Phone
Phone / not known tablet / mobile browser on desktop.
Definition: user_agent.hpp:318
@ fDevice_Tablet
Known tablet.
Definition: user_agent.hpp:319
@ ePlatform_Android
Android.
Definition: user_agent.hpp:210
@ ePlatform_Palm
PalmOS.
Definition: user_agent.hpp:211
@ ePlatform_Symbian
SymbianOS.
Definition: user_agent.hpp:212
@ ePlatform_Mac
MacOS.
Definition: user_agent.hpp:206
@ ePlatform_Windows
Microsoft Windows.
Definition: user_agent.hpp:205
@ ePlatform_Unix
Unix.
Definition: user_agent.hpp:207
@ ePlatform_WindowsCE
Microsoft Windows CE (+ Windows Mobile)
Definition: user_agent.hpp:213
@ ePlatform_MobileDevice
Other mobile devices or services.
Definition: user_agent.hpp:214
@ ePlatform_Unknown
Unknown OS.
Definition: user_agent.hpp:204
@ eMinimo
Minimo (www.mozilla.org/projects/minimo)
Definition: user_agent.hpp:163
@ eEnigmaBrowser
Enigma Browser (www.suttondesigns.com)
Definition: user_agent.hpp:128
@ eSafari
Safari (www.apple.com/safari)
Definition: user_agent.hpp:141
@ eChrome
Google Chrome (www.google.com/chrome)
Definition: user_agent.hpp:134
@ eUnknown
Unknown user agent.
Definition: user_agent.hpp:92
@ eQtWeb
QtWeb (www.qtweb.net)
Definition: user_agent.hpp:140
@ eKonqueror
Konqueror (www.konqueror.org) (KHTML based since v3.2 ?)
Definition: user_agent.hpp:136
@ eMadfox
Madfox (www.splyb.com/madfox)
Definition: user_agent.hpp:119
@ ePolaris
Polaris Browser (www.infraware.co.kr)
Definition: user_agent.hpp:171
@ eIceweasel
Debian Iceweasel (www.geticeweasel.org)
Definition: user_agent.hpp:113
@ ePIE
Pocket IE (www.reensoft.com/PIEPlus)
Definition: user_agent.hpp:168
@ eScript
Class: script tools (perl/php/...)
Definition: user_agent.hpp:148
@ eOperaMobile
Opera Mobile (www.opera.com/mobile)
Definition: user_agent.hpp:166
@ eEudoraWeb
EudoraWeb (www.eudora.com)
Definition: user_agent.hpp:162
@ eSEMCBrowser
Sony Ericsson SEMC-Browser (www.sonyericsson.com)
Definition: user_agent.hpp:174
@ eFirefox
Firefox (www.mozilla.org/products/firefox)
Definition: user_agent.hpp:110
@ eBeonex
Beonex Communicator (www.beonex.com)
Definition: user_agent.hpp:107
@ eNetCaptor
NetCaptor (www.netcaptor.com)
Definition: user_agent.hpp:131
@ ePocketLink
PocketLink (www.mobilefan.net)
Definition: user_agent.hpp:170
@ eKNinja
K-Ninja Samurai (k-ninja-samurai.en.softonic.com)
Definition: user_agent.hpp:118
@ eNetFront
NetFront (www.access-company.com)
Definition: user_agent.hpp:164
@ eOpera
Opera (www.opera.com)
Definition: user_agent.hpp:99
@ eNagios
check_http/nagios-plugins (nagiosplugins.org)
Definition: user_agent.hpp:104
@ eMultiZilla
MultiZilla (multizilla.mozdev.org)
Definition: user_agent.hpp:120
@ eOmniWeb
OmniWeb (www.omnigroup.com/applications/omniweb)
Definition: user_agent.hpp:139
@ eDoCoMo
DoCoMo (www.nttdocomo.com)
Definition: user_agent.hpp:161
@ eIceCat
GNU IceCat (http://www.gnu.org/software/gnuzilla)
Definition: user_agent.hpp:112
@ eTelecaObigo
Teleca/Obigo (www.teleca.com / www.obigo.com)
Definition: user_agent.hpp:175
@ eEdge
Microsoft Edge (www.microsoft.com)
Definition: user_agent.hpp:95
@ eBlackberry
Blackberry (www.blackberry.com)
Definition: user_agent.hpp:160
@ eSeaMonkey
SeaMonkey (www.mozilla.org/projects/seamonkey)
Definition: user_agent.hpp:121
@ eGranParadiso
GranParadiso (www.mozilla.org)
Definition: user_agent.hpp:115
@ eXiino
Xiino (www.ilinx.co.jp/en/)
Definition: user_agent.hpp:178
@ eChimera
Chimera (chimera.mozdev.org)
Definition: user_agent.hpp:109
@ eStainless
Stainless (www.stainlessapp.com)
Definition: user_agent.hpp:143
@ eiCab
iCab (www.icab.de)
Definition: user_agent.hpp:96
@ eCrazyBrowser
Crazy Browser (www.crazybrowser.com)
Definition: user_agent.hpp:127
@ eAirEdge
Mobile devices (browsers and services for: telephones, smartphones, tablets and etc) Some mobile devi...
Definition: user_agent.hpp:158
@ eOpenWave
OpenWave/UP.Browser (www.openwave.com)
Definition: user_agent.hpp:167
@ eLynx
Lynx (lynx.browser.org)
Definition: user_agent.hpp:97
@ eIE
Microsoft Internet Explorer (www.microsoft.com/windows/ie)
Definition: user_agent.hpp:94
@ eSafariMobile
Mobile Safari (www.apple.com/safari)
Definition: user_agent.hpp:173
@ eOfflineBrowser
Class: offline browsers.
Definition: user_agent.hpp:147
@ eMaxthon
Maxthon/MyIE2 (www.maxthon.com)
Definition: user_agent.hpp:130
@ eCamino
Camino (www.caminobrowser.org)
Definition: user_agent.hpp:108
@ eNetNewsWire
NetNewsWire (www.apple.com)
Definition: user_agent.hpp:138
@ eOperaMini
Opera Mini (www.opera.com/mini)
Definition: user_agent.hpp:165
@ ePapers
Papers (papersapp.com)
Definition: user_agent.hpp:101
@ eNetscape
Netscape (Navigator), versions >=6 are Gecko-based (www.netscape.com)
Definition: user_agent.hpp:98
@ eAvantGo
AvantGo (www.sybase.com/avantgo)
Definition: user_agent.hpp:159
@ eAvantBrowser
Avant Browser (www.avantbrowser.com)
Definition: user_agent.hpp:126
@ eIRider
iRider (www.irider.com)
Definition: user_agent.hpp:129
@ eReqwireless
Reqwireless Webviewer.
Definition: user_agent.hpp:172
@ euZardWeb
uZard Web (www.uzard.com)
Definition: user_agent.hpp:176
@ eFlock
Flock (www.flock.com)
Definition: user_agent.hpp:111
@ eW3m
w3m (www.w3m.org)
Definition: user_agent.hpp:103
@ eAOL
America Online Browser (www.aol.com)
Definition: user_agent.hpp:125
@ eUCBrowser
UC Browser (www.ucweb.com/ucbrowser)
Definition: user_agent.hpp:102
@ eKazehakase
Kazehakase (kazehakase.sourceforge.jp)
Definition: user_agent.hpp:116
@ eGaleon
Galeon (galeon.sourceforge.net)
Definition: user_agent.hpp:114
@ eMozilla
Any other Gecko-based not from the list above, Mozilla version >= 5.0.
Definition: user_agent.hpp:182
@ eFluid
Fluid (fluidapp.com)
Definition: user_agent.hpp:135
@ eWebValidator
Class: validators.
Definition: user_agent.hpp:150
@ eLinkChecker
Class: link checkers.
Definition: user_agent.hpp:149
@ eMozillaCompatible
Any other not from list above.
Definition: user_agent.hpp:187
@ eKMeleon
K-Meleon (kmeleon.sf.net)
Definition: user_agent.hpp:117
@ eShiira
Shiira (hmdt-web.net/shiira/en)
Definition: user_agent.hpp:142
@ eOregano
Oregano (www.castle.org.uk/oregano)
Definition: user_agent.hpp:100
@ eMidori
Midori.
Definition: user_agent.hpp:137
@ eCrawler
Search robots/bots/validators.
Definition: user_agent.hpp:146
@ eAcooBrowser
Acoo Browser (www.acoobrowser.com)
Definition: user_agent.hpp:124
@ eVodafone
Ex J-Phone, now Vodafone Live! (www.vodafone.com)
Definition: user_agent.hpp:177
@ ePlucker
Plucker (www.plkr.org)
Definition: user_agent.hpp:169
const string & Get(const string &name, bool *found=NULL) const
Get environment value by name.
Definition: ncbienv.cpp:109
#define NCBI_PARAM_TYPE(section, name)
Generate typename for a parameter from its {section, name} attributes.
Definition: ncbi_param.hpp:149
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
NCBI_NS_STD::string::size_type SIZE_TYPE
Definition: ncbistr.hpp:132
#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:3461
static bool MatchesMask(CTempString str, CTempString mask, ECase use_case=eCase)
Match "str" against the "mask".
Definition: ncbistr.cpp:389
#define NPOS
Definition: ncbistr.hpp:133
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3186
static string & ToLower(string &str)
Convert string to lower case – string& version.
Definition: ncbistr.cpp:405
@ fSplit_Truncate
Definition: ncbistr.hpp:2501
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2498
int GetMajor(void) const
Major version.
void SetVersion(int ver_major, int ver_minor, int patch_level=0)
Definition: version.cpp:204
int i
int len
static int version
Definition: mdb_load.c:29
const struct ncbi::grid::netcache::search::fields::KEY key
int isdigit(Uchar c)
Definition: ncbictype.hpp:64
static patstr * include_patterns
Definition: pcregrep.c:261
static patstr * patterns
Definition: pcregrep.c:259
static patstr * exclude_patterns
Definition: pcregrep.c:263
TUASearchFlags flags
Definition: user_agent.cpp:485
CCgiUserAgent::EBrowserEngine engine
Definition: user_agent.cpp:483
CCgiUserAgent::EBrowser type
Definition: user_agent.cpp:480
const char * name
Definition: user_agent.cpp:481
CCgiUserAgent::EBrowserPlatform platform
Definition: user_agent.cpp:484
const char * key
Definition: user_agent.cpp:482
#define _TROUBLE
#define _ASSERT
int TUASearchFlags
Definition: user_agent.cpp:475
NCBI_PARAM_DEF(string, CGI, Bots, "")
const size_t kBrowsers
Definition: user_agent.cpp:822
void s_ParseVersion(const string &token, SIZE_TYPE start_pos, TUserAgentVersion *version)
Definition: user_agent.cpp:836
const char * kMultiLinePatternDelimiters
Definition: user_agent.cpp:54
#define F_ISSET(mask)
Definition: user_agent.cpp:47
EUASearchFlags
Definition: user_agent.cpp:465
@ fAppComment
Definition: user_agent.cpp:467
@ fProduct
Definition: user_agent.cpp:470
@ fApp
Definition: user_agent.cpp:471
@ fVendorComment
Definition: user_agent.cpp:469
@ fAppProduct
Definition: user_agent.cpp:466
@ fAny
Definition: user_agent.cpp:473
@ fVendorProduct
Definition: user_agent.cpp:468
@ fVendor
Definition: user_agent.cpp:472
const char * kSingleLinePatternDelimiters
Definition: user_agent.cpp:53
const SBrowser s_Browsers[]
Definition: user_agent.cpp:490
string s_ToLower(string str)
Definition: user_agent.cpp:56
EPattern
Definition: user_agent.cpp:186
@ eMobile
Definition: user_agent.cpp:189
@ eBot
Definition: user_agent.cpp:190
@ ePhone
Definition: user_agent.cpp:187
@ eTablet
Definition: user_agent.cpp:188
SIZE_TYPE s_SkipDigits(const string &str, SIZE_TYPE pos)
Definition: user_agent.cpp:826
NCBI_PARAM_DECL(string, CGI, Bots)
#define USTR(str)
Definition: user_agent.cpp:50
API to parse user agent strings.
Modified on Wed Apr 17 13:09:37 2024 by modify_doxy.py rev. 669887