bes  Updated for version 3.17.0
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 <sstream>
47 #include <iostream>
48 
49 using std::istringstream;
50 using std::cout;
51 using std::endl;
52 
53 #include "BESUtil.h"
54 #include "BESDebug.h"
55 #include "BESForbiddenError.h"
56 #include "BESNotFoundError.h"
57 #include "BESInternalError.h"
58 
59 #define CRLF "\r\n"
60 
61 #define debug_key "BesUtil"
62 
67 void BESUtil::set_mime_text(ostream &strm)
68 {
69  strm << "HTTP/1.0 200 OK" << CRLF;
70  strm << "XBES-Server: " << PACKAGE_STRING << CRLF;
71 
72  const time_t t = time(0);
73  strm << "Date: " << rfc822_date(t).c_str() << CRLF;
74  strm << "Last-Modified: " << rfc822_date(t).c_str() << CRLF;
75 
76  strm << "Content-Type: text/plain" << CRLF;
77  // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616.
78  strm << "Content-Description: unknown" << CRLF;
79  strm << CRLF;
80 }
81 
86 void BESUtil::set_mime_html(ostream &strm)
87 {
88  strm << "HTTP/1.0 200 OK" << CRLF;
89  strm << "XBES-Server: " << PACKAGE_STRING << CRLF;
90 
91  const time_t t = time(0);
92  strm << "Date: " << rfc822_date(t).c_str() << CRLF;
93  strm << "Last-Modified: " << rfc822_date(t).c_str() << CRLF;
94 
95  strm << "Content-type: text/html" << CRLF;
96  // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616.
97  strm << "Content-Description: unknown" << CRLF;
98  strm << CRLF;
99 }
100 
101 // Return a MIME rfc-822 date. The grammar for this is:
102 // date-time = [ day "," ] date time ; dd mm yy
103 // ; hh:mm:ss zzz
104 //
105 // day = "Mon" / "Tue" / "Wed" / "Thu"
106 // / "Fri" / "Sat" / "Sun"
107 //
108 // date = 1*2DIGIT month 2DIGIT ; day month year
109 // ; e.g. 20 Jun 82
110 // NB: year is 4 digit; see RFC 1123. 11/30/99 jhrg
111 //
112 // month = "Jan" / "Feb" / "Mar" / "Apr"
113 // / "May" / "Jun" / "Jul" / "Aug"
114 // / "Sep" / "Oct" / "Nov" / "Dec"
115 //
116 // time = hour zone ; ANSI and Military
117 //
118 // hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
119 // ; 00:00:00 - 23:59:59
120 //
121 // zone = "UT" / "GMT" ; Universal Time
122 // ; North American : UT
123 // / "EST" / "EDT" ; Eastern: - 5/ - 4
124 // / "CST" / "CDT" ; Central: - 6/ - 5
125 // / "MST" / "MDT" ; Mountain: - 7/ - 6
126 // / "PST" / "PDT" ; Pacific: - 8/ - 7
127 // / 1ALPHA ; Military: Z = UT;
128 // ; A:-1; (J not used)
129 // ; M:-12; N:+1; Y:+12
130 // / ( ("+" / "-") 4DIGIT ) ; Local differential
131 // ; hours+min. (HHMM)
132 
133 static const char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
134 static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
135 
145 string BESUtil::rfc822_date(const time_t t)
146 {
147  struct tm *stm = gmtime(&t);
148  char d[256];
149 
150  snprintf(d, 255, "%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday], stm->tm_mday, months[stm->tm_mon],
151  1900 + stm->tm_year, stm->tm_hour, stm->tm_min, stm->tm_sec);
152  d[255] = '\0';
153  return string(d);
154 }
155 
156 string BESUtil::unhexstring(string s)
157 {
158  int val;
159  istringstream ss(s);
160  ss >> std::hex >> val;
161  char tmp_str[2];
162  tmp_str[0] = static_cast<char>(val);
163  tmp_str[1] = '\0';
164  return string(tmp_str);
165 }
166 
167 // I modified this to mirror the version in libdap. The change allows several
168 // escape sequences to by listed in 'except'. jhrg 2/18/09
169 string BESUtil::www2id(const string &in, const string &escape, const string &except)
170 {
171  string::size_type i = 0;
172  string res = in;
173  while ((i = res.find_first_of(escape, i)) != string::npos) {
174  if (except.find(res.substr(i, 3)) != string::npos) {
175  i += 3;
176  continue;
177  }
178  res.replace(i, 3, unhexstring(res.substr(i + 1, 2)));
179  }
180 
181  return res;
182 }
183 
184 string BESUtil::lowercase(const string &s)
185 {
186  string return_string = s;
187  for (int j = 0; j < static_cast<int>(return_string.length()); j++) {
188  return_string[j] = (char) tolower(return_string[j]);
189  }
190 
191  return return_string;
192 }
193 
194 string BESUtil::unescape(const string &s)
195 {
196  bool done = false;
197  string::size_type index = 0;
198  /* string::size_type new_index = 0 ; */
199  string new_str;
200  while (!done) {
201  string::size_type bs = s.find('\\', index);
202  if (bs == string::npos) {
203  new_str += s.substr(index, s.length() - index);
204  done = true;
205  }
206  else {
207  new_str += s.substr(index, bs - index);
208  new_str += s[bs + 1];
209  index = bs + 2;
210  }
211  }
212 
213  return new_str;
214 }
215 
237 void BESUtil::check_path(const string &path, const string &root, bool follow_sym_links)
238 {
239  // if nothing is passed in path, then the path checks out since root is
240  // assumed to be valid.
241  if (path == "") return;
242 
243  // Rather than have two basically identical code paths for the two cases (follow and !follow symlinks)
244  // We evaluate the follow_sym_links switch and use a function pointer to get the correct "stat"
245  // function for the eval operation.
246  int (*ye_old_stat_function)(const char *pathname, struct stat *buf);
247  if (follow_sym_links) {
248  BESDEBUG(debug_key, "eval_w10n_resourceId() - Using 'stat' function (follow_sym_links = true)" << endl);
249  ye_old_stat_function = &stat;
250  }
251  else {
252  BESDEBUG(debug_key, "eval_w10n_resourceId() - Using 'lstat' function (follow_sym_links = false)" << endl);
253  ye_old_stat_function = &lstat;
254  }
255 
256  // make sure there are no ../ in the directory, backing up in any way is
257  // not allowed.
258  string::size_type dotdot = path.find("..");
259  if (dotdot != string::npos) {
260  string s = (string) "You are not allowed to access the node " + path;
261  throw BESForbiddenError(s, __FILE__, __LINE__);
262  }
263 
264  // What I want to do is to take each part of path and check to see if it
265  // is a symbolic link and it is accessible. If everything is ok, add the
266  // next part of the path.
267  bool done = false;
268 
269  // what is remaining to check
270  string rem = path;
271  if (rem[0] == '/') rem = rem.substr(1, rem.length() - 1);
272  if (rem[rem.length() - 1] == '/') rem = rem.substr(0, rem.length() - 1);
273 
274  // full path of the thing to check
275  string fullpath = root;
276  if (fullpath[fullpath.length() - 1] == '/') {
277  fullpath = fullpath.substr(0, fullpath.length() - 1);
278  }
279 
280  // path checked so far
281  string checked;
282  while (!done) {
283  size_t slash = rem.find('/');
284  if (slash == string::npos) {
285  fullpath = fullpath + "/" + rem;
286  checked = checked + "/" + rem;
287  done = true;
288  }
289  else {
290  fullpath = fullpath + "/" + rem.substr(0, slash);
291  checked = checked + "/" + rem.substr(0, slash);
292  rem = rem.substr(slash + 1, rem.length() - slash);
293  }
294 
295  struct stat buf;
296  int statret = ye_old_stat_function(fullpath.c_str(), &buf);
297  if (statret == -1) {
298  int errsv = errno;
299  // stat failed, so not accessible. Get the error string,
300  // store in error, and throw exception
301  char *s_err = strerror(errsv);
302  string error = "Unable to access node " + checked + ": ";
303  if (s_err) {
304  error = error + s_err;
305  }
306  else {
307  error = error + "unknown access error";
308  }
309 
310  BESDEBUG(debug_key, "check_path() - error: "<< error << " errno: " << errno << endl);
311 
312  // ENOENT means that the node wasn't found.
313  // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
314  // Otherwise, access is being denied for some other reason
315  if (errsv == ENOENT || errsv == ENOTDIR) {
316  // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
317  throw BESNotFoundError(error, __FILE__, __LINE__);
318  }
319  else {
320  throw BESForbiddenError(error, __FILE__, __LINE__);
321  }
322  }
323  else {
324  //The call to (stat | lstat) was successful, now check to see if it's a symlink.
325  // Note that if follow_symlinks is true then this will never evaluate as true
326  // because we'll be using 'stat' and not 'lstat' and stat will follow the link
327  // and return information about the file/dir pointed to by the symlink
328  if (S_ISLNK(buf.st_mode)) {
329  string error = "You do not have permission to access " + checked;
330  throw BESForbiddenError(error, __FILE__, __LINE__);
331  }
332  }
333  }
334 
335 #if 0
336  while (!done) {
337  size_t slash = rem.find('/');
338  if (slash == string::npos) {
339  fullpath = fullpath + "/" + rem;
340  checked = checked + "/" + rem;
341  done = true;
342  }
343  else {
344  fullpath = fullpath + "/" + rem.substr(0, slash);
345  checked = checked + "/" + rem.substr(0, slash);
346  rem = rem.substr(slash + 1, rem.length() - slash);
347  }
348 
349  if (!follow_sym_links) {
350  struct stat buf;
351  int statret = lstat(fullpath.c_str(), &buf);
352  if (statret == -1) {
353  int errsv = errno;
354  // stat failed, so not accessible. Get the error string,
355  // store in error, and throw exception
356  char *s_err = strerror(errsv);
357  string error = "Unable to access node " + checked + ": ";
358  if (s_err) {
359  error = error + s_err;
360  }
361  else {
362  error = error + "unknown access error";
363  }
364  // ENOENT means that the node wasn't found. Otherwise, access
365  // is denied for some reason
366  if (errsv == ENOENT) {
367  throw BESNotFoundError(error, __FILE__, __LINE__);
368  }
369  else {
370  throw BESForbiddenError(error, __FILE__, __LINE__);
371  }
372  }
373  else {
374  // lstat was successful, now check if sym link
375  if (S_ISLNK( buf.st_mode )) {
376  string error = "You do not have permission to access "
377  + checked;
378  throw BESForbiddenError(error, __FILE__, __LINE__);
379  }
380  }
381  }
382  else {
383  // just do a stat and see if we can access the thing. If we
384  // can't, get the error information and throw an exception
385  struct stat buf;
386  int statret = stat(fullpath.c_str(), &buf);
387  if (statret == -1) {
388  int errsv = errno;
389  // stat failed, so not accessible. Get the error string,
390  // store in error, and throw exception
391  char *s_err = strerror(errsv);
392  string error = "Unable to access node " + checked + ": ";
393  if (s_err) {
394  error = error + s_err;
395  }
396  else {
397  error = error + "unknown access error";
398  }
399  // ENOENT means that the node wasn't found. Otherwise, access
400  // is denied for some reason
401  if (errsv == ENOENT) {
402  throw BESNotFoundError(error, __FILE__, __LINE__);
403  }
404  else {
405  throw BESForbiddenError(error, __FILE__, __LINE__);
406  }
407  }
408  }
409  }
410 
411 #endif
412 }
413 
414 char *
415 BESUtil::fastpidconverter(char *buf, int base)
416 {
417  return fastpidconverter(getpid(), buf, base);
418 }
419 
420 char *
421 BESUtil::fastpidconverter(long val, /* value to be converted */
422 char *buf, /* output string */
423 int base) /* conversion base */
424 {
425  ldiv_t r; /* result of val / base */
426 
427  if (base > 36 || base < 2) /* no conversion if wrong base */
428  {
429  *buf = '\0';
430  return buf;
431  }
432  if (val < 0) *buf++ = '-';
433  r = ldiv(labs(val), base);
434 
435  /* output digits of val/base first */
436 
437  if (r.quot > 0) buf = fastpidconverter(r.quot, buf, base);
438  /* output last digit */
439 
440  *buf++ = "0123456789abcdefghijklmnopqrstuvwxyz"[(int) r.rem];
441  *buf = '\0';
442  return buf;
443 }
444 
446 {
447  if (!key.empty()) {
448  string::size_type first = key.find_first_not_of(" \t\n\r");
449  string::size_type last = key.find_last_not_of(" \t\n\r");
450  if (first == string::npos)
451  key = "";
452  else {
453  string::size_type num = last - first + 1;
454  string new_key = key.substr(first, num);
455  key = new_key;
456  }
457  }
458 }
459 
460 string BESUtil::entity(char c)
461 {
462  switch (c) {
463  case '>':
464  return "&gt;";
465  case '<':
466  return "&lt;";
467  case '&':
468  return "&amp;";
469  case '\'':
470  return "&apos;";
471  case '\"':
472  return "&quot;";
473  default:
474  return string(1, c); // is this proper default, just the char?
475  }
476 }
477 
484 string BESUtil::id2xml(string in, const string &not_allowed)
485 {
486  string::size_type i = 0;
487 
488  while ((i = in.find_first_of(not_allowed, i)) != string::npos) {
489  in.replace(i, 1, entity(in[i]));
490  i++;
491  }
492 
493  return in;
494 }
495 
501 string BESUtil::xml2id(string in)
502 {
503  string::size_type i = 0;
504 
505  while ((i = in.find("&gt;", i)) != string::npos)
506  in.replace(i, 4, ">");
507 
508  i = 0;
509  while ((i = in.find("&lt;", i)) != string::npos)
510  in.replace(i, 4, "<");
511 
512  i = 0;
513  while ((i = in.find("&amp;", i)) != string::npos)
514  in.replace(i, 5, "&");
515 
516  i = 0;
517  while ((i = in.find("&apos;", i)) != string::npos)
518  in.replace(i, 6, "'");
519 
520  i = 0;
521  while ((i = in.find("&quot;", i)) != string::npos)
522  in.replace(i, 6, "\"");
523 
524  return in;
525 }
526 
540 void BESUtil::explode(char delim, const string &str, list<string> &values)
541 {
542  std::string::size_type start = 0;
543  std::string::size_type qstart = 0;
544  std::string::size_type adelim = 0;
545  std::string::size_type aquote = 0;
546  bool done = false;
547  while (!done) {
548  string aval;
549  if (str[start] == '"') {
550  bool endquote = false;
551  qstart = start + 1;
552  while (!endquote) {
553  aquote = str.find('"', qstart);
554  if (aquote == string::npos) {
555  string currval = str.substr(start, str.length() - start);
556  string err = "BESUtil::explode - No end quote after value " + currval;
557  throw BESInternalError(err, __FILE__, __LINE__);
558  }
559  // could be an escaped escape character and an escaped
560  // quote, or an escaped escape character and a quote
561  if (str[aquote - 1] == '\\') {
562  if (str[aquote - 2] == '\\') {
563  endquote = true;
564  qstart = aquote + 1;
565  }
566  else {
567  qstart = aquote + 1;
568  }
569  }
570  else {
571  endquote = true;
572  qstart = aquote + 1;
573  }
574  }
575  if (str[qstart] != delim && qstart != str.length()) {
576  string currval = str.substr(start, qstart - start);
577  string err = "BESUtil::explode - No delim after end quote " + currval;
578  throw BESInternalError(err, __FILE__, __LINE__);
579  }
580  if (qstart == str.length()) {
581  adelim = string::npos;
582  }
583  else {
584  adelim = qstart;
585  }
586  }
587  else {
588  adelim = str.find(delim, start);
589  }
590  if (adelim == string::npos) {
591  aval = str.substr(start, str.length() - start);
592  done = true;
593  }
594  else {
595  aval = str.substr(start, adelim - start);
596  }
597 
598  values.push_back(aval);
599  start = adelim + 1;
600  if (start == str.length()) {
601  values.push_back("");
602  done = true;
603  }
604  }
605 }
606 
617 string BESUtil::implode(const list<string> &values, char delim)
618 {
619  string result;
620  list<string>::const_iterator i = values.begin();
621  list<string>::const_iterator e = values.end();
622  bool first = true;
623  string::size_type d; // = string::npos ;
624  for (; i != e; i++) {
625  if (!first) result += delim;
626  d = (*i).find(delim);
627  if (d != string::npos && (*i)[0] != '"') {
628  string err = (string) "BESUtil::implode - delimiter exists in value " + (*i);
629  throw BESInternalError(err, __FILE__, __LINE__);
630  }
631  //d = string::npos ;
632  result += (*i);
633  first = false;
634  }
635  return result;
636 }
637 
657 void BESUtil::url_explode(const string &url_str, BESUtil::url &url_parts)
658 {
659  string rest;
660 
661  string::size_type colon = url_str.find(":");
662  if (colon == string::npos) {
663  string err = "BESUtil::url_explode: missing colon for protocol";
664  throw BESInternalError(err, __FILE__, __LINE__);
665  }
666 
667  url_parts.protocol = url_str.substr(0, colon);
668 
669  if (url_str.substr(colon, 3) != "://") {
670  string err = "BESUtil::url_explode: no :// in the URL";
671  throw BESInternalError(err, __FILE__, __LINE__);
672  }
673 
674  colon += 3;
675  rest = url_str.substr(colon);
676 
677  string::size_type slash = rest.find("/");
678  if (slash == string::npos) slash = rest.length();
679 
680  string::size_type at = rest.find("@");
681  if ((at != string::npos) && (at < slash)) {
682  // everything before the @ is username:password
683  string up = rest.substr(0, at);
684  colon = up.find(":");
685  if (colon != string::npos) {
686  url_parts.uname = up.substr(0, colon);
687  url_parts.psswd = up.substr(colon + 1);
688  }
689  else {
690  url_parts.uname = up;
691  }
692  // everything after the @ is domain/path
693  rest = rest.substr(at + 1);
694  }
695  slash = rest.find("/");
696  if (slash == string::npos) slash = rest.length();
697  colon = rest.find(":");
698  if ((colon != string::npos) && (colon < slash)) {
699  // everything before the colon is the domain
700  url_parts.domain = rest.substr(0, colon);
701  // everything after the folon is port/path
702  rest = rest.substr(colon + 1);
703  slash = rest.find("/");
704  if (slash != string::npos) {
705  url_parts.port = rest.substr(0, slash);
706  url_parts.path = rest.substr(slash + 1);
707  }
708  else {
709  url_parts.port = rest;
710  url_parts.path = "";
711  }
712  }
713  else {
714  slash = rest.find("/");
715  if (slash != string::npos) {
716  url_parts.domain = rest.substr(0, slash);
717  url_parts.path = rest.substr(slash + 1);
718  }
719  else {
720  url_parts.domain = rest;
721  }
722  }
723 }
724 
725 string BESUtil::url_create(BESUtil::url &url_parts)
726 {
727  string url = url_parts.protocol + "://";
728  if (!url_parts.uname.empty()) {
729  url += url_parts.uname;
730  if (!url_parts.psswd.empty()) url += ":" + url_parts.psswd;
731  url += "@";
732  }
733  url += url_parts.domain;
734  if (!url_parts.port.empty()) url += ":" + url_parts.port;
735  if (!url_parts.path.empty()) url += "/" + url_parts.path;
736 
737  return url;
738 }
739 
747 string BESUtil::assemblePath(const string &firstPart, const string &secondPart, bool ensureLeadingSlash){
748 
749  //BESDEBUG("util", "BESUtil::assemblePath() - BEGIN" << endl);
750  //BESDEBUG("util", "BESUtil::assemblePath() - firstPart: "<< firstPart << endl);
751  //BESDEBUG("util", "BESUtil::assemblePath() - secondPart: "<< secondPart << endl);
752 
753  string firstPathFragment = firstPart;
754  string secondPathFragment = secondPart;
755 
756 
757  if(ensureLeadingSlash){
758  if(*firstPathFragment.begin() != '/')
759  firstPathFragment = "/" + firstPathFragment;
760  }
761 
762  // make sure there are not multiple slashes at the end of the first part...
763  while(*firstPathFragment.rbegin() == '/' && firstPathFragment.length()>0){
764  firstPathFragment = firstPathFragment.substr(0,firstPathFragment.length()-1);
765  //BESDEBUG("util", "BESUtil::assemblePath() - firstPathFragment: "<< firstPathFragment << endl);
766  }
767 
768  // make sure first part ends with a "/"
769  if(*firstPathFragment.rbegin() != '/'){
770  firstPathFragment += "/";
771  }
772  //BESDEBUG("util", "BESUtil::assemblePath() - firstPathFragment: "<< firstPathFragment << endl);
773 
774  // make sure second part does not BEGIN with a slash
775  while(*secondPathFragment.begin() == '/' && secondPathFragment.length()>0){
776  secondPathFragment = secondPathFragment.substr(1);
777  }
778 
779  //BESDEBUG("util", "BESUtil::assemblePath() - secondPathFragment: "<< secondPathFragment << endl);
780 
781  string newPath = firstPathFragment + secondPathFragment;
782 
783  //BESDEBUG("util", "BESUtil::assemblePath() - newPath: "<< newPath << endl);
784  //BESDEBUG("util", "BESUtil::assemblePath() - END" << endl);
785 
786  return newPath;
787 }
error thrown if the resource requested cannot be found
static string id2xml(string in, const string &not_allowed="><&'\"")
Definition: BESUtil.cc:484
exception thrown if inernal error encountered
static string lowercase(const string &s)
Definition: BESUtil.cc:184
static string www2id(const string &in, const string &escape="%", const string &except="")
Definition: BESUtil.cc:169
static void removeLeadingAndTrailingBlanks(string &key)
Definition: BESUtil.cc:445
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:747
static string implode(const list< string > &values, char delim)
Definition: BESUtil.cc:617
static string xml2id(string in)
Definition: BESUtil.cc:501
static void set_mime_html(ostream &strm)
Generate an HTTP 1.0 response header for a html document.
Definition: BESUtil.cc:86
static void explode(char delim, const string &str, list< string > &values)
Definition: BESUtil.cc:540
static void set_mime_text(ostream &strm)
Generate an HTTP 1.0 response header for a text document.
Definition: BESUtil.cc:67
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:657
error thrown if the BES is not allowed to access the resource requested
static char * fastpidconverter(char *buf, int base)
Definition: BESUtil.cc:415
static string unescape(const string &s)
Definition: BESUtil.cc:194
static void check_path(const string &path, const string &root, bool follow_sym_links)
Definition: BESUtil.cc:237