OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3
|
00001 // BESKeys.cc 00002 00003 // This file is part of bes, A C++ back-end server implementation framework 00004 // for the OPeNDAP Data Access Protocol. 00005 00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research 00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact University Corporation for Atmospheric Research at 00024 // 3080 Center Green Drive, Boulder, CO 80301 00025 00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005 00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR. 00028 // 00029 // Authors: 00030 // pwest Patrick West <pwest@ucar.edu> 00031 // jgarcia Jose Garcia <jgarcia@ucar.edu> 00032 00033 #include "config.h" 00034 00035 #ifdef __cplusplus 00036 extern "C" { 00037 #include <sys/types.h> 00038 #include "regex.h" 00039 } 00040 #endif 00041 00042 #include <cerrno> 00043 #include <cstring> 00044 00045 #if HAVE_UNISTD_H 00046 #include <unistd.h> 00047 #endif 00048 00049 #include "BESKeys.h" 00050 #include "BESUtil.h" 00051 #include "BESFSDir.h" 00052 #include "BESFSFile.h" 00053 #include "BESInternalFatalError.h" 00054 #include "BESSyntaxUserError.h" 00055 00056 #define BES_INCLUDE_KEY "BES.Include" 00057 00058 vector<string> BESKeys::KeyList ; 00059 00076 BESKeys::BESKeys( const string &keys_file_name ) 00077 : _keys_file( 0 ), 00078 _keys_file_name( keys_file_name ), 00079 _the_keys( 0 ), 00080 _own_keys( true ) 00081 { 00082 _the_keys = new map<string,vector<string> >; 00083 initialize_keys( ) ; 00084 } 00085 00086 BESKeys::BESKeys( const string &keys_file_name, map<string,vector<string> > *keys) 00087 : _keys_file( 0 ), 00088 _keys_file_name( keys_file_name ), 00089 _the_keys( keys ), 00090 _own_keys( false ) 00091 { 00092 initialize_keys( ) ; 00093 } 00094 00097 BESKeys::~BESKeys() 00098 { 00099 clean() ; 00100 } 00101 00102 void 00103 BESKeys::initialize_keys( ) 00104 { 00105 _keys_file = new ifstream( _keys_file_name.c_str() ) ; 00106 int myerrno = errno ; 00107 if( !(*_keys_file) ) 00108 { 00109 char path[500] ; 00110 getcwd( path, sizeof( path ) ) ; 00111 string s = string("BES: fatal, cannot open BES configuration file ") 00112 + _keys_file_name + ": " ; 00113 char *err = strerror( myerrno ) ; 00114 if( err ) 00115 s += err ; 00116 else 00117 s += "Unknown error" ; 00118 00119 s += (string)".\n" + "The current working directory is " + path + "\n" ; 00120 throw BESInternalFatalError( s, __FILE__, __LINE__ ) ; 00121 } 00122 00123 try 00124 { 00125 load_keys() ; 00126 } 00127 catch( BESError &e ) 00128 { 00129 // be sure we're throwing a fatal error, since the BES can't run 00130 // within the configuration file 00131 clean() ; 00132 throw BESInternalFatalError( e.get_message(), 00133 e.get_file(), e.get_line() ) ; 00134 } 00135 catch(...) 00136 { 00137 clean() ; 00138 string s = (string)"Undefined exception while trying to load keys " 00139 + "from bes configuration file " + _keys_file_name ; 00140 throw BESInternalFatalError( s, __FILE__, __LINE__ ) ; 00141 } 00142 } 00143 00144 void 00145 BESKeys::clean() 00146 { 00147 if( _keys_file ) 00148 { 00149 _keys_file->close() ; 00150 delete _keys_file ; 00151 } 00152 if( _the_keys && _own_keys ) 00153 { 00154 delete _the_keys ; 00155 } 00156 } 00157 00158 /* @brief Determine if the specified key file has been loaded yet 00159 * 00160 * Given the name of the key file, determine if it has already been 00161 * loaded. More specifically, if started to load the file. 00162 * 00163 * @returns true if already started to load, false otherwise 00164 */ 00165 bool 00166 BESKeys::LoadedKeys( const string &key_file ) 00167 { 00168 vector<string>::const_iterator i = BESKeys::KeyList.begin() ; 00169 vector<string>::const_iterator e = BESKeys::KeyList.end() ; 00170 for( ; i != e; i++ ) 00171 { 00172 if( (*i) == key_file ) 00173 { 00174 return true ; 00175 } 00176 } 00177 return false ; 00178 } 00179 00180 void 00181 BESKeys::load_keys() 00182 { 00183 char buffer[255]; 00184 string key,value; 00185 while(!(*_keys_file).eof()) 00186 { 00187 if((*_keys_file).getline(buffer,255)) 00188 { 00189 bool addto = false ; 00190 if( break_pair( buffer, key, value, addto ) ) 00191 { 00192 if( key == BES_INCLUDE_KEY ) 00193 { 00194 load_include_files( value ) ; 00195 } 00196 else 00197 { 00198 set_key( key, value, addto ) ; 00199 } 00200 } 00201 } 00202 } 00203 } 00204 00205 // The string contained in the character buffer b should be of the 00206 // format key=value or key+=value. The pair is broken apart, storing the 00207 // key in the key parameter and the value of the key in the value 00208 // parameter. If += is used, then the value should be added to the value 00209 // of key, not replacing. 00210 // 00211 // It used to be that we would validate the key=value line. Instead, 00212 // anything after the equal sign is considered the value of the key. 00213 inline bool 00214 BESKeys::break_pair( const char* b, string& key, string &value, bool &addto ) 00215 { 00216 addto = false ; 00217 // Ignore comments and lines with only spaces 00218 if( b && ( b[0] != '#' ) && ( !only_blanks( b ) ) ) 00219 { 00220 register size_t l = strlen( b ) ; 00221 if( l > 1 ) 00222 { 00223 int pos = 0 ; 00224 bool done = false ; 00225 for( register size_t j = 0; j < l && !done ; j++ ) 00226 { 00227 if( b[j] == '=' ) 00228 { 00229 if( !addto ) pos = j ; 00230 else 00231 { 00232 if( pos != static_cast<int>(j-1) ) 00233 { 00234 string s = string("BES: Invalid entry ") + b 00235 + " in configuration file " 00236 + _keys_file_name 00237 + " '+' character found in variable name" 00238 + " or attempting '+=' with space" 00239 + " between the characters.\n" ; 00240 throw BESInternalFatalError( s, __FILE__, __LINE__); 00241 } 00242 } 00243 done = true ; 00244 } 00245 else if( b[j] == '+' ) 00246 { 00247 addto = true ; 00248 pos = j ; 00249 } 00250 } 00251 if( !done ) 00252 { 00253 string s = string("BES: Invalid entry ") + b 00254 + " in configuration file " 00255 + _keys_file_name + ": " 00256 + " '=' character not found.\n" ; 00257 throw BESInternalFatalError( s, __FILE__, __LINE__); 00258 } 00259 00260 string s = b ; 00261 key = s.substr( 0, pos ) ; 00262 BESUtil::removeLeadingAndTrailingBlanks( key ) ; 00263 if( addto ) value = s.substr( pos+2, s.size() ) ; 00264 else value = s.substr( pos+1, s.size() ) ; 00265 BESUtil::removeLeadingAndTrailingBlanks( value ) ; 00266 00267 return true; 00268 } 00269 00270 return false; 00271 } 00272 00273 return false; 00274 } 00275 00285 void 00286 BESKeys::load_include_files( const string &files ) 00287 { 00288 string newdir ; 00289 BESFSFile allfiles( files ) ; 00290 00291 // If the files specified begin with a /, then use that directory 00292 // instead of the current keys file directory. 00293 if( !files.empty() && files[0] == '/' ) 00294 { 00295 newdir = allfiles.getDirName() ; 00296 } 00297 else 00298 { 00299 // determine the directory of the current keys file. All included 00300 // files will be relative to this file. 00301 BESFSFile currfile( _keys_file_name ) ; 00302 string currdir = currfile.getDirName() ; 00303 00304 string alldir = allfiles.getDirName() ; 00305 00306 if( ( currdir == "./" || currdir == "." ) 00307 && ( alldir == "./" || alldir == "." ) ) 00308 { 00309 newdir = "./" ; 00310 } 00311 else 00312 { 00313 if( alldir == "./" || alldir == "." ) 00314 { 00315 newdir = currdir ; 00316 } 00317 else 00318 { 00319 newdir = currdir + "/" + alldir ; 00320 } 00321 } 00322 } 00323 00324 // load the files one at a time. If the directory doesn't exist, 00325 // then don't load any configuration files 00326 BESFSDir fsd( newdir, allfiles.getFileName() ) ; 00327 BESFSDir::fileIterator i = fsd.beginOfFileList() ; 00328 BESFSDir::fileIterator e = fsd.endOfFileList() ; 00329 for( ; i != e; i++ ) 00330 { 00331 load_include_file( (*i).getFullPath() ) ; 00332 } 00333 } 00334 00341 void 00342 BESKeys::load_include_file( const string &file ) 00343 { 00344 // make sure the file exists and is readable 00345 // throws exception if unable to read 00346 // not loaded if has already be started to be loaded 00347 if( !BESKeys::LoadedKeys( file ) ) 00348 { 00349 BESKeys::KeyList.push_back( file ) ; 00350 BESKeys tmp( file, _the_keys ) ; 00351 } 00352 } 00353 00354 bool 00355 BESKeys::only_blanks(const char *line) 00356 { 00357 int val; 00358 regex_t rx; 00359 string expr = "[^[:space:]]" ; 00360 val = regcomp( &rx, expr.c_str(), REG_ICASE ) ; 00361 00362 if( val != 0 ) 00363 { 00364 string s = (string)"Regular expression " + expr 00365 + " did not compile correctly " 00366 + " in configuration file " + _keys_file_name ; 00367 throw BESInternalFatalError( s, __FILE__, __LINE__ ) ; 00368 } 00369 val = regexec( &rx, line, 0, 0, REG_NOTBOL ) ; 00370 if( val == 0 ) 00371 { 00372 regfree( &rx ) ; 00373 return false ; 00374 } 00375 else 00376 { 00377 if( val == REG_NOMATCH ) 00378 { 00379 regfree( &rx ) ; 00380 return true ; 00381 } 00382 else if( val == REG_ESPACE ) 00383 { 00384 string s = (string)"Execution of regular expression out of space" 00385 + " in configuration file " + _keys_file_name ; 00386 throw BESInternalFatalError( s, __FILE__, __LINE__ ) ; 00387 } 00388 else 00389 { 00390 string s = (string)"Execution of regular expression has unknown " 00391 + " problem in configuration file " + _keys_file_name ; 00392 throw BESInternalFatalError( s, __FILE__, __LINE__ ) ; 00393 } 00394 } 00395 } 00396 00413 void 00414 BESKeys::set_key( const string &key, const string &val, bool addto ) 00415 { 00416 map<string,vector<string> >::iterator i ; 00417 i = _the_keys->find( key ) ; 00418 if( i == _the_keys->end() ) 00419 { 00420 vector<string> vals ; 00421 (*_the_keys)[key] = vals ; 00422 } 00423 if( !addto ) (*_the_keys)[key].clear() ; 00424 if( !val.empty() ) 00425 { 00426 (*_the_keys)[key].push_back( val ) ; 00427 } 00428 } 00429 00441 void 00442 BESKeys::set_key( const string &pair ) 00443 { 00444 string key ; 00445 string val ; 00446 bool addto = false ; 00447 break_pair( pair.c_str(), key, val, addto ) ; 00448 set_key( key, val, addto ) ; 00449 } 00450 00465 void 00466 BESKeys::get_value( const string& s, string &val, bool &found ) 00467 { 00468 found = false ; 00469 map<string,vector<string> >::iterator i ; 00470 i = _the_keys->find( s ) ; 00471 if( i != _the_keys->end() ) 00472 { 00473 found = true ; 00474 if( (*i).second.size() > 1 ) 00475 { 00476 string err = string("Multiple values for the key ") + s 00477 + " found, should only be one." ; 00478 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00479 } 00480 if( (*i).second.size() == 1 ) 00481 { 00482 val = (*i).second[0] ; 00483 } 00484 else 00485 { 00486 val = "" ; 00487 } 00488 } 00489 } 00490 00502 void 00503 BESKeys::get_values( const string& s, vector<string> &vals, bool &found ) 00504 { 00505 found = false ; 00506 map<string,vector<string> >::iterator i ; 00507 i = _the_keys->find( s ) ; 00508 if( i != _the_keys->end() ) 00509 { 00510 found = true ; 00511 vals = (*i).second ; 00512 } 00513 } 00514 00521 void 00522 BESKeys::dump( ostream &strm ) const 00523 { 00524 strm << BESIndent::LMarg << "BESKeys::dump - (" 00525 << (void *)this << ")" << endl ; 00526 BESIndent::Indent() ; 00527 strm << BESIndent::LMarg << "key file:" << _keys_file_name << endl ; 00528 if( _keys_file && *_keys_file ) 00529 { 00530 strm << BESIndent::LMarg << "key file is valid" << endl ; 00531 } 00532 else 00533 { 00534 strm << BESIndent::LMarg << "key file is NOT valid" << endl ; 00535 } 00536 if( _the_keys && _the_keys->size() ) 00537 { 00538 strm << BESIndent::LMarg << " keys:" << endl ; 00539 BESIndent::Indent() ; 00540 Keys_citer i = _the_keys->begin() ; 00541 Keys_citer ie = _the_keys->end() ; 00542 for( ; i != ie; i++ ) 00543 { 00544 strm << BESIndent::LMarg << (*i).first << ":" << endl ; 00545 BESIndent::Indent() ; 00546 vector<string>::const_iterator v = (*i).second.begin() ; 00547 vector<string>::const_iterator ve = (*i).second.end() ; 00548 for( ; v != ve; v++ ) 00549 { 00550 strm << (*v) << endl ; 00551 } 00552 BESIndent::UnIndent() ; 00553 } 00554 BESIndent::UnIndent() ; 00555 } 00556 else 00557 { 00558 strm << BESIndent::LMarg << "keys: none" << endl ; 00559 } 00560 BESIndent::UnIndent() ; 00561 } 00562