bes  Updated for version 3.19.1
BESUtil.cc
1 // BESUtil.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include "config.h"
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 
38 #if HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 
42 #include <cstdio>
43 #include <cerrno>
44 #include <cstring>
45 #include <cstdlib>
46 #include <cassert>
47 
48 #include <sstream>
49 #include <iostream>
50 
51 using std::istringstream;
52 using std::cout;
53 using std::endl;
54 
55 #include "TheBESKeys.h"
56 #include "BESUtil.h"
57 #include "BESDebug.h"
58 #include "BESForbiddenError.h"
59 #include "BESNotFoundError.h"
60 #include "BESInternalError.h"
61 
62 #define CRLF "\r\n"
63 
64 #define debug_key "BesUtil"
65 
66 const string BES_KEY_TIMEOUT_CANCEL = "BES.CancelTimeoutOnSend";
67 
72 void BESUtil::set_mime_text(ostream &strm)
73 {
74  strm << "HTTP/1.0 200 OK" << CRLF;
75  strm << "XBES-Server: " << PACKAGE_STRING << CRLF;
76 
77  const time_t t = time(0);
78  strm << "Date: " << rfc822_date(t).c_str() << CRLF;
79  strm << "Last-Modified: " << rfc822_date(t).c_str() << CRLF;
80 
81  strm << "Content-Type: text/plain" << CRLF;
82  // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616.
83  strm << "Content-Description: unknown" << CRLF;
84  strm << CRLF;
85 }
86 
91 void BESUtil::set_mime_html(ostream &strm)
92 {
93  strm << "HTTP/1.0 200 OK" << CRLF;
94  strm << "XBES-Server: " << PACKAGE_STRING << CRLF;
95 
96  const time_t t = time(0);
97  strm << "Date: " << rfc822_date(t).c_str() << CRLF;
98  strm << "Last-Modified: " << rfc822_date(t).c_str() << CRLF;
99 
100  strm << "Content-type: text/html" << CRLF;
101  // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616.
102  strm << "Content-Description: unknown" << CRLF;
103  strm << CRLF;
104 }
105 
106 // Return a MIME rfc-822 date. The grammar for this is:
107 // date-time = [ day "," ] date time ; dd mm yy
108 // ; hh:mm:ss zzz
109 //
110 // day = "Mon" / "Tue" / "Wed" / "Thu"
111 // / "Fri" / "Sat" / "Sun"
112 //
113 // date = 1*2DIGIT month 2DIGIT ; day month year
114 // ; e.g. 20 Jun 82
115 // NB: year is 4 digit; see RFC 1123. 11/30/99 jhrg
116 //
117 // month = "Jan" / "Feb" / "Mar" / "Apr"
118 // / "May" / "Jun" / "Jul" / "Aug"
119 // / "Sep" / "Oct" / "Nov" / "Dec"
120 //
121 // time = hour zone ; ANSI and Military
122 //
123 // hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
124 // ; 00:00:00 - 23:59:59
125 //
126 // zone = "UT" / "GMT" ; Universal Time
127 // ; North American : UT
128 // / "EST" / "EDT" ; Eastern: - 5/ - 4
129 // / "CST" / "CDT" ; Central: - 6/ - 5
130 // / "MST" / "MDT" ; Mountain: - 7/ - 6
131 // / "PST" / "PDT" ; Pacific: - 8/ - 7
132 // / 1ALPHA ; Military: Z = UT;
133 // ; A:-1; (J not used)
134 // ; M:-12; N:+1; Y:+12
135 // / ( ("+" / "-") 4DIGIT ) ; Local differential
136 // ; hours+min. (HHMM)
137 
138 static const char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
139 static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
140 
150 string BESUtil::rfc822_date(const time_t t)
151 {
152  struct tm *stm = gmtime(&t);
153  char d[256];
154 
155  snprintf(d, 255, "%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday], stm->tm_mday, months[stm->tm_mon],
156  1900 + stm->tm_year, stm->tm_hour, stm->tm_min, stm->tm_sec);
157  d[255] = '\0';
158  return string(d);
159 }
160 
161 string BESUtil::unhexstring(string s)
162 {
163  int val;
164  istringstream ss(s);
165  ss >> std::hex >> val;
166  char tmp_str[2];
167  tmp_str[0] = static_cast<char>(val);
168  tmp_str[1] = '\0';
169  return string(tmp_str);
170 }
171 
172 // I modified this to mirror the version in libdap. The change allows several
173 // escape sequences to by listed in 'except'. jhrg 2/18/09
174 string BESUtil::www2id(const string &in, const string &escape, const string &except)
175 {
176  string::size_type i = 0;
177  string res = in;
178  while ((i = res.find_first_of(escape, i)) != string::npos) {
179  if (except.find(res.substr(i, 3)) != string::npos) {
180  i += 3;
181  continue;
182  }
183  res.replace(i, 3, unhexstring(res.substr(i + 1, 2)));
184  }
185 
186  return res;
187 }
188 
189 string BESUtil::lowercase(const string &s)
190 {
191  string return_string = s;
192  for (int j = 0; j < static_cast<int>(return_string.length()); j++) {
193  return_string[j] = (char) tolower(return_string[j]);
194  }
195 
196  return return_string;
197 }
198 
199 string BESUtil::unescape(const string &s)
200 {
201  bool done = false;
202  string::size_type index = 0;
203  /* string::size_type new_index = 0 ; */
204  string new_str;
205  while (!done) {
206  string::size_type bs = s.find('\\', index);
207  if (bs == string::npos) {
208  new_str += s.substr(index, s.length() - index);
209  done = true;
210  }
211  else {
212  new_str += s.substr(index, bs - index);
213  new_str += s[bs + 1];
214  index = bs + 2;
215  }
216  }
217 
218  return new_str;
219 }
220 
242 void BESUtil::check_path(const string &path, const string &root, bool follow_sym_links)
243 {
244  // if nothing is passed in path, then the path checks out since root is
245  // assumed to be valid.
246  if (path == "") return;
247 
248  // Rather than have two basically identical code paths for the two cases (follow and !follow symlinks)
249  // We evaluate the follow_sym_links switch and use a function pointer to get the correct "stat"
250  // function for the eval operation.
251  int (*ye_old_stat_function)(const char *pathname, struct stat *buf);
252  if (follow_sym_links) {
253  BESDEBUG(debug_key, "eval_w10n_resourceId() - Using 'stat' function (follow_sym_links = true)" << endl);
254  ye_old_stat_function = &stat;
255  }
256  else {
257  BESDEBUG(debug_key, "eval_w10n_resourceId() - Using 'lstat' function (follow_sym_links = false)" << endl);
258  ye_old_stat_function = &lstat;
259  }
260 
261  // make sure there are no ../ in the directory, backing up in any way is
262  // not allowed.
263  string::size_type dotdot = path.find("..");
264  if (dotdot != string::npos) {
265  string s = (string) "You are not allowed to access the node " + path;
266  throw BESForbiddenError(s, __FILE__, __LINE__);
267  }
268 
269  // What I want to do is to take each part of path and check to see if it
270  // is a symbolic link and it is accessible. If everything is ok, add the
271  // next part of the path.
272  bool done = false;
273 
274  // what is remaining to check
275  string rem = path;
276  if (rem[0] == '/') rem = rem.substr(1, rem.length() - 1);
277  if (rem[rem.length() - 1] == '/') rem = rem.substr(0, rem.length() - 1);
278 
279  // full path of the thing to check
280  string fullpath = root;
281  if (fullpath[fullpath.length() - 1] == '/') {
282  fullpath = fullpath.substr(0, fullpath.length() - 1);
283  }
284 
285  // path checked so far
286  string checked;
287  while (!done) {
288  size_t slash = rem.find('/');
289  if (slash == string::npos) {
290  fullpath = fullpath + "/" + rem;
291  checked = checked + "/" + rem;
292  done = true;
293  }
294  else {
295  fullpath = fullpath + "/" + rem.substr(0, slash);
296  checked = checked + "/" + rem.substr(0, slash);
297  rem = rem.substr(slash + 1, rem.length() - slash);
298  }
299 
300  struct stat buf;
301  int statret = ye_old_stat_function(fullpath.c_str(), &buf);
302  if (statret == -1) {
303  int errsv = errno;
304  // stat failed, so not accessible. Get the error string,
305  // store in error, and throw exception
306  char *s_err = strerror(errsv);
307  string error = "Unable to access node " + checked + ": ";
308  if (s_err) {
309  error = error + s_err;
310  }
311  else {
312  error = error + "unknown access error";
313  }
314 
315  BESDEBUG(debug_key, "check_path() - error: "<< error << " errno: " << errno << endl);
316 
317  // ENOENT means that the node wasn't found.
318  // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
319  // Otherwise, access is being denied for some other reason
320  if (errsv == ENOENT || errsv == ENOTDIR) {
321  // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
322  throw BESNotFoundError(error, __FILE__, __LINE__);
323  }
324  else {
325  throw BESForbiddenError(error, __FILE__, __LINE__);
326  }
327  }
328  else {
329  //The call to (stat | lstat) was successful, now check to see if it's a symlink.
330  // Note that if follow_symlinks is true then this will never evaluate as true
331  // because we'll be using 'stat' and not 'lstat' and stat will follow the link
332  // and return information about the file/dir pointed to by the symlink
333  if (S_ISLNK(buf.st_mode)) {
334  string error = "You do not have permission to access " + checked;
335  throw BESForbiddenError(error, __FILE__, __LINE__);
336  }
337  }
338  }
339 
340 #if 0
341  while (!done) {
342  size_t slash = rem.find('/');
343  if (slash == string::npos) {
344  fullpath = fullpath + "/" + rem;
345  checked = checked + "/" + rem;
346  done = true;
347  }
348  else {
349  fullpath = fullpath + "/" + rem.substr(0, slash);
350  checked = checked + "/" + rem.substr(0, slash);
351  rem = rem.substr(slash + 1, rem.length() - slash);
352  }
353 
354  if (!follow_sym_links) {
355  struct stat buf;
356  int statret = lstat(fullpath.c_str(), &buf);
357  if (statret == -1) {
358  int errsv = errno;
359  // stat failed, so not accessible. Get the error string,
360  // store in error, and throw exception
361  char *s_err = strerror(errsv);
362  string error = "Unable to access node " + checked + ": ";
363  if (s_err) {
364  error = error + s_err;
365  }
366  else {
367  error = error + "unknown access error";
368  }
369  // ENOENT means that the node wasn't found. Otherwise, access
370  // is denied for some reason
371  if (errsv == ENOENT) {
372  throw BESNotFoundError(error, __FILE__, __LINE__);
373  }
374  else {
375  throw BESForbiddenError(error, __FILE__, __LINE__);
376  }
377  }
378  else {
379  // lstat was successful, now check if sym link
380  if (S_ISLNK( buf.st_mode )) {
381  string error = "You do not have permission to access "
382  + checked;
383  throw BESForbiddenError(error, __FILE__, __LINE__);
384  }
385  }
386  }
387  else {
388  // just do a stat and see if we can access the thing. If we
389  // can't, get the error information and throw an exception
390  struct stat buf;
391  int statret = stat(fullpath.c_str(), &buf);
392  if (statret == -1) {
393  int errsv = errno;
394  // stat failed, so not accessible. Get the error string,
395  // store in error, and throw exception
396  char *s_err = strerror(errsv);
397  string error = "Unable to access node " + checked + ": ";
398  if (s_err) {
399  error = error + s_err;
400  }
401  else {
402  error = error + "unknown access error";
403  }
404  // ENOENT means that the node wasn't found. Otherwise, access
405  // is denied for some reason
406  if (errsv == ENOENT) {
407  throw BESNotFoundError(error, __FILE__, __LINE__);
408  }
409  else {
410  throw BESForbiddenError(error, __FILE__, __LINE__);
411  }
412  }
413  }
414  }
415 
416 #endif
417 }
418 
419 char *
420 BESUtil::fastpidconverter(char *buf, int base)
421 {
422  return fastpidconverter(getpid(), buf, base);
423 }
424 
425 char *
426 BESUtil::fastpidconverter(long val, /* value to be converted */
427 char *buf, /* output string */
428 int base) /* conversion base */
429 {
430  ldiv_t r; /* result of val / base */
431 
432  if (base > 36 || base < 2) /* no conversion if wrong base */
433  {
434  *buf = '\0';
435  return buf;
436  }
437  if (val < 0) *buf++ = '-';
438  r = ldiv(labs(val), base);
439 
440  /* output digits of val/base first */
441 
442  if (r.quot > 0) buf = fastpidconverter(r.quot, buf, base);
443  /* output last digit */
444 
445  *buf++ = "0123456789abcdefghijklmnopqrstuvwxyz"[(int) r.rem];
446  *buf = '\0';
447  return buf;
448 }
449 
451 {
452  if (!key.empty()) {
453  string::size_type first = key.find_first_not_of(" \t\n\r");
454  string::size_type last = key.find_last_not_of(" \t\n\r");
455  if (first == string::npos)
456  key = "";
457  else {
458  string::size_type num = last - first + 1;
459  string new_key = key.substr(first, num);
460  key = new_key;
461  }
462  }
463 }
464 
465 string BESUtil::entity(char c)
466 {
467  switch (c) {
468  case '>':
469  return "&gt;";
470  case '<':
471  return "&lt;";
472  case '&':
473  return "&amp;";
474  case '\'':
475  return "&apos;";
476  case '\"':
477  return "&quot;";
478  default:
479  return string(1, c); // is this proper default, just the char?
480  }
481 }
482 
489 string BESUtil::id2xml(string in, const string &not_allowed)
490 {
491  string::size_type i = 0;
492 
493  while ((i = in.find_first_of(not_allowed, i)) != string::npos) {
494  in.replace(i, 1, entity(in[i]));
495  i++;
496  }
497 
498  return in;
499 }
500 
506 string BESUtil::xml2id(string in)
507 {
508  string::size_type i = 0;
509 
510  while ((i = in.find("&gt;", i)) != string::npos)
511  in.replace(i, 4, ">");
512 
513  i = 0;
514  while ((i = in.find("&lt;", i)) != string::npos)
515  in.replace(i, 4, "<");
516 
517  i = 0;
518  while ((i = in.find("&amp;", i)) != string::npos)
519  in.replace(i, 5, "&");
520 
521  i = 0;
522  while ((i = in.find("&apos;", i)) != string::npos)
523  in.replace(i, 6, "'");
524 
525  i = 0;
526  while ((i = in.find("&quot;", i)) != string::npos)
527  in.replace(i, 6, "\"");
528 
529  return in;
530 }
531 
545 void BESUtil::explode(char delim, const string &str, list<string> &values)
546 {
547  std::string::size_type start = 0;
548  std::string::size_type qstart = 0;
549  std::string::size_type adelim = 0;
550  std::string::size_type aquote = 0;
551  bool done = false;
552  while (!done) {
553  string aval;
554  if (str[start] == '"') {
555  bool endquote = false;
556  qstart = start + 1;
557  while (!endquote) {
558  aquote = str.find('"', qstart);
559  if (aquote == string::npos) {
560  string currval = str.substr(start, str.length() - start);
561  string err = "BESUtil::explode - No end quote after value " + currval;
562  throw BESInternalError(err, __FILE__, __LINE__);
563  }
564  // could be an escaped escape character and an escaped
565  // quote, or an escaped escape character and a quote
566  if (str[aquote - 1] == '\\') {
567  if (str[aquote - 2] == '\\') {
568  endquote = true;
569  qstart = aquote + 1;
570  }
571  else {
572  qstart = aquote + 1;
573  }
574  }
575  else {
576  endquote = true;
577  qstart = aquote + 1;
578  }
579  }
580  if (str[qstart] != delim && qstart != str.length()) {
581  string currval = str.substr(start, qstart - start);
582  string err = "BESUtil::explode - No delim after end quote " + currval;
583  throw BESInternalError(err, __FILE__, __LINE__);
584  }
585  if (qstart == str.length()) {
586  adelim = string::npos;
587  }
588  else {
589  adelim = qstart;
590  }
591  }
592  else {
593  adelim = str.find(delim, start);
594  }
595  if (adelim == string::npos) {
596  aval = str.substr(start, str.length() - start);
597  done = true;
598  }
599  else {
600  aval = str.substr(start, adelim - start);
601  }
602 
603  values.push_back(aval);
604  start = adelim + 1;
605  if (start == str.length()) {
606  values.push_back("");
607  done = true;
608  }
609  }
610 }
611 
622 string BESUtil::implode(const list<string> &values, char delim)
623 {
624  string result;
625  list<string>::const_iterator i = values.begin();
626  list<string>::const_iterator e = values.end();
627  bool first = true;
628  string::size_type d; // = string::npos ;
629  for (; i != e; i++) {
630  if (!first) result += delim;
631  d = (*i).find(delim);
632  if (d != string::npos && (*i)[0] != '"') {
633  string err = (string) "BESUtil::implode - delimiter exists in value " + (*i);
634  throw BESInternalError(err, __FILE__, __LINE__);
635  }
636  //d = string::npos ;
637  result += (*i);
638  first = false;
639  }
640  return result;
641 }
642 
662 void BESUtil::url_explode(const string &url_str, BESUtil::url &url_parts)
663 {
664  string rest;
665 
666  string::size_type colon = url_str.find(":");
667  if (colon == string::npos) {
668  string err = "BESUtil::url_explode: missing colon for protocol";
669  throw BESInternalError(err, __FILE__, __LINE__);
670  }
671 
672  url_parts.protocol = url_str.substr(0, colon);
673 
674  if (url_str.substr(colon, 3) != "://") {
675  string err = "BESUtil::url_explode: no :// in the URL";
676  throw BESInternalError(err, __FILE__, __LINE__);
677  }
678 
679  colon += 3;
680  rest = url_str.substr(colon);
681 
682  string::size_type slash = rest.find("/");
683  if (slash == string::npos) slash = rest.length();
684 
685  string::size_type at = rest.find("@");
686  if ((at != string::npos) && (at < slash)) {
687  // everything before the @ is username:password
688  string up = rest.substr(0, at);
689  colon = up.find(":");
690  if (colon != string::npos) {
691  url_parts.uname = up.substr(0, colon);
692  url_parts.psswd = up.substr(colon + 1);
693  }
694  else {
695  url_parts.uname = up;
696  }
697  // everything after the @ is domain/path
698  rest = rest.substr(at + 1);
699  }
700  slash = rest.find("/");
701  if (slash == string::npos) slash = rest.length();
702  colon = rest.find(":");
703  if ((colon != string::npos) && (colon < slash)) {
704  // everything before the colon is the domain
705  url_parts.domain = rest.substr(0, colon);
706  // everything after the folon is port/path
707  rest = rest.substr(colon + 1);
708  slash = rest.find("/");
709  if (slash != string::npos) {
710  url_parts.port = rest.substr(0, slash);
711  url_parts.path = rest.substr(slash + 1);
712  }
713  else {
714  url_parts.port = rest;
715  url_parts.path = "";
716  }
717  }
718  else {
719  slash = rest.find("/");
720  if (slash != string::npos) {
721  url_parts.domain = rest.substr(0, slash);
722  url_parts.path = rest.substr(slash + 1);
723  }
724  else {
725  url_parts.domain = rest;
726  }
727  }
728 }
729 
730 string BESUtil::url_create(BESUtil::url &url_parts)
731 {
732  string url = url_parts.protocol + "://";
733  if (!url_parts.uname.empty()) {
734  url += url_parts.uname;
735  if (!url_parts.psswd.empty()) url += ":" + url_parts.psswd;
736  url += "@";
737  }
738  url += url_parts.domain;
739  if (!url_parts.port.empty()) url += ":" + url_parts.port;
740  if (!url_parts.path.empty()) url += "/" + url_parts.path;
741 
742  return url;
743 }
744 
757 string BESUtil::assemblePath(const string &firstPart, const string &secondPart, bool ensureLeadingSlash)
758 {
759 #if 0
760  assert(!firstPart.empty());
761 
762  // This version works but does not remove duplicate slashes
763  string first = firstPart;
764  string second = secondPart;
765 
766  // add a leading slash if needed
767  if (ensureLeadingSlash && first[0] != '/')
768  first = "/" + first;
769 
770  // if 'second' start with a slash, remove it
771  if (second[0] == '/')
772  second = second.substr(1);
773 
774  // glue the two parts together, adding a slash if needed
775  if (first.back() == '/')
776  return first.append(second);
777  else
778  return first.append("/").append(second);
779 #endif
780 
781 #if 1
782  BESDEBUG("util", "BESUtil::assemblePath() - firstPart: "<< firstPart << endl);
783  BESDEBUG("util", "BESUtil::assemblePath() - secondPart: "<< secondPart << endl);
784 
785  assert(!firstPart.empty());
786 
787  string first = firstPart;
788  string second = secondPart;
789 
790  if (ensureLeadingSlash) {
791  if (first[0] != '/') first = "/" + first;
792  }
793 
794  // make sure there are not multiple slashes at the end of the first part...
795  // Note that this removes all of the slashes. jhrg 9/27/16
796  while (!first.empty() && *first.rbegin() == '/') {
797  // C++-11 first.pop_back();
798  first = first.substr(0, first.length() - 1);
799  }
800 
801  // make sure second part does not BEGIN with a slash
802  while (!second.empty() && second[0] == '/') {
803  // erase is faster? second = second.substr(1);
804  second.erase(0, 1);
805  }
806 
807  string newPath = first.append("/").append(second);
808 
809  BESDEBUG("util", "BESUtil::assemblePath() - newPath: "<< newPath << endl);
810 
811  return newPath;
812 #endif
813 
814 #if 0
815  BESDEBUG("util", "BESUtil::assemblePath() - firstPart: "<< firstPart << endl);
816  BESDEBUG("util", "BESUtil::assemblePath() - secondPart: "<< secondPart << endl);
817 
818  string first = firstPart;
819  string second = secondPart;
820 
821  if (ensureLeadingSlash) {
822  if (*first.begin() != '/') first = "/" + first;
823  }
824 
825  // make sure there are not multiple slashes at the end of the first part...
826  while (*first.rbegin() == '/' && first.length() > 0) {
827  first = first.substr(0, first.length() - 1);
828  }
829 
830  // make sure first part ends with a "/"
831  if (*first.rbegin() != '/') {
832  first += "/";
833  }
834 
835  // make sure second part does not BEGIN with a slash
836  while (*second.begin() == '/' && second.length() > 0) {
837  second = second.substr(1);
838  }
839 
840  string newPath = first + second;
841 
842  BESDEBUG("util", "BESUtil::assemblePath() - newPath: "<< newPath << endl);
843 
844  return newPath;
845 #endif
846 }
847 
852 bool BESUtil::endsWith(std::string const &fullString, std::string const &ending)
853 {
854  if (fullString.length() >= ending.length()) {
855  return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending));
856  }
857  else {
858  return false;
859  }
860 }
861 
862 
879 {
880  bool cancel_timeout_on_send = false;
881  bool found = false;
882  string doset ="";
883  const string dosettrue ="true";
884  const string dosetyes = "yes";
885 
886  TheBESKeys::TheKeys()->get_value( BES_KEY_TIMEOUT_CANCEL, doset, found ) ;
887  if( true == found ) {
888  doset = BESUtil::lowercase( doset ) ;
889  if( dosettrue == doset || dosetyes == doset )
890  cancel_timeout_on_send = true;
891  }
892  BESDEBUG("util",__func__ << "() - cancel_timeout_on_send: " <<(cancel_timeout_on_send?"true":"false") << endl);
893  if (cancel_timeout_on_send)
894  alarm(0);
895 }
896 
897 
error thrown if the resource requested cannot be found
exception thrown if inernal error encountered
static string lowercase(const string &s)
Definition: BESUtil.cc:189
static void conditional_timeout_cancel()
Definition: BESUtil.cc:878
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:422
static string www2id(const string &in, const string &escape="%", const string &except="")
Definition: BESUtil.cc:174
static void removeLeadingAndTrailingBlanks(string &key)
Definition: BESUtil.cc:450
static string assemblePath(const string &firstPart, const string &secondPart, bool addLeadingSlash=false)
Assemble path fragments making sure that they are separated by a single &#39;/&#39; character.
Definition: BESUtil.cc:757
static string implode(const list< string > &values, char delim)
Definition: BESUtil.cc:622
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:62
static string xml2id(string in)
Definition: BESUtil.cc:506
static void set_mime_html(ostream &strm)
Generate an HTTP 1.0 response header for a html document.
Definition: BESUtil.cc:91
static void explode(char delim, const string &str, list< string > &values)
Definition: BESUtil.cc:545
static void set_mime_text(ostream &strm)
Generate an HTTP 1.0 response header for a text document.
Definition: BESUtil.cc:72
static void url_explode(const string &url_str, BESUtil::url &url_parts)
Given a url, break the url into its different parts.
Definition: BESUtil.cc:662
static string id2xml(string in, const string &not_allowed="><&'\)
Definition: BESUtil.cc:489
static bool endsWith(std::string const &fullString, std::string const &ending)
Definition: BESUtil.cc:852
error thrown if the BES is not allowed to access the resource requested
static char * fastpidconverter(char *buf, int base)
Definition: BESUtil.cc:420
static string unescape(const string &s)
Definition: BESUtil.cc:199
static void check_path(const string &path, const string &root, bool follow_sym_links)
Definition: BESUtil.cc:242