35 #include <sys/types.h> 53 using std::stringstream;
54 using std::istringstream;
60 #include "TheBESKeys.h" 63 #include "BESForbiddenError.h" 64 #include "BESNotFoundError.h" 65 #include "BESInternalError.h" 67 #include "BESCatalogList.h" 71 #define debug_key "util" 72 #define prolog string("BESUtil::").append(__func__).append("() - ") 74 const string BES_KEY_TIMEOUT_CANCEL =
"BES.CancelTimeoutOnSend";
82 strm <<
"HTTP/1.0 200 OK" << CRLF;
83 strm <<
"XBES-Server: " << PACKAGE_STRING << CRLF;
85 const time_t t = time(0);
86 strm <<
"Date: " << rfc822_date(t).c_str() << CRLF;
87 strm <<
"Last-Modified: " << rfc822_date(t).c_str() << CRLF;
89 strm <<
"Content-Type: text/plain" << CRLF;
91 strm <<
"Content-Description: unknown" << CRLF;
101 strm <<
"HTTP/1.0 200 OK" << CRLF;
102 strm <<
"XBES-Server: " << PACKAGE_STRING << CRLF;
104 const time_t t = time(0);
105 strm <<
"Date: " << rfc822_date(t).c_str() << CRLF;
106 strm <<
"Last-Modified: " << rfc822_date(t).c_str() << CRLF;
108 strm <<
"Content-type: text/html" << CRLF;
110 strm <<
"Content-Description: unknown" << CRLF;
146 static const char *days[] = {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat" };
147 static const char *months[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" };
158 string BESUtil::rfc822_date(
const time_t t)
160 struct tm *stm = gmtime(&t);
163 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,
164 stm->tm_min, stm->tm_sec);
169 string BESUtil::unhexstring(
string s)
173 ss >> std::hex >> val;
175 tmp_str[0] = static_cast<char>(val);
177 return string(tmp_str);
184 string::size_type i = 0;
186 while ((i = res.find_first_of(escape, i)) != string::npos) {
187 if (except.find(res.substr(i, 3)) != string::npos) {
191 res.replace(i, 3, unhexstring(res.substr(i + 1, 2)));
199 string return_string = s;
200 for (
int j = 0; j < static_cast<int>(return_string.length()); j++) {
201 return_string[j] = (char) tolower(return_string[j]);
204 return return_string;
210 string::size_type index = 0;
214 string::size_type bs = s.find(
'\\', index);
215 if (bs == string::npos) {
216 new_str += s.substr(index, s.length() - index);
220 new_str += s.substr(index, bs - index);
221 new_str += s[bs + 1];
255 if (path ==
"")
return;
260 int (*ye_old_stat_function)(
const char *pathname,
struct stat *buf);
261 if (follow_sym_links) {
262 BESDEBUG(debug_key,
"check_path() - Using 'stat' function (follow_sym_links = true)" << endl);
263 ye_old_stat_function = &stat;
266 BESDEBUG(debug_key,
"check_path() - Using 'lstat' function (follow_sym_links = false)" << endl);
267 ye_old_stat_function = &lstat;
272 string::size_type dotdot = path.find(
"..");
273 if (dotdot != string::npos) {
274 string s = (string)
"You are not allowed to access the node " + path;
285 if (rem[0] ==
'/') rem = rem.substr(1);
286 if (rem[rem.length() - 1] ==
'/') rem = rem.substr(0, rem.length() - 1);
289 string fullpath = root;
290 if (fullpath[fullpath.length() - 1] ==
'/') {
291 fullpath = fullpath.substr(0, fullpath.length() - 1);
297 size_t slash = rem.find(
'/');
298 if (slash == string::npos) {
300 fullpath.append(
"/").append(rem);
306 fullpath.append(
"/").append(rem.substr(0, slash));
309 rem = rem.substr(slash + 1, rem.length() - slash);
315 int statret = ye_old_stat_function(fullpath.c_str(), &buf);
320 char *s_err = strerror(errsv);
322 string error =
"Unable to access node " + fullpath +
": ";
326 error.append(
"unknown error");
328 BESDEBUG(debug_key,
"check_path() - error: "<< error <<
" errno: " << errno << endl);
333 if (errsv == ENOENT || errsv == ENOTDIR) {
346 if (S_ISLNK(buf.st_mode)) {
348 throw BESForbiddenError(
string(
"You do not have permission to access ") + fullpath, __FILE__, __LINE__);
355 size_t slash = rem.find(
'/');
356 if (slash == string::npos) {
357 fullpath = fullpath +
"/" + rem;
358 checked = checked +
"/" + rem;
362 fullpath = fullpath +
"/" + rem.substr(0, slash);
363 checked = checked +
"/" + rem.substr(0, slash);
364 rem = rem.substr(slash + 1, rem.length() - slash);
367 if (!follow_sym_links) {
369 int statret = lstat(fullpath.c_str(), &buf);
374 char *s_err = strerror(errsv);
375 string error =
"Unable to access node " + checked +
": ";
377 error = error + s_err;
380 error = error +
"unknown access error";
384 if (errsv == ENOENT) {
393 if (S_ISLNK( buf.st_mode )) {
394 string error =
"You do not have permission to access " 404 int statret = stat(fullpath.c_str(), &buf);
409 char *s_err = strerror(errsv);
410 string error =
"Unable to access node " + checked +
": ";
412 error = error + s_err;
415 error = error +
"unknown access error";
419 if (errsv == ENOENT) {
445 if (base > 36 || base < 2)
450 if (val < 0) *buf++ =
'-';
451 r = ldiv(labs(val), base);
458 *buf++ =
"0123456789abcdefghijklmnopqrstuvwxyz"[(int) r.rem];
466 string::size_type first = key.find_first_not_of(
" \t\n\r");
467 string::size_type last = key.find_last_not_of(
" \t\n\r");
468 if (first == string::npos)
471 string::size_type num = last - first + 1;
472 string new_key = key.substr(first, num);
478 string BESUtil::entity(
char c)
504 string::size_type i = 0;
506 while ((i = in.find_first_of(not_allowed, i)) != string::npos) {
507 in.replace(i, 1, entity(in[i]));
521 string::size_type i = 0;
523 while ((i = in.find(
">", i)) != string::npos)
524 in.replace(i, 4,
">");
527 while ((i = in.find(
"<", i)) != string::npos)
528 in.replace(i, 4,
"<");
531 while ((i = in.find(
"&", i)) != string::npos)
532 in.replace(i, 5,
"&");
535 while ((i = in.find(
"'", i)) != string::npos)
536 in.replace(i, 6,
"'");
539 while ((i = in.find(
""", i)) != string::npos)
540 in.replace(i, 6,
"\"");
560 std::string::size_type start = 0;
561 std::string::size_type qstart = 0;
562 std::string::size_type adelim = 0;
563 std::string::size_type aquote = 0;
567 if (str[start] ==
'"') {
568 bool endquote =
false;
571 aquote = str.find(
'"', qstart);
572 if (aquote == string::npos) {
573 string currval = str.substr(start, str.length() - start);
574 string err =
"BESUtil::explode - No end quote after value " + currval;
579 if (str[aquote - 1] ==
'\\') {
580 if (str[aquote - 2] ==
'\\') {
593 if (str[qstart] != delim && qstart != str.length()) {
594 string currval = str.substr(start, qstart - start);
595 string err =
"BESUtil::explode - No delim after end quote " + currval;
598 if (qstart == str.length()) {
599 adelim = string::npos;
606 adelim = str.find(delim, start);
608 if (adelim == string::npos) {
609 aval = str.substr(start, str.length() - start);
613 aval = str.substr(start, adelim - start);
616 values.push_back(aval);
618 if (start == str.length()) {
619 values.push_back(
"");
638 list<string>::const_iterator i = values.begin();
639 list<string>::const_iterator e = values.end();
642 for (; i != e; i++) {
643 if (!first) result += delim;
644 d = (*i).find(delim);
645 if (d != string::npos && (*i)[0] !=
'"') {
646 string err = (string)
"BESUtil::implode - delimiter exists in value " + (*i);
679 string::size_type colon = url_str.find(
":");
680 if (colon == string::npos) {
681 string err =
"BESUtil::url_explode: missing colon for protocol";
685 url_parts.protocol = url_str.substr(0, colon);
687 if (url_str.substr(colon, 3) !=
"://") {
688 string err =
"BESUtil::url_explode: no :// in the URL";
693 rest = url_str.substr(colon);
695 string::size_type slash = rest.find(
"/");
696 if (slash == string::npos) slash = rest.length();
698 string::size_type at = rest.find(
"@");
699 if ((at != string::npos) && (at < slash)) {
701 string up = rest.substr(0, at);
702 colon = up.find(
":");
703 if (colon != string::npos) {
704 url_parts.uname = up.substr(0, colon);
705 url_parts.psswd = up.substr(colon + 1);
708 url_parts.uname = up;
711 rest = rest.substr(at + 1);
713 slash = rest.find(
"/");
714 if (slash == string::npos) slash = rest.length();
715 colon = rest.find(
":");
716 if ((colon != string::npos) && (colon < slash)) {
718 url_parts.domain = rest.substr(0, colon);
720 rest = rest.substr(colon + 1);
721 slash = rest.find(
"/");
722 if (slash != string::npos) {
723 url_parts.port = rest.substr(0, slash);
724 url_parts.path = rest.substr(slash + 1);
727 url_parts.port = rest;
732 slash = rest.find(
"/");
733 if (slash != string::npos) {
734 url_parts.domain = rest.substr(0, slash);
735 url_parts.path = rest.substr(slash + 1);
738 url_parts.domain = rest;
745 string url = url_parts.protocol +
"://";
746 if (!url_parts.uname.empty()) {
747 url += url_parts.uname;
748 if (!url_parts.psswd.empty()) url +=
":" + url_parts.psswd;
751 url += url_parts.domain;
752 if (!url_parts.port.empty()) url +=
":" + url_parts.port;
753 if (!url_parts.path.empty()) url +=
"/" + url_parts.path;
771 string first = firstPart;
772 string second = secondPart;
773 string sep(1,separator);
777 while (!first.empty() && *first.rbegin() == separator) {
779 first = first.substr(0, first.length() - 1);
782 while (!second.empty() && second[0] == separator) {
790 else if (second.empty()) {
794 newPath = first.append(sep).append(second);
818 string BESUtil::assemblePath(
const string &firstPart,
const string &secondPart,
bool leadingSlash,
bool trailingSlash)
821 assert(!firstPart.empty());
824 string first = firstPart;
825 string second = secondPart;
828 if (ensureLeadingSlash && first[0] !=
'/')
832 if (second[0] ==
'/')
833 second = second.substr(1);
836 if (first.back() ==
'/')
837 return first.append(second);
839 return first.append(
"/").append(second);
843 BESDEBUG(debug_key, prolog <<
"firstPart: '" << firstPart <<
"'" << endl);
844 BESDEBUG(debug_key, prolog <<
"secondPart: '" << secondPart <<
"'" << endl);
849 string first = firstPart;
850 string second = secondPart;
854 while (!first.empty() && *first.rbegin() ==
'/') {
856 first = first.substr(0, first.length() - 1);
860 while (!second.empty() && second[0] ==
'/') {
870 else if (second.empty()) {
874 newPath = first.append(
"/").append(second);
880 if (newPath.empty()) {
883 else if (newPath.compare(0, 1,
"/")) {
884 newPath =
"/" + newPath;
889 if (newPath.compare(newPath.length(), 1,
"/")) {
890 newPath = newPath.append(
"/");
894 while(newPath.length()>1 && *newPath.rbegin() ==
'/')
895 newPath = newPath.substr(0,newPath.length()-1);
897 BESDEBUG(debug_key, prolog <<
"newPath: "<< newPath << endl);
902 BESDEBUG(
"util",
"BESUtil::assemblePath() - firstPart: "<< firstPart << endl);
903 BESDEBUG(
"util",
"BESUtil::assemblePath() - secondPart: "<< secondPart << endl);
905 string first = firstPart;
906 string second = secondPart;
908 if (ensureLeadingSlash) {
909 if (*first.begin() !=
'/') first =
"/" + first;
913 while (*first.rbegin() ==
'/' && first.length() > 0) {
914 first = first.substr(0, first.length() - 1);
918 if (*first.rbegin() !=
'/') {
923 while (*second.begin() ==
'/' && second.length() > 0) {
924 second = second.substr(1);
927 string newPath = first + second;
929 BESDEBUG(
"util",
"BESUtil::assemblePath() - newPath: "<< newPath << endl);
941 if (fullString.length() >= ending.length()) {
942 return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending));
966 bool cancel_timeout_on_send =
false;
969 const string dosettrue =
"true";
970 const string dosetyes =
"yes";
975 if (dosettrue == doset || dosetyes == doset) cancel_timeout_on_send =
true;
977 BESDEBUG(debug_key, __func__ <<
"() - cancel_timeout_on_send: " <<(cancel_timeout_on_send?
"true":
"false") << endl);
978 if (cancel_timeout_on_send) alarm(0);
988 size_t pos = s.find(find_this);
989 while (pos != string::npos) {
991 s.replace(pos, find_this.size(), replace_with_this);
993 pos = s.find(find_this, pos + find_this.size());
1010 if (separator.length() != 1)
1011 throw BESInternalError(
"Path separators must be a single character. The string '" + separator +
"' does not qualify.", __FILE__, __LINE__);
1012 char separator_char = separator[0];
1013 string double_separator;
1014 double_separator = double_separator.append(separator).append(separator);
1016 string path(raw_path);
1023 if (path == separator) {
1026 if (leading_separator) {
1027 if (path[0] != separator_char) {
1028 path = string(separator).append(path);
1032 if (path[0] == separator_char) {
1033 path = path.substr(1);
1036 if (trailing_separator) {
1037 if (*path.rbegin() != separator_char) {
1038 path = path.append(separator);
1042 if (*path.rbegin() == separator_char) {
1043 path = path.substr(0, path.length() - 1);
1057 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
1059 string::size_type pos = str.find_first_of(delimiters, lastPos);
1060 while (string::npos != pos || string::npos != lastPos) {
1062 tokens.push_back(str.substr(lastPos, pos - lastPos));
1064 lastPos = str.find_first_not_of(delimiters, pos);
1066 pos = str.find_first_of(delimiters, lastPos);
1078 return get_time(time(0), use_local_time);
1090 char buf[
sizeof "YYYY-MM-DDTHH:MM:SS zones"];
1099 if (!use_local_time)
1100 status = strftime(buf,
sizeof buf,
"%FT%T%Z", gmtime(&the_time));
1102 status = strftime(buf,
sizeof buf,
"%FT%T%Z", localtime(&the_time));
1105 LOG(prolog +
"Error formatting time value!");
1106 return "date-format-error";
1126 vector<string> tokens;
1128 while (getline(ss, item, delim)) {
1130 if (item.empty() && skip_empty)
1133 tokens.push_back(item);
1137 if (skip_empty && !item.empty())
1138 tokens.push_back(item);
1146 BESCatalog *BESUtil::separateCatalogFromPath(std::string &ppath)
1149 vector<string> path_tokens;
1153 BESDEBUG(debug_key, prolog <<
"Normalized path: " << path << endl);
1158 string use_container = ppath;
1162 if (!path_tokens.empty()) {
1163 BESDEBUG(debug_key,
"First path token: " << path_tokens[0] << endl);
1166 BESDEBUG(debug_key, prolog <<
"Located catalog " << catalog->
get_catalog_name() <<
" from path component" << endl);
1171 BESDEBUG(debug_key, prolog <<
"Modified container/path value to: " << use_container << endl);
error thrown if the resource requested cannot be found
static void tokenize(const std::string &str, std::vector< std::string > &tokens, const std::string &delimiters="/")
virtual std::string get_catalog_name() const
Get the name for this catalog.
static string get_time(bool use_local_time=false)
static string id2xml(string in, const string ¬_allowed="><&'\"")
exception thrown if inernal error encountered
static string pathConcat(const string &firstPart, const string &secondPart, char separator='/')
Concatenate path fragments making sure that they are separated by a single '/' character.
static string lowercase(const string &s)
static void conditional_timeout_cancel()
static std::string normalize_path(const std::string &path, bool leading_separator, bool trailing_separator, const string separator="/")
Removes duplicate separators and provides leading and trailing separators as directed.
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static string www2id(const string &in, const string &escape="%", const string &except="")
static void removeLeadingAndTrailingBlanks(string &key)
static string implode(const list< string > &values, char delim)
static TheBESKeys * TheKeys()
static std::vector< std::string > split(const 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 string xml2id(string in)
static void set_mime_html(ostream &strm)
Generate an HTTP 1.0 response header for a html document.
static void explode(char delim, const string &str, list< string > &values)
static void set_mime_text(ostream &strm)
Generate an HTTP 1.0 response header for a text document.
static void url_explode(const 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)
Catalogs provide a hierarchical organization for data.
error thrown if the BES is not allowed to access the resource requested
static char * fastpidconverter(char *buf, int base)
static string unescape(const string &s)
static BESCatalogList * TheCatalogList()
Get the singleton BESCatalogList instance.
static void check_path(const string &path, const string &root, bool follow_sym_links)
Check if the specified path is valid.
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 string assemblePath(const string &firstPart, const string &secondPart, bool leadingSlash=false, bool trailingSlash=false)
Assemble path fragments making sure that they are separated by a single '/' character.