37#include "GatewayPathInfoResponseHandler.h"
41#include "BESInfoList.h"
44#include "BESRequestHandlerList.h"
45#include "BESRequestHandler.h"
47#include "BESDapNames.h"
48#include "BESDataNames.h"
49#include "BESCatalogList.h"
50#include "BESCatalog.h"
51#include "BESCatalogEntry.h"
52#include "BESCatalogUtils.h"
53#include "BESSyntaxUserError.h"
54#include "BESForbiddenError.h"
55#include "BESNotFoundError.h"
56#include "BESStopWatch.h"
64#define PATH_INFO_RESPONSE "PathInfo"
66#define VALID_PATH "validPath"
67#define REMAINDER "remainder"
68#define IS_DATA "isData"
69#define IS_FILE "isFile"
71#define IS_ACCESSIBLE "access"
73#define LMT "lastModified"
75#define prolog std::string("GatewayPathInfoResponseHandler::").append(__func__).append("() - ")
77GatewayPathInfoResponseHandler::GatewayPathInfoResponseHandler(
const string &name) :
82GatewayPathInfoResponseHandler::~GatewayPathInfoResponseHandler()
98 BES_STOPWATCH_START(SPI_DEBUG_KEY, prolog +
"Timer");
100 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"BEGIN" << endl );
102 BESInfo *info = BESInfoList::TheList()->build_info();
105 string container = dhi.
data[CONTAINER];
108 string defcatname = BESCatalogList::TheCatalogList()->default_catalog_name();
111 BESCatalog *defcat = BESCatalogList::TheCatalogList()->default_catalog();
113 throw BESInternalError(
"Not able to find the default catalog.", __FILE__, __LINE__);
116 string::size_type notslash = container.find_first_not_of(
"/", 0);
117 if (notslash != string::npos) {
118 container = container.substr(notslash);
123 string::size_type slash = container.find_first_of(
"/", 0);
124 if (slash != string::npos) {
125 catname = container.substr(0, slash);
133 BESCatalog *catobj = BESCatalogList::TheCatalogList()->find_catalog(catname);
135 if (slash != string::npos) {
136 container = container.substr(slash + 1);
139 notslash = container.find_first_not_of(
"/", 0);
140 if (notslash != string::npos) {
141 container = container.substr(notslash);
149 if (container.empty()) container =
"/";
151 if (container[0] !=
'/') container =
"/" + container;
153 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"container: " << container << endl );
157 map<string, string, std::less<>> pathInfoAttrs;
158 pathInfoAttrs[PATH] = container;
160 info->begin_tag(PATH_INFO_RESPONSE, &pathInfoAttrs);
162 string validPath, remainder;
163 bool isFile, isDir, canRead;
164 long long size, time;
170 BESCatalogUtils *utils = BESCatalogList::TheCatalogList()->default_catalog()->get_catalog_utils();
171 eval_resource_path(container, utils->
get_root_dir(), utils->follow_sym_links(), validPath, isFile, isDir, size,
172 time, canRead, remainder);
179 if (validPath.size() != 0) {
186 string err = (string)
"Failed to find the validPath node " + validPath
187 +
" this should not be possible. Some thing BAD is happening.";
192 list<string> services = entry->get_service_list();
195 if (services.size()) {
198 for (; si != se; si++) {
199 if ((*si) == OPENDAP_SERVICE) isData =
true;
204 map<string, string, std::less<>> validPathAttrs;
205 validPathAttrs[IS_DATA] = isData ?
"true" :
"false";
206 validPathAttrs[IS_FILE] = isFile ?
"true" :
"false";
207 validPathAttrs[IS_DIR] = isDir ?
"true" :
"false";
208 validPathAttrs[IS_ACCESSIBLE] = canRead ?
"true" :
"false";
211 std::ostringstream os_size;
213 validPathAttrs[SIZE] = os_size.str();
216 std::ostringstream os_time;
218 validPathAttrs[LMT] = os_time.str();
220 info->add_tag(VALID_PATH, validPath, &validPathAttrs);
221 info->add_tag(REMAINDER, remainder);
223 info->end_tag(PATH_INFO_RESPONSE);
226 info->end_response();
228 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"END" << endl );
260 strm << BESIndent::LMarg <<
"GatewayPathInfoResponseHandler::dump - (" << (
void *)
this <<
")" << std::endl;
263 BESIndent::UnIndent();
267GatewayPathInfoResponseHandler::GatewayPathInfoResponseBuilder(
const string &name)
275void GatewayPathInfoResponseHandler::eval_resource_path(
const string &resource_path,
const string &catalog_root,
276 const bool follow_sym_links,
string &validPath,
bool &isFile,
bool &isDir,
long long &size,
277 long long &lastModifiedTime,
bool &canRead,
string &remainder)
280 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"CatalogRoot: "<< catalog_root << endl);
282 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"resourceID: "<< resource_path << endl);
287 lastModifiedTime = -1;
290 string rem = resource_path;
296 int (*ye_old_stat_function)(
const char *pathname,
struct stat *buf);
297 if (follow_sym_links) {
298 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"Using 'stat' function (follow_sym_links = true)" << endl);
299 ye_old_stat_function = &stat;
302 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"Using 'lstat' function (follow_sym_links = false)" << endl);
303 ye_old_stat_function = &lstat;
308 if (resource_path ==
"") {
309 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"The resourceID is empty" << endl);
315 string::size_type dotdot = resource_path.find(
"..");
316 if (dotdot != string::npos) {
317 BESDEBUG(SPI_DEBUG_KEY,
318 prolog <<
"ERROR: The resourceID '" << resource_path <<
319 "' contains the substring '..' This is Forbidden." << endl);
320 string s = (string)
"Invalid node name '" + resource_path +
"' ACCESS IS FORBIDDEN";
321 throw BESForbiddenError(s, __FILE__, __LINE__);
330 string fullpath = catalog_root;
339 size_t slash = rem.find(
'/');
340 if (slash == string::npos) {
341 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"Checking final path component: " << rem << endl);
350 rem = rem.substr(slash + 1, rem.size() - slash);
353 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"validPath: "<< validPath << endl);
354 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" checking: "<< checking << endl);
355 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" fullpath: "<< fullpath << endl);
357 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" rem: "<< rem << endl);
359 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"remainder: "<< remainder << endl);
362 int statret = ye_old_stat_function(fullpath.c_str(), &sb);
366 validPath = checking;
373 char *s_err = strerror(errsv);
374 string error =
"Unable to access node " + checking +
": ";
376 error = error + s_err;
379 error = error +
"unknown access error";
381 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" error: " << error <<
" errno: " << errno << endl);
383 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"remainder: '" << remainder <<
"'" << endl);
387 if (errsv != ENOENT && errsv != ENOTDIR) {
388 throw BESForbiddenError(error, __FILE__, __LINE__);
392 size_t s_loc = remainder.find(
'/');
393 if (s_loc == string::npos) {
395 string basename = remainder;
396 bool moreDots =
true;
399 size_t d_loc = basename.find_last_of(
".");
400 if (d_loc != string::npos) {
401 basename = basename.substr(0, d_loc);
402 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"basename: "<< basename << endl);
404 string candidate_remainder = remainder.substr(basename.size());
405 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"candidate_remainder: "<< candidate_remainder << endl);
408 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"candidate_path: "<< candidate_path << endl);
411 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"full_candidate_path: "<< full_candidate_path << endl);
414 int statret1 = ye_old_stat_function(full_candidate_path.c_str(), &sb1);
415 if (statret1 != -1) {
416 validPath = candidate_path;
417 remainder = candidate_remainder;
422 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"No dots in remainder: "<< remainder << endl);
428 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"Remainder has slash pollution: "<< remainder << endl);
434 statret = ye_old_stat_function(fullpath.c_str(), &sb);
435 if (S_ISREG(sb.st_mode)) {
436 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"'"<< fullpath <<
"' Is regular file." << endl);
440 else if (S_ISDIR(sb.st_mode)) {
441 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"'"<< fullpath <<
"' Is directory." << endl);
445 else if (S_ISLNK(sb.st_mode)) {
446 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"'"<< fullpath <<
"' Is symbolic Link." << endl);
447 string error =
"Service not configured to traverse symbolic links as embodied by the node '" + checking
448 +
"' ACCESS IS FORBIDDEN";
449 throw BESForbiddenError(error, __FILE__, __LINE__);
455 std::ifstream ifile(fullpath.c_str());
456 canRead = ifile.good();
468#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
470 lastModifiedTime = (sb.st_mtimespec.tv_sec * 1000) + (sb.st_mtimespec.tv_nsec / 1000000);
472 lastModifiedTime = sb.st_mtime;
475 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" fullpath: " << fullpath << endl);
476 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"validPath: " << validPath << endl);
477 BESDEBUG(SPI_DEBUG_KEY, prolog <<
"remainder: " << remainder << endl);
478 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" rem: " << rem << endl);
479 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" isFile: " << (isFile?
"true":
"false") << endl);
480 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" isDir: " << (isDir?
"true":
"false") << endl);
481 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" access: " << (canRead?
"true":
"false") << endl);
482 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" size: " << size << endl);
483 BESDEBUG(SPI_DEBUG_KEY, prolog <<
" LMT: " << lastModifiedTime << endl);
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
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.
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
void dump(std::ostream &strm) const override
dumps information about this object
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 dump(std::ostream &strm) const
dumps information about this object
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...