41#include "ShowPathInfoResponseHandler.h"
45#include "BESInfoList.h"
48#include "BESRequestHandlerList.h"
49#include "BESRequestHandler.h"
51#include "BESDapNames.h"
52#include "BESDataNames.h"
53#include "BESCatalogList.h"
54#include "BESCatalog.h"
55#include "BESCatalogEntry.h"
56#include "BESCatalogUtils.h"
57#include "BESSyntaxUserError.h"
58#include "BESForbiddenError.h"
59#include "BESNotFoundError.h"
60#include "BESStopWatch.h"
68#define PATH_INFO_RESPONSE "PathInfo"
70#define VALID_PATH "validPath"
71#define REMAINDER "remainder"
72#define IS_DATA "isData"
73#define IS_FILE "isFile"
75#define IS_ACCESSIBLE "access"
77#define LMT "lastModified"
79#define SPI_DEBUG_KEY "show-path-info"
80#define SHOW_PATH_INFO_RESPONSE_STR "showPathInfo"
82ShowPathInfoResponseHandler::ShowPathInfoResponseHandler(
const string &name) :
87ShowPathInfoResponseHandler::~ShowPathInfoResponseHandler()
107 BESDEBUG(SPI_DEBUG_KEY,
108 "ShowPathInfoResponseHandler::execute() - BEGIN ############################################################## BEGIN" << endl);
110 BESInfo *info = BESInfoList::TheList()->build_info();
111 d_response_object = info;
113 string container = dhi.
data[CONTAINER];
121 throw BESInternalError(
"Not able to find the default catalog.", __FILE__, __LINE__);
124 string::size_type notslash = container.find_first_not_of(
"/", 0);
125 if (notslash != string::npos) {
126 container = container.substr(notslash);
131 string::size_type slash = container.find_first_of(
"/", 0);
132 if (slash != string::npos) {
133 catname = container.substr(0, slash);
143 if (slash != string::npos) {
144 container = container.substr(slash + 1);
147 notslash = container.find_first_not_of(
"/", 0);
148 if (notslash != string::npos) {
149 container = container.substr(notslash);
157 if (container.empty()) container =
"/";
159 if (container[0] !=
'/') container =
"/" + container;
161 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::execute() - container: " << container << endl);
166 map<string, string> pathInfoAttrs;
167 pathInfoAttrs[PATH] = container;
169 info->begin_tag(PATH_INFO_RESPONSE, &pathInfoAttrs);
171 string validPath, remainder;
172 bool isFile, isDir, canRead;
173 long long size, time;
177 eval_resource_path(container, utils->
get_root_dir(), utils->follow_sym_links(), validPath, isFile, isDir, size,
178 time, canRead, remainder);
185 if (validPath.length() != 0) {
192 string err = (string)
"Failed to find the validPath node " + validPath
193 +
" this should not be possible. Some thing BAD is happening.";
198 list<string> services = entry->get_service_list();
201 if (services.size()) {
202 list<string>::const_iterator si = services.begin();
203 list<string>::const_iterator se = services.end();
204 for (; si != se; si++) {
205 if ((*si) == OPENDAP_SERVICE) isData =
true;
210 map<string, string> validPathAttrs;
211 validPathAttrs[IS_DATA] = isData ?
"true" :
"false";
212 validPathAttrs[IS_FILE] = isFile ?
"true" :
"false";
213 validPathAttrs[IS_DIR] = isDir ?
"true" :
"false";
214 validPathAttrs[IS_ACCESSIBLE] = canRead ?
"true" :
"false";
217 std::ostringstream os_size;
219 validPathAttrs[SIZE] = os_size.str();
222 std::ostringstream os_time;
224 validPathAttrs[LMT] = os_time.str();
226 info->add_tag(VALID_PATH, validPath, &validPathAttrs);
227 info->add_tag(REMAINDER, remainder);
229 info->end_tag(PATH_INFO_RESPONSE);
232 info->end_response();
234 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::execute() - END" << endl);
250 if (d_response_object) {
265 strm << BESIndent::LMarg <<
"ShowPathInfoResponseHandler::dump - (" << (
void *)
this <<
")" << std::endl;
268 BESIndent::UnIndent();
272ShowPathInfoResponseHandler::ShowPathInfoResponseBuilder(
const string &name)
280void ShowPathInfoResponseHandler::eval_resource_path(
const string &resource_path,
const string &catalog_root,
281 const bool follow_sym_links,
string &validPath,
bool &isFile,
bool &isDir,
long long &size,
282 long long &lastModifiedTime,
bool &canRead,
string &remainder)
285 BESDEBUG(SPI_DEBUG_KEY,
286 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"CatalogRoot: "<< catalog_root << endl);
288 BESDEBUG(SPI_DEBUG_KEY,
289 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"resourceID: "<< resource_path << endl);
294 lastModifiedTime = -1;
297 string rem = resource_path;
303 int (*ye_old_stat_function)(
const char *pathname,
struct stat *buf);
304 if (follow_sym_links) {
305 BESDEBUG(SPI_DEBUG_KEY,
306 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"Using 'stat' function (follow_sym_links = true)" << endl);
307 ye_old_stat_function = &stat;
310 BESDEBUG(SPI_DEBUG_KEY,
311 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"Using 'lstat' function (follow_sym_links = false)" << endl);
312 ye_old_stat_function = &lstat;
317 if (resource_path ==
"") {
318 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::"<<__func__ <<
"() - The resourceID is empty" << endl);
324 string::size_type dotdot = resource_path.find(
"..");
325 if (dotdot != string::npos) {
326 BESDEBUG(SPI_DEBUG_KEY,
327 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
" ERROR: The resourceID '" << resource_path <<
"' contains the substring '..' This is Forbidden." << endl);
328 string s = (string)
"Invalid node name '" + resource_path +
"' ACCESS IS FORBIDDEN";
339 string fullpath = catalog_root;
348 size_t slash = rem.find(
'/');
349 if (slash == string::npos) {
350 BESDEBUG(SPI_DEBUG_KEY,
351 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"Checking final path component: " << rem << endl);
360 rem = rem.substr(slash + 1, rem.length() - slash);
363 BESDEBUG(SPI_DEBUG_KEY,
364 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"validPath: "<< validPath << endl);
365 BESDEBUG(SPI_DEBUG_KEY,
366 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"checking: "<< checking << endl);
367 BESDEBUG(SPI_DEBUG_KEY,
368 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"fullpath: "<< fullpath << endl);
370 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"rem: "<< rem << endl);
372 BESDEBUG(SPI_DEBUG_KEY,
373 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"remainder: "<< remainder << endl);
376 int statret = ye_old_stat_function(fullpath.c_str(), &sb);
380 validPath = checking;
387 char *s_err = strerror(errsv);
388 string error =
"Unable to access node " + checking +
": ";
390 error = error + s_err;
393 error = error +
"unknown access error";
395 BESDEBUG(SPI_DEBUG_KEY,
396 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"error: "<< error <<
" errno: " << errno << endl);
398 BESDEBUG(SPI_DEBUG_KEY,
399 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"remainder: '" << remainder <<
"'" << endl);
403 if (errsv != ENOENT && errsv != ENOTDIR) {
408 size_t s_loc = remainder.find(
'/');
409 if (s_loc == string::npos) {
411 string basename = remainder;
412 bool moreDots =
true;
415 size_t d_loc = basename.find_last_of(
".");
416 if (d_loc != string::npos) {
417 basename = basename.substr(0, d_loc);
418 BESDEBUG(SPI_DEBUG_KEY,
419 "ShowPathInfoResponseHandler::" << __func__ <<
"() - basename: "<< basename << endl);
421 string candidate_remainder = remainder.substr(basename.length());
422 BESDEBUG(SPI_DEBUG_KEY,
423 "ShowPathInfoResponseHandler::" << __func__ <<
"() - candidate_remainder: "<< candidate_remainder << endl);
426 BESDEBUG(SPI_DEBUG_KEY,
427 "ShowPathInfoResponseHandler::" << __func__ <<
"() - candidate_path: "<< candidate_path << endl);
430 BESDEBUG(SPI_DEBUG_KEY,
431 "ShowPathInfoResponseHandler::" << __func__ <<
"() - full_candidate_path: "<< full_candidate_path << endl);
434 int statret1 = ye_old_stat_function(full_candidate_path.c_str(), &sb1);
435 if (statret1 != -1) {
436 validPath = candidate_path;
437 remainder = candidate_remainder;
442 BESDEBUG(SPI_DEBUG_KEY,
443 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"No dots in remainder: "<< remainder << endl);
449 BESDEBUG(SPI_DEBUG_KEY,
450 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"Remainder has slash pollution: "<< remainder << endl);
456 statret = ye_old_stat_function(fullpath.c_str(), &sb);
457 if (S_ISREG(sb.st_mode)) {
458 BESDEBUG(SPI_DEBUG_KEY,
459 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"'"<< fullpath <<
"' Is regular file." << endl);
463 else if (S_ISDIR(sb.st_mode)) {
464 BESDEBUG(SPI_DEBUG_KEY,
465 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"'"<< fullpath <<
"' Is directory." << endl);
469 else if (S_ISLNK(sb.st_mode)) {
470 BESDEBUG(SPI_DEBUG_KEY,
471 "ShowPathInfoResponseHandler::"<<__func__ <<
"() - " <<
"'"<< fullpath <<
"' Is symbolic Link." << endl);
472 string error =
"Service not configured to traverse symbolic links as embodied by the node '" + checking
473 +
"' ACCESS IS FORBIDDEN";
480 std::ifstream ifile(fullpath.c_str());
481 canRead = ifile.good();
494#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
496 lastModifiedTime = (sb.st_mtimespec.tv_sec * 1000) + (sb.st_mtimespec.tv_nsec / 1000000);
498 lastModifiedTime = sb.st_mtime;
502 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::" << __func__ <<
"() - fullpath: " << fullpath << endl);
503 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::" << __func__ <<
"() - validPath: " << validPath << endl);
504 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::" << __func__ <<
"() - remainder: " << remainder << endl);
505 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::" << __func__ <<
"() - rem: " << rem << endl);
506 BESDEBUG(SPI_DEBUG_KEY,
507 "ShowPathInfoResponseHandler::" << __func__ <<
"() - isFile: " << (isFile?
"true":
"false") << endl);
508 BESDEBUG(SPI_DEBUG_KEY,
509 "ShowPathInfoResponseHandler::" << __func__ <<
"() - isDir: " << (isDir?
"true":
"false") << endl);
510 BESDEBUG(SPI_DEBUG_KEY,
511 "ShowPathInfoResponseHandler::" << __func__ <<
"() - access: " << (canRead?
"true":
"false") << endl);
512 BESDEBUG(SPI_DEBUG_KEY,
"ShowPathInfoResponseHandler::" << __func__ <<
"() - size: " << size << endl);
513 BESDEBUG(SPI_DEBUG_KEY,
514 "ShowPathInfoResponseHandler::" << __func__ <<
"() - LMT: " << lastModifiedTime << endl);
virtual BESCatalog * default_catalog() const
The the default catalog.
virtual std::string default_catalog_name() const
The name of the default catalog.
static BESCatalogList * TheCatalogList()
Get the singleton BESCatalogList instance.
const std::string & get_root_dir() const
Get the root directory of the catalog.
Catalogs provide a hierarchical organization for data.
virtual BESCatalogEntry * show_catalog(const std::string &container, BESCatalogEntry *entry)=0
virtual BESCatalogUtils * get_catalog_utils() const
Get a pointer to the utilities, customized for this catalog.
Structure storing information used by the BES to handle the request.
std::map< std::string, std::string > data
the map of string data that will be required for the current request.
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
error thrown if the BES is not allowed to access the resource requested
informational response object
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi)=0
transmit the informational object
virtual void begin_response(const std::string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
exception thrown if internal error encountered
handler object that knows how to create a specific response object
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual bool start(std::string name)
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.
response handler that returns nodes or leaves within the catalog either at the root or at a specified...
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi)
transmit the response object built by the execute command using the specified transmitter object
virtual void execute(BESDataHandlerInterface &dhi)
executes the command 'show catalog|leaves [for <node>];' by returning nodes or leaves at the top leve...
virtual void dump(std::ostream &strm) const
dumps information about this object