Your IP : 18.223.210.196
/*
* Phusion Passenger - https://www.phusionpassenger.com/
* Copyright (c) 2010-2018 Phusion Holding B.V.
*
* "Passenger", "Phusion Passenger" and "Union Station" are registered
* trademarks of Phusion Holding B.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _PASSENGER_APACHE2_DIRECTORY_MAPPER_H_
#define _PASSENGER_APACHE2_DIRECTORY_MAPPER_H_
#include <string>
#include <set>
#include <cstring>
#include <oxt/backtrace.hpp>
#include <boost/thread.hpp>
#include <AppTypeDetector/Detector.h>
#include <Utils.h>
#include <Utils/CachedFileStat.hpp>
// The APR headers must come after the Passenger headers.
// See Hooks.cpp to learn why.
#include <httpd.h>
#include <http_core.h>
#include "Config.h"
namespace Passenger {
namespace Apache2Module {
using namespace std;
using namespace oxt;
class DocumentRootDeterminationError: public oxt::tracable_exception {
private:
string msg;
public:
DocumentRootDeterminationError(const string &message): msg(message) {}
virtual ~DocumentRootDeterminationError() throw() {}
virtual const char *what() const throw() { return msg.c_str(); }
};
/**
* Utility class for determining URI-to-application directory mappings.
* Given a URI, it will determine whether that URI belongs to a Phusion
* Passenger-handled application, what the base URI of that application is,
* and what the associated 'public' directory is.
*
* @note This class is not thread-safe, but is reentrant.
* @ingroup Core
*/
class DirectoryMapper {
private:
const WrapperRegistry::Registry ®istry;
DirConfig *config;
request_rec *r;
CachedFileStat *cstat;
boost::mutex *cstatMutex;
boost::mutex *configMutex;
const char *baseURI;
string publicDir;
string appRoot;
unsigned int throttleRate;
AppTypeDetector::Detector::Result detectorResult;
bool autoDetectionDone;
const char *findBaseURI() const {
set<string>::const_iterator it, end = config->getBaseURIs().end();
const char *uri = r->uri;
size_t uri_len = strlen(uri);
for (it = config->getBaseURIs().begin(); it != end; it++) {
const string &base = *it;
if (base == "/") {
/* Ignore 'PassengerBaseURI /' options. Users usually
* specify this out of ignorance.
*/
continue;
}
if ( base == "/"
|| ( uri_len == base.size() && memcmp(uri, base.c_str(), uri_len) == 0 )
|| ( uri_len > base.size() && memcmp(uri, base.c_str(), base.size()) == 0
&& uri[base.size()] == '/' )
) {
return base.c_str();
}
}
return NULL;
}
/**
* @throws FileSystemException An error occured while examening the filesystem.
* @throws DocumentRootDeterminationError Unable to query the location of the document root.
* @throws TimeRetrievalException
* @throws boost::thread_interrupted
*/
void autoDetect() {
if (autoDetectionDone) {
return;
}
TRACE_POINT();
/* Determine the document root without trailing slashes. */
StaticString docRoot = ap_document_root(r);
if (docRoot.size() > 1 && docRoot[docRoot.size() - 1] == '/') {
docRoot = docRoot.substr(0, docRoot.size() - 1);
}
if (docRoot.empty()) {
throw DocumentRootDeterminationError("Cannot determine the document root");
}
/* Find the base URI for this web application, if any. */
const char *baseURI = findBaseURI();
if (baseURI != NULL) {
/* We infer that the 'public' directory of the web application
* is document root + base URI.
*/
publicDir = docRoot + baseURI;
} else {
/* No base URI directives are applicable for this request. So assume that
* the web application's public directory is the document root.
*/
publicDir = docRoot;
}
UPDATE_TRACE_POINT();
AppTypeDetector::Detector detector(registry, cstat,
cstatMutex, throttleRate, configMutex);
AppTypeDetector::Detector::Result detectorResult;
string appRoot;
// If `AppStartCommand` is set, then it means the config specified that it is
// either a generic app or a Kuria app.
if (!config->getAppStartCommand().empty()) {
appRoot = config->getAppRoot();
} else if (config->getAppType().empty()) {
// If neither `AppStartCommand` nor `AppType` are set, then
// autodetect what kind of app this is.
if (config->getAppRoot().empty()) {
detectorResult = detector.checkDocumentRoot(publicDir,
baseURI != NULL,
&appRoot);
} else {
appRoot = config->getAppRoot();
detectorResult = detector.checkAppRoot(appRoot);
}
} else if (!config->getAppRoot().empty()) {
// If `AppStartCommand` is not set but `AppType` is (as well as
// the required `AppRoot`), then verify whether the given
// `AppType` value is supported and resolve aliases.
appRoot = config->getAppRoot().toString();
detectorResult.wrapperRegistryEntry = ®istry.lookup(
config->getAppType());
}
this->appRoot = appRoot;
this->baseURI = baseURI;
this->detectorResult = detectorResult;
autoDetectionDone = true;
}
public:
/**
* Create a new DirectoryMapper object.
*
* @param cstat A CachedFileStat object used for statting files.
* @param cstatMutex A mutex for locking CachedFileStat, making its
* usage thread-safe.
* @param throttleRate A throttling rate for cstat.
* @warning Do not use this object after the destruction of <tt>r</tt>,
* <tt>config</tt> or <tt>cstat</tt>.
*/
DirectoryMapper(request_rec *r, DirConfig *config,
const WrapperRegistry::Registry &_registry,
CachedFileStat *cstat, boost::mutex *cstatMutex,
unsigned int throttleRate, boost::mutex *configMutex)
: registry(_registry)
{
this->r = r;
this->config = config;
this->cstat = cstat;
this->cstatMutex = cstatMutex;
this->configMutex = configMutex;
this->throttleRate = throttleRate;
baseURI = NULL;
autoDetectionDone = false;
}
/**
* Determines whether the given HTTP request falls under one of the specified
* PassengerBaseURIs. If yes, then the first matching base URI will be returned.
* Otherwise, NULL will be returned.
*
* @throws FileSystemException An error occured while examening the filesystem.
* @throws DocumentRoot
* @throws TimeRetrievalException
* @throws boost::thread_interrupted
* @warning The return value may only be used as long as <tt>config</tt>
* hasn't been destroyed.
*/
const char *getBaseURI() {
TRACE_POINT();
autoDetect();
return baseURI;
}
/**
* Returns the filename of the 'public' directory of the application
* that's associated with the HTTP request.
*
* @throws FileSystemException An error occured while examening the filesystem.
* @throws DocumentRootDeterminationError Unable to query the location of the document root.
* @throws TimeRetrievalException
* @throws boost::thread_interrupted
*/
const string &getPublicDirectory() {
autoDetect();
return publicDir;
}
/**
* Returns the application root, or the empty string if this request does not
* belong to an application.
*
* @throws FileSystemException An error occured while examening the filesystem.
* @throws DocumentRootDeterminationError Unable to query the location of the document root.
* @throws TimeRetrievalException
* @throws boost::thread_interrupted
*/
const string &getAppRoot() {
autoDetect();
return appRoot;
}
/**
* Returns the application detector result associated with the HTTP request.
*
* @throws FileSystemException An error occured while examening the filesystem.
* @throws DocumentRootDeterminationError Unable to query the location of the document root.
* @throws TimeRetrievalException
* @throws boost::thread_interrupted
*/
AppTypeDetector::Detector::Result getDetectorResult() {
autoDetect();
return detectorResult;
}
};
} // namespace Apache2Module
} // namespace Passenger
#endif /* _PASSENGER_APACHE2_DIRECTORY_MAPPER_H_ */