35 #include <sys/types.h>
54 using std::stringstream;
55 using std::istringstream;
63 #include "TheBESKeys.h"
66 #include "BESForbiddenError.h"
67 #include "BESNotFoundError.h"
68 #include "BESInternalError.h"
70 #include "BESCatalogList.h"
74 #define debug_key "util"
75 #define prolog string("BESUtil::").append(__func__).append("() - ")
77 const string BES_KEY_TIMEOUT_CANCEL =
"BES.CancelTimeoutOnSend";
85 strm <<
"HTTP/1.0 200 OK" << CRLF;
86 strm <<
"XBES-Server: " << PACKAGE_STRING << CRLF;
88 const time_t t = time(0);
89 strm <<
"Date: " << rfc822_date(t).c_str() << CRLF;
90 strm <<
"Last-Modified: " << rfc822_date(t).c_str() << CRLF;
92 strm <<
"Content-Type: text/plain" << CRLF;
94 strm <<
"Content-Description: unknown" << CRLF;
104 strm <<
"HTTP/1.0 200 OK" << CRLF;
105 strm <<
"XBES-Server: " << PACKAGE_STRING << CRLF;
107 const time_t t = time(0);
108 strm <<
"Date: " << rfc822_date(t).c_str() << CRLF;
109 strm <<
"Last-Modified: " << rfc822_date(t).c_str() << CRLF;
111 strm <<
"Content-type: text/html" << CRLF;
113 strm <<
"Content-Description: unknown" << CRLF;
149 static const char *days[] = {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat" };
150 static const char *months[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" };
161 string BESUtil::rfc822_date(
const time_t t)
163 struct tm *stm = gmtime(&t);
166 snprintf(d, 255,
"%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday], stm->tm_mday, months[stm->tm_mon], 1900 + stm->tm_year, stm->tm_hour,
167 stm->tm_min, stm->tm_sec);
172 string BESUtil::unhexstring(
string s)
176 ss >> std::hex >> val;
178 tmp_str[0] =
static_cast<char>(val);
180 return string(tmp_str);
187 string::size_type i = 0;
189 while ((i = res.find_first_of(escape, i)) != string::npos) {
190 if (except.find(res.substr(i, 3)) != string::npos) {
194 res.replace(i, 3, unhexstring(res.substr(i + 1, 2)));
202 string return_string = s;
203 for (
int j = 0; j < static_cast<int>(return_string.length()); j++) {
204 return_string[j] = (char) tolower(return_string[j]);
207 return return_string;
213 string::size_type index = 0;
217 string::size_type bs = s.find(
'\\', index);
218 if (bs == string::npos) {
219 new_str += s.substr(index, s.length() - index);
223 new_str += s.substr(index, bs - index);
224 new_str += s[bs + 1];
258 if (path ==
"")
return;
263 int (*ye_old_stat_function)(
const char *pathname,
struct stat *buf);
264 if (follow_sym_links) {
265 BESDEBUG(debug_key,
"check_path() - Using 'stat' function (follow_sym_links = true)" << endl);
266 ye_old_stat_function = &stat;
269 BESDEBUG(debug_key,
"check_path() - Using 'lstat' function (follow_sym_links = false)" << endl);
270 ye_old_stat_function = &lstat;
275 string::size_type dotdot = path.find(
"..");
276 if (dotdot != string::npos) {
277 string s = (string)
"You are not allowed to access the node " + path;
288 if (rem[0] ==
'/') rem = rem.substr(1);
289 if (rem[rem.length() - 1] ==
'/') rem = rem.substr(0, rem.length() - 1);
292 string fullpath = root;
293 if (fullpath[fullpath.length() - 1] ==
'/') {
294 fullpath = fullpath.substr(0, fullpath.length() - 1);
300 size_t slash = rem.find(
'/');
301 if (slash == string::npos) {
303 fullpath.append(
"/").append(rem);
309 fullpath.append(
"/").append(rem.substr(0, slash));
312 rem = rem.substr(slash + 1, rem.length() - slash);
318 int statret = ye_old_stat_function(fullpath.c_str(), &buf);
323 char *s_err = strerror(errsv);
325 string error =
"Unable to access node " + fullpath +
": ";
329 error.append(
"unknown error");
331 BESDEBUG(debug_key,
"check_path() - error: "<< error <<
" errno: " << errno << endl);
336 if (errsv == ENOENT || errsv == ENOTDIR) {
349 if (S_ISLNK(buf.st_mode)) {
351 throw BESForbiddenError(
string(
"You do not have permission to access ") + fullpath, __FILE__, __LINE__);
358 size_t slash = rem.find(
'/');
359 if (slash == string::npos) {
360 fullpath = fullpath +
"/" + rem;
361 checked = checked +
"/" + rem;
365 fullpath = fullpath +
"/" + rem.substr(0, slash);
366 checked = checked +
"/" + rem.substr(0, slash);
367 rem = rem.substr(slash + 1, rem.length() - slash);
370 if (!follow_sym_links) {
372 int statret = lstat(fullpath.c_str(), &buf);
377 char *s_err = strerror(errsv);
378 string error =
"Unable to access node " + checked +
": ";
380 error = error + s_err;
383 error = error +
"unknown access error";
387 if (errsv == ENOENT) {
396 if (S_ISLNK( buf.st_mode )) {
397 string error =
"You do not have permission to access "
407 int statret = stat(fullpath.c_str(), &buf);
412 char *s_err = strerror(errsv);
413 string error =
"Unable to access node " + checked +
": ";
415 error = error + s_err;
418 error = error +
"unknown access error";
422 if (errsv == ENOENT) {
448 if (base > 36 || base < 2)
453 if (val < 0) *buf++ =
'-';
454 r = ldiv(labs(val), base);
461 *buf++ =
"0123456789abcdefghijklmnopqrstuvwxyz"[(
int) r.rem];
469 string::size_type first = key.find_first_not_of(
" \t\n\r");
470 string::size_type last = key.find_last_not_of(
" \t\n\r");
471 if (first == string::npos)
474 string::size_type num = last - first + 1;
475 string new_key = key.substr(first, num);
481 string BESUtil::entity(
char c)
507 string::size_type i = 0;
509 while ((i = in.find_first_of(not_allowed, i)) != string::npos) {
510 in.replace(i, 1, entity(in[i]));
524 string::size_type i = 0;
526 while ((i = in.find(
">", i)) != string::npos)
527 in.replace(i, 4,
">");
530 while ((i = in.find(
"<", i)) != string::npos)
531 in.replace(i, 4,
"<");
534 while ((i = in.find(
"&", i)) != string::npos)
535 in.replace(i, 5,
"&");
538 while ((i = in.find(
"'", i)) != string::npos)
539 in.replace(i, 6,
"'");
542 while ((i = in.find(
""", i)) != string::npos)
543 in.replace(i, 6,
"\"");
563 std::string::size_type start = 0;
564 std::string::size_type qstart = 0;
565 std::string::size_type adelim = 0;
566 std::string::size_type aquote = 0;
570 if (str[start] ==
'"') {
571 bool endquote =
false;
574 aquote = str.find(
'"', qstart);
575 if (aquote == string::npos) {
576 string currval = str.substr(start, str.length() - start);
577 string err =
"BESUtil::explode - No end quote after value " + currval;
582 if (str[aquote - 1] ==
'\\') {
583 if (str[aquote - 2] ==
'\\') {
596 if (str[qstart] != delim && qstart != str.length()) {
597 string currval = str.substr(start, qstart - start);
598 string err =
"BESUtil::explode - No delim after end quote " + currval;
601 if (qstart == str.length()) {
602 adelim = string::npos;
609 adelim = str.find(delim, start);
611 if (adelim == string::npos) {
612 aval = str.substr(start, str.length() - start);
616 aval = str.substr(start, adelim - start);
619 values.push_back(aval);
621 if (start == str.length()) {
622 values.push_back(
"");
641 list<string>::const_iterator i = values.begin();
642 list<string>::const_iterator e = values.end();
645 for (; i != e; i++) {
646 if (!first) result += delim;
647 d = (*i).find(delim);
648 if (d != string::npos && (*i)[0] !=
'"') {
649 string err = (string)
"BESUtil::implode - delimiter exists in value " + (*i);
682 string::size_type colon = url_str.find(
":");
683 if (colon == string::npos) {
684 string err =
"BESUtil::url_explode: missing colon for protocol";
688 url_parts.protocol = url_str.substr(0, colon);
690 if (url_str.substr(colon, 3) !=
"://") {
691 string err =
"BESUtil::url_explode: no :// in the URL";
696 rest = url_str.substr(colon);
698 string::size_type slash = rest.find(
"/");
699 if (slash == string::npos) slash = rest.length();
701 string::size_type at = rest.find(
"@");
702 if ((at != string::npos) && (at < slash)) {
704 string up = rest.substr(0, at);
705 colon = up.find(
":");
706 if (colon != string::npos) {
707 url_parts.uname = up.substr(0, colon);
708 url_parts.psswd = up.substr(colon + 1);
711 url_parts.uname = up;
714 rest = rest.substr(at + 1);
716 slash = rest.find(
"/");
717 if (slash == string::npos) slash = rest.length();
718 colon = rest.find(
":");
719 if ((colon != string::npos) && (colon < slash)) {
721 url_parts.domain = rest.substr(0, colon);
723 rest = rest.substr(colon + 1);
724 slash = rest.find(
"/");
725 if (slash != string::npos) {
726 url_parts.port = rest.substr(0, slash);
727 url_parts.path = rest.substr(slash + 1);
730 url_parts.port = rest;
735 slash = rest.find(
"/");
736 if (slash != string::npos) {
737 url_parts.domain = rest.substr(0, slash);
738 url_parts.path = rest.substr(slash + 1);
741 url_parts.domain = rest;
748 string url = url_parts.protocol +
"://";
749 if (!url_parts.uname.empty()) {
750 url += url_parts.uname;
751 if (!url_parts.psswd.empty()) url +=
":" + url_parts.psswd;
754 url += url_parts.domain;
755 if (!url_parts.port.empty()) url +=
":" + url_parts.port;
756 if (!url_parts.path.empty()) url +=
"/" + url_parts.path;
774 string first = firstPart;
775 string second = secondPart;
776 string sep(1,separator);
780 while (!first.empty() && *first.rbegin() == separator) {
782 first = first.substr(0, first.length() - 1);
785 while (!second.empty() && second[0] == separator) {
793 else if (second.empty()) {
797 newPath = first.append(sep).append(second);
821 string BESUtil::assemblePath(
const string &firstPart,
const string &secondPart,
bool leadingSlash,
bool trailingSlash)
824 assert(!firstPart.empty());
827 string first = firstPart;
828 string second = secondPart;
831 if (ensureLeadingSlash && first[0] !=
'/')
835 if (second[0] ==
'/')
836 second = second.substr(1);
839 if (first.back() ==
'/')
840 return first.append(second);
842 return first.append(
"/").append(second);
846 BESDEBUG(debug_key, prolog <<
"firstPart: '" << firstPart <<
"'" << endl);
847 BESDEBUG(debug_key, prolog <<
"secondPart: '" << secondPart <<
"'" << endl);
852 string first = firstPart;
853 string second = secondPart;
857 while (!first.empty() && *first.rbegin() ==
'/') {
859 first = first.substr(0, first.length() - 1);
863 while (!second.empty() && second[0] ==
'/') {
873 else if (second.empty()) {
877 newPath = first.append(
"/").append(second);
883 if (newPath.empty()) {
886 else if (newPath.compare(0, 1,
"/")) {
887 newPath =
"/" + newPath;
892 if (newPath.compare(newPath.length(), 1,
"/")) {
893 newPath = newPath.append(
"/");
897 while(newPath.length()>1 && *newPath.rbegin() ==
'/')
898 newPath = newPath.substr(0,newPath.length()-1);
900 BESDEBUG(debug_key, prolog <<
"newPath: "<< newPath << endl);
905 BESDEBUG(
"util",
"BESUtil::assemblePath() - firstPart: "<< firstPart << endl);
906 BESDEBUG(
"util",
"BESUtil::assemblePath() - secondPart: "<< secondPart << endl);
908 string first = firstPart;
909 string second = secondPart;
911 if (ensureLeadingSlash) {
912 if (*first.begin() !=
'/') first =
"/" + first;
916 while (*first.rbegin() ==
'/' && first.length() > 0) {
917 first = first.substr(0, first.length() - 1);
921 if (*first.rbegin() !=
'/') {
926 while (*second.begin() ==
'/' && second.length() > 0) {
927 second = second.substr(1);
930 string newPath = first + second;
932 BESDEBUG(
"util",
"BESUtil::assemblePath() - newPath: "<< newPath << endl);
944 if (fullString.length() >= ending.length()) {
945 return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending));
969 bool cancel_timeout_on_send =
false;
972 const string dosettrue =
"true";
973 const string dosetyes =
"yes";
978 if (dosettrue == doset || dosetyes == doset) cancel_timeout_on_send =
true;
980 BESDEBUG(debug_key, __func__ <<
"() - cancel_timeout_on_send: " <<(cancel_timeout_on_send?
"true":
"false") << endl);
981 if (cancel_timeout_on_send) alarm(0);
991 size_t pos = s.find(find_this);
992 while (pos != string::npos) {
994 s.replace(pos, find_this.size(), replace_with_this);
996 pos = s.find(find_this, pos + find_this.size());
1013 if (separator.length() != 1)
1014 throw BESInternalError(
"Path separators must be a single character. The string '" + separator +
"' does not qualify.", __FILE__, __LINE__);
1015 char separator_char = separator[0];
1016 string double_separator;
1017 double_separator = double_separator.append(separator).append(separator);
1019 string path(raw_path);
1026 if (path == separator) {
1029 if (leading_separator) {
1030 if (path[0] != separator_char) {
1031 path = string(separator).append(path);
1035 if (path[0] == separator_char) {
1036 path = path.substr(1);
1039 if (trailing_separator) {
1040 if (*path.rbegin() != separator_char) {
1041 path = path.append(separator);
1045 if (*path.rbegin() == separator_char) {
1046 path = path.substr(0, path.length() - 1);
1060 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
1062 string::size_type pos = str.find_first_of(delimiters, lastPos);
1063 while (string::npos != pos || string::npos != lastPos) {
1065 tokens.push_back(str.substr(lastPos, pos - lastPos));
1067 lastPos = str.find_first_not_of(delimiters, pos);
1069 pos = str.find_first_of(delimiters, lastPos);
1081 return get_time(time(0), use_local_time);
1093 char buf[
sizeof "YYYY-MM-DDTHH:MM:SS zones"];
1102 if (!use_local_time)
1103 status = strftime(buf,
sizeof buf,
"%FT%T%Z", gmtime(&the_time));
1105 status = strftime(buf,
sizeof buf,
"%FT%T%Z", localtime(&the_time));
1108 LOG(prolog +
"Error formatting time value!");
1109 return "date-format-error";
1129 vector<string> tokens;
1131 while (getline(ss, item, delim)) {
1133 if (item.empty() && skip_empty)
1136 tokens.push_back(item);
1140 if (skip_empty && !item.empty())
1141 tokens.push_back(item);
1149 BESCatalog *BESUtil::separateCatalogFromPath(std::string &ppath)
1152 vector<string> path_tokens;
1156 BESDEBUG(debug_key, prolog <<
"Normalized path: " << path << endl);
1161 string use_container = ppath;
1165 if (!path_tokens.empty()) {
1166 BESDEBUG(debug_key,
"First path token: " << path_tokens[0] << endl);
1169 BESDEBUG(debug_key, prolog <<
"Located catalog " << catalog->
get_catalog_name() <<
" from path component" << endl);
1174 BESDEBUG(debug_key, prolog <<
"Modified container/path value to: " << use_container << endl);
static BESCatalogList * TheCatalogList()
Get the singleton BESCatalogList instance.
Catalogs provide a hierarchical organization for data.
virtual std::string get_catalog_name() const
Get the name for this catalog.
error thrown if the BES is not allowed to access the resource requested
exception thrown if internal error encountered
error thrown if the resource requested cannot be found
static std::vector< std::string > split(const std::string &s, char delim='/', bool skip_empty=true)
Splits the string s into the return vector of tokens using the delimiter delim and skipping empty val...
static void explode(char delim, const std::string &str, std::list< std::string > &values)
static void url_explode(const std::string &url_str, BESUtil::url &url_parts)
Given a url, break the url into its different parts.
static bool endsWith(std::string const &fullString, std::string const &ending)
static void tokenize(const std::string &str, std::vector< std::string > &tokens, const std::string &delimiters="/")
static void replace_all(std::string &s, std::string find_this, std::string replace_with_this)
Operates on the string 's' to replaces every occurrence of the value of the string 'find_this' with t...
static void set_mime_text(std::ostream &strm)
Generate an HTTP 1.0 response header for a text document.
static std::string id2xml(std::string in, const std::string ¬_allowed="><&'\"")
static void conditional_timeout_cancel()
static void check_path(const std::string &path, const std::string &root, bool follow_sym_links)
Check if the specified path is valid.
static void set_mime_html(std::ostream &strm)
Generate an HTTP 1.0 response header for a html document.
static std::string lowercase(const std::string &s)
static std::string pathConcat(const std::string &firstPart, const std::string &secondPart, char separator='/')
Concatenate path fragments making sure that they are separated by a single '/' character.
static std::string assemblePath(const std::string &firstPart, const std::string &secondPart, bool leadingSlash=false, bool trailingSlash=false)
Assemble path fragments making sure that they are separated by a single '/' character.
static std::string www2id(const std::string &in, const std::string &escape="%", const std::string &except="")
static std::string implode(const std::list< std::string > &values, char delim)
static std::string xml2id(std::string in)
static std::string normalize_path(const std::string &path, bool leading_separator, bool trailing_separator, const std::string separator="/")
Removes duplicate separators and provides leading and trailing separators as directed.
static std::string unescape(const std::string &s)
static char * fastpidconverter(char *buf, int base)
static void removeLeadingAndTrailingBlanks(std::string &key)
static std::string get_time(bool use_local_time=false)
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()