/hphp/runtime/server/server.h
C Header | 407 lines | 185 code | 57 blank | 165 comment | 2 complexity | 9650dac4e8c32b7f5fc445ca81974806 MD5 | raw file
- /*
- +----------------------------------------------------------------------+
- | HipHop for PHP |
- +----------------------------------------------------------------------+
- | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- */
- #ifndef incl_HPHP_HTTP_SERVER_SERVER_H_
- #define incl_HPHP_HTTP_SERVER_SERVER_H_
- #include <chrono>
- #include <memory>
- #include "hphp/runtime/server/takeover-agent.h"
- #include "hphp/runtime/server/transport.h"
- #include "hphp/util/exception.h"
- #include "hphp/util/lock.h"
- /**
- * (1) For people who want to quickly come up with an HTTP server handling
- * their specific requests, we really want to minimize writing an HTTP
- * server to something like this,
- *
- * class MyRequestHandler : public RequestHandler {
- * public:
- * virtual void handleRequest(Transport *transport) {
- * // ...
- * }
- * };
- *
- * Then, run a server like this,
- *
- * auto server = std::make_shared<LibEventServer>("127.0.0.1", 80, 20);
- * server->setRequestHandlerFactory<MyRequestHandler>();
- * Server::InstallStopSignalHandlers(server);
- * server->start();
- *
- * This way, we can easily swap out an implementation like LibEventServer
- * without any modifications to MyRequestHandler, if LibEventServer model
- * doesn't perform well with the specific requests.
- *
- * (2) For people who are interested in implementing a high-performance HTTP
- * server, derive a new class from Server just like LibEventServer
- * does.
- *
- * class MyTransport : public Transport {
- * // implements transport-related functions
- * };
- *
- * class MyServer : public Server {
- * // implements how to start/stop a server
- * };
- *
- * (3) LibEventServer is pre-implemented with evhttp, and it has one thread
- * listening on a socket and dispatching jobs to multiple worker threads.
- *
- */
- namespace HPHP {
- ///////////////////////////////////////////////////////////////////////////////
- struct Server;
- struct ServerFactory;
- using ServerPtr = std::unique_ptr<Server>;
- using ServerFactoryPtr = std::shared_ptr<ServerFactory>;
- /**
- * Base class of an HTTP request handler. Defining minimal interface an
- * HTTP request handler needs to implement.
- *
- * Note that each request handler may be invoked multiple times for different
- * requests.
- */
- class RequestHandler {
- public:
- explicit RequestHandler(int timeout) : m_timeout(timeout) {}
- virtual ~RequestHandler() {}
- /**
- * Called before and after request-handling work.
- */
- virtual void setupRequest(Transport* transport) {}
- virtual void teardownRequest(Transport* transport) noexcept {}
- /**
- * Sub-class handles a request by implementing this function.
- */
- virtual void handleRequest(Transport* transport) = 0;
- /**
- * Sub-class handles a request by implementing this function. This is called
- * when the server determines this request should not be processed (e.g., due
- * to timeout).
- */
- virtual void abortRequest(Transport* transport) = 0;
- /**
- * Convenience wrapper around {setup,handle,teardown}Request().
- */
- void run(Transport* transport) {
- SCOPE_EXIT { teardownRequest(transport); };
- setupRequest(transport);
- handleRequest(transport);
- }
- /**
- * Write an entry to the handler's access log.
- */
- virtual void logToAccessLog(Transport* transport) {}
- int getDefaultTimeout() const { return m_timeout; }
- private:
- int m_timeout;
- };
- typedef std::function<std::unique_ptr<RequestHandler>()> RequestHandlerFactory;
- typedef std::function<bool(const std::string&)> URLChecker;
- /**
- * Base class of an HTTP server. Defining minimal interface an HTTP server
- * needs to implement.
- */
- class Server {
- public:
- enum class RunStatus {
- NOT_YET_STARTED = 0,
- RUNNING,
- STOPPING,
- STOPPED,
- };
- /**
- * Whether to turn on full stacktrace on internal server errors. Default is
- * true.
- */
- static bool StackTraceOnError;
- /**
- * ...so that we can grarefully stop these servers on signals.
- */
- static void InstallStopSignalHandlers(ServerPtr server);
- public:
- class ServerEventListener {
- public:
- virtual ~ServerEventListener() {}
- virtual void serverStopped(Server* server) {}
- };
- /**
- * Constructor.
- */
- Server(const std::string &address, int port, int threadCount);
- /**
- * Set the RequestHandlerFactory that this server will use.
- * This must be called before start().
- */
- void setRequestHandlerFactory(RequestHandlerFactory f) {
- m_handlerFactory = f;
- }
- /**
- * Helper function to set the RequestHandlerFactory to a
- * GenericRequestHandlerFactory for the specified handler type.
- */
- template<class TRequestHandler>
- void setRequestHandlerFactory(int timeout) {
- setRequestHandlerFactory([timeout] {
- return std::unique_ptr<RequestHandler>(new TRequestHandler(timeout));
- });
- }
- /**
- * Set the URLChecker function which determines which paths this server is
- * allowed to server.
- *
- * Defaults to SatelliteServerInfo::checkURL()
- */
- void setUrlChecker(const URLChecker& checker) {
- m_urlChecker = checker;
- }
- /**
- * Add or remove a ServerEventListener.
- */
- void addServerEventListener(ServerEventListener* listener) {
- m_listeners.push_back(listener);
- }
- void removeServerEventListener(ServerEventListener* listener) {
- auto it = std::find(m_listeners.begin(), m_listeners.end(), listener);
- if (it != m_listeners.end()) {
- m_listeners.erase(it);
- }
- }
- /**
- * Add or remove a TakeoverListener to this server.
- *
- * This is a no-op for servers that do not support socket takeover.
- */
- virtual void addTakeoverListener(TakeoverListener* listener) {}
- virtual void removeTakeoverListener(TakeoverListener* listener) {}
- /**
- * Add additional worker threads
- */
- virtual void addWorkers(int numWorkers) = 0;
- /**
- * Informational.
- */
- std::string getAddress() const { return m_address;}
- int getPort() const { return m_port;}
- int getThreadCount() const { return m_threadCount;}
- RunStatus getStatus() const {
- return m_status;
- }
- void setStatus(RunStatus status) {
- m_status = status;
- }
- /**
- * Destructor.
- */
- virtual ~Server() {}
- /**
- * Start this web server. Note this is a non-blocking call.
- */
- virtual void start() = 0;
- /**
- * Block until web server is stopped.
- */
- virtual void waitForEnd() = 0;
- /**
- * Gracefully stop this web server. We will stop accepting new connections
- * and finish ongoing requests without being interrupted in the middle of
- * them. Note this is a non-blocking call and it will return immediately.
- * At background, it will eventually make the thread calling start() quit.
- */
- virtual void stop() = 0;
- /**
- * How many threads are actively working on handling requests.
- */
- virtual int getActiveWorker() = 0;
- /**
- * How many jobs are queued waiting to be handled.
- */
- virtual int getQueuedJobs() = 0;
- virtual int getLibEventConnectionCount() = 0;
- /**
- * Create a new RequestHandler.
- */
- std::unique_ptr<RequestHandler> createRequestHandler() {
- return m_handlerFactory();
- }
- /**
- * Check whether a request to the specified server path is allowed.
- */
- bool shouldHandle(const std::string &path) {
- return m_urlChecker(path);
- }
- /**
- * To enable SSL of the current server, it will listen to an additional
- * port as specified in parameter.
- */
- virtual bool enableSSL(int port) = 0;
- protected:
- std::string m_address;
- int m_port;
- int m_threadCount;
- mutable Mutex m_mutex;
- RequestHandlerFactory m_handlerFactory;
- URLChecker m_urlChecker;
- std::list<ServerEventListener*> m_listeners;
- private:
- RunStatus m_status;
- };
- class ServerOptions {
- public:
- ServerOptions(const std::string &address,
- uint16_t port,
- int numThreads)
- : m_address(address),
- m_port(port),
- m_numThreads(numThreads),
- m_serverFD(-1),
- m_sslFD(-1),
- m_takeoverFilename(),
- m_useFileSocket(false) {
- }
- std::string m_address;
- uint16_t m_port;
- int m_numThreads;
- int m_serverFD;
- int m_sslFD;
- std::string m_takeoverFilename;
- bool m_useFileSocket;
- };
- /**
- * A ServerFactory knows how to create Server objects.
- */
- class ServerFactory : private boost::noncopyable {
- public:
- virtual ~ServerFactory() {}
- virtual ServerPtr createServer(const ServerOptions &options) = 0;
- ServerPtr createServer(const std::string &address,
- uint16_t port,
- int numThreads);
- };
- /**
- * A registry mapping server type names to ServerFactory objects.
- *
- * This allows new server types to be plugged in dynamically, without having to
- * hard code the list of all possible server types.
- */
- class ServerFactoryRegistry : private boost::noncopyable {
- public:
- ServerFactoryRegistry();
- static ServerFactoryRegistry *getInstance();
- static ServerPtr createServer(const std::string &type,
- const std::string &address,
- uint16_t port,
- int numThreads);
- void registerFactory(const std::string &name,
- const ServerFactoryPtr &factory);
- ServerFactoryPtr getFactory(const std::string &name);
- private:
- Mutex m_lock;
- std::map<std::string, ServerFactoryPtr> m_factories;
- };
- /**
- * All exceptions Server throws should derive from this base class.
- */
- class ServerException : public Exception {
- public:
- ServerException(const char *fmt, ...) ATTRIBUTE_PRINTF(2,3);
- };
- class FailedToListenException : public ServerException {
- public:
- explicit FailedToListenException(const std::string &addr)
- : ServerException("Failed to listen to unix socket at %s", addr.c_str()) {
- }
- FailedToListenException(const std::string &addr, int port)
- : ServerException("Failed to listen on %s:%d", addr.c_str(), port) {
- }
- };
- class InvalidUrlException : public ServerException {
- public:
- explicit InvalidUrlException(const char *part)
- : ServerException("Invalid URL: %s", part) {
- }
- };
- class InvalidMethodException : public ServerException {
- public:
- explicit InvalidMethodException(const char *msg)
- : ServerException("Invalid method: %s", msg) {
- }
- };
- class InvalidHeaderException : public ServerException {
- public:
- InvalidHeaderException(const char *name, const char *value)
- : ServerException("Invalid header: %s: %s", name, value) {
- }
- };
- ///////////////////////////////////////////////////////////////////////////////
- }
- #endif // incl_HPHP_HTTP_SERVER_SERVER_H_