PageRenderTime 45ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/server/server.h

https://gitlab.com/Blueprint-Marketing/hhvm
C Header | 407 lines | 185 code | 57 blank | 165 comment | 2 complexity | 9650dac4e8c32b7f5fc445ca81974806 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_HTTP_SERVER_SERVER_H_
  17. #define incl_HPHP_HTTP_SERVER_SERVER_H_
  18. #include <chrono>
  19. #include <memory>
  20. #include "hphp/runtime/server/takeover-agent.h"
  21. #include "hphp/runtime/server/transport.h"
  22. #include "hphp/util/exception.h"
  23. #include "hphp/util/lock.h"
  24. /**
  25. * (1) For people who want to quickly come up with an HTTP server handling
  26. * their specific requests, we really want to minimize writing an HTTP
  27. * server to something like this,
  28. *
  29. * class MyRequestHandler : public RequestHandler {
  30. * public:
  31. * virtual void handleRequest(Transport *transport) {
  32. * // ...
  33. * }
  34. * };
  35. *
  36. * Then, run a server like this,
  37. *
  38. * auto server = std::make_shared<LibEventServer>("127.0.0.1", 80, 20);
  39. * server->setRequestHandlerFactory<MyRequestHandler>();
  40. * Server::InstallStopSignalHandlers(server);
  41. * server->start();
  42. *
  43. * This way, we can easily swap out an implementation like LibEventServer
  44. * without any modifications to MyRequestHandler, if LibEventServer model
  45. * doesn't perform well with the specific requests.
  46. *
  47. * (2) For people who are interested in implementing a high-performance HTTP
  48. * server, derive a new class from Server just like LibEventServer
  49. * does.
  50. *
  51. * class MyTransport : public Transport {
  52. * // implements transport-related functions
  53. * };
  54. *
  55. * class MyServer : public Server {
  56. * // implements how to start/stop a server
  57. * };
  58. *
  59. * (3) LibEventServer is pre-implemented with evhttp, and it has one thread
  60. * listening on a socket and dispatching jobs to multiple worker threads.
  61. *
  62. */
  63. namespace HPHP {
  64. ///////////////////////////////////////////////////////////////////////////////
  65. struct Server;
  66. struct ServerFactory;
  67. using ServerPtr = std::unique_ptr<Server>;
  68. using ServerFactoryPtr = std::shared_ptr<ServerFactory>;
  69. /**
  70. * Base class of an HTTP request handler. Defining minimal interface an
  71. * HTTP request handler needs to implement.
  72. *
  73. * Note that each request handler may be invoked multiple times for different
  74. * requests.
  75. */
  76. class RequestHandler {
  77. public:
  78. explicit RequestHandler(int timeout) : m_timeout(timeout) {}
  79. virtual ~RequestHandler() {}
  80. /**
  81. * Called before and after request-handling work.
  82. */
  83. virtual void setupRequest(Transport* transport) {}
  84. virtual void teardownRequest(Transport* transport) noexcept {}
  85. /**
  86. * Sub-class handles a request by implementing this function.
  87. */
  88. virtual void handleRequest(Transport* transport) = 0;
  89. /**
  90. * Sub-class handles a request by implementing this function. This is called
  91. * when the server determines this request should not be processed (e.g., due
  92. * to timeout).
  93. */
  94. virtual void abortRequest(Transport* transport) = 0;
  95. /**
  96. * Convenience wrapper around {setup,handle,teardown}Request().
  97. */
  98. void run(Transport* transport) {
  99. SCOPE_EXIT { teardownRequest(transport); };
  100. setupRequest(transport);
  101. handleRequest(transport);
  102. }
  103. /**
  104. * Write an entry to the handler's access log.
  105. */
  106. virtual void logToAccessLog(Transport* transport) {}
  107. int getDefaultTimeout() const { return m_timeout; }
  108. private:
  109. int m_timeout;
  110. };
  111. typedef std::function<std::unique_ptr<RequestHandler>()> RequestHandlerFactory;
  112. typedef std::function<bool(const std::string&)> URLChecker;
  113. /**
  114. * Base class of an HTTP server. Defining minimal interface an HTTP server
  115. * needs to implement.
  116. */
  117. class Server {
  118. public:
  119. enum class RunStatus {
  120. NOT_YET_STARTED = 0,
  121. RUNNING,
  122. STOPPING,
  123. STOPPED,
  124. };
  125. /**
  126. * Whether to turn on full stacktrace on internal server errors. Default is
  127. * true.
  128. */
  129. static bool StackTraceOnError;
  130. /**
  131. * ...so that we can grarefully stop these servers on signals.
  132. */
  133. static void InstallStopSignalHandlers(ServerPtr server);
  134. public:
  135. class ServerEventListener {
  136. public:
  137. virtual ~ServerEventListener() {}
  138. virtual void serverStopped(Server* server) {}
  139. };
  140. /**
  141. * Constructor.
  142. */
  143. Server(const std::string &address, int port, int threadCount);
  144. /**
  145. * Set the RequestHandlerFactory that this server will use.
  146. * This must be called before start().
  147. */
  148. void setRequestHandlerFactory(RequestHandlerFactory f) {
  149. m_handlerFactory = f;
  150. }
  151. /**
  152. * Helper function to set the RequestHandlerFactory to a
  153. * GenericRequestHandlerFactory for the specified handler type.
  154. */
  155. template<class TRequestHandler>
  156. void setRequestHandlerFactory(int timeout) {
  157. setRequestHandlerFactory([timeout] {
  158. return std::unique_ptr<RequestHandler>(new TRequestHandler(timeout));
  159. });
  160. }
  161. /**
  162. * Set the URLChecker function which determines which paths this server is
  163. * allowed to server.
  164. *
  165. * Defaults to SatelliteServerInfo::checkURL()
  166. */
  167. void setUrlChecker(const URLChecker& checker) {
  168. m_urlChecker = checker;
  169. }
  170. /**
  171. * Add or remove a ServerEventListener.
  172. */
  173. void addServerEventListener(ServerEventListener* listener) {
  174. m_listeners.push_back(listener);
  175. }
  176. void removeServerEventListener(ServerEventListener* listener) {
  177. auto it = std::find(m_listeners.begin(), m_listeners.end(), listener);
  178. if (it != m_listeners.end()) {
  179. m_listeners.erase(it);
  180. }
  181. }
  182. /**
  183. * Add or remove a TakeoverListener to this server.
  184. *
  185. * This is a no-op for servers that do not support socket takeover.
  186. */
  187. virtual void addTakeoverListener(TakeoverListener* listener) {}
  188. virtual void removeTakeoverListener(TakeoverListener* listener) {}
  189. /**
  190. * Add additional worker threads
  191. */
  192. virtual void addWorkers(int numWorkers) = 0;
  193. /**
  194. * Informational.
  195. */
  196. std::string getAddress() const { return m_address;}
  197. int getPort() const { return m_port;}
  198. int getThreadCount() const { return m_threadCount;}
  199. RunStatus getStatus() const {
  200. return m_status;
  201. }
  202. void setStatus(RunStatus status) {
  203. m_status = status;
  204. }
  205. /**
  206. * Destructor.
  207. */
  208. virtual ~Server() {}
  209. /**
  210. * Start this web server. Note this is a non-blocking call.
  211. */
  212. virtual void start() = 0;
  213. /**
  214. * Block until web server is stopped.
  215. */
  216. virtual void waitForEnd() = 0;
  217. /**
  218. * Gracefully stop this web server. We will stop accepting new connections
  219. * and finish ongoing requests without being interrupted in the middle of
  220. * them. Note this is a non-blocking call and it will return immediately.
  221. * At background, it will eventually make the thread calling start() quit.
  222. */
  223. virtual void stop() = 0;
  224. /**
  225. * How many threads are actively working on handling requests.
  226. */
  227. virtual int getActiveWorker() = 0;
  228. /**
  229. * How many jobs are queued waiting to be handled.
  230. */
  231. virtual int getQueuedJobs() = 0;
  232. virtual int getLibEventConnectionCount() = 0;
  233. /**
  234. * Create a new RequestHandler.
  235. */
  236. std::unique_ptr<RequestHandler> createRequestHandler() {
  237. return m_handlerFactory();
  238. }
  239. /**
  240. * Check whether a request to the specified server path is allowed.
  241. */
  242. bool shouldHandle(const std::string &path) {
  243. return m_urlChecker(path);
  244. }
  245. /**
  246. * To enable SSL of the current server, it will listen to an additional
  247. * port as specified in parameter.
  248. */
  249. virtual bool enableSSL(int port) = 0;
  250. protected:
  251. std::string m_address;
  252. int m_port;
  253. int m_threadCount;
  254. mutable Mutex m_mutex;
  255. RequestHandlerFactory m_handlerFactory;
  256. URLChecker m_urlChecker;
  257. std::list<ServerEventListener*> m_listeners;
  258. private:
  259. RunStatus m_status;
  260. };
  261. class ServerOptions {
  262. public:
  263. ServerOptions(const std::string &address,
  264. uint16_t port,
  265. int numThreads)
  266. : m_address(address),
  267. m_port(port),
  268. m_numThreads(numThreads),
  269. m_serverFD(-1),
  270. m_sslFD(-1),
  271. m_takeoverFilename(),
  272. m_useFileSocket(false) {
  273. }
  274. std::string m_address;
  275. uint16_t m_port;
  276. int m_numThreads;
  277. int m_serverFD;
  278. int m_sslFD;
  279. std::string m_takeoverFilename;
  280. bool m_useFileSocket;
  281. };
  282. /**
  283. * A ServerFactory knows how to create Server objects.
  284. */
  285. class ServerFactory : private boost::noncopyable {
  286. public:
  287. virtual ~ServerFactory() {}
  288. virtual ServerPtr createServer(const ServerOptions &options) = 0;
  289. ServerPtr createServer(const std::string &address,
  290. uint16_t port,
  291. int numThreads);
  292. };
  293. /**
  294. * A registry mapping server type names to ServerFactory objects.
  295. *
  296. * This allows new server types to be plugged in dynamically, without having to
  297. * hard code the list of all possible server types.
  298. */
  299. class ServerFactoryRegistry : private boost::noncopyable {
  300. public:
  301. ServerFactoryRegistry();
  302. static ServerFactoryRegistry *getInstance();
  303. static ServerPtr createServer(const std::string &type,
  304. const std::string &address,
  305. uint16_t port,
  306. int numThreads);
  307. void registerFactory(const std::string &name,
  308. const ServerFactoryPtr &factory);
  309. ServerFactoryPtr getFactory(const std::string &name);
  310. private:
  311. Mutex m_lock;
  312. std::map<std::string, ServerFactoryPtr> m_factories;
  313. };
  314. /**
  315. * All exceptions Server throws should derive from this base class.
  316. */
  317. class ServerException : public Exception {
  318. public:
  319. ServerException(const char *fmt, ...) ATTRIBUTE_PRINTF(2,3);
  320. };
  321. class FailedToListenException : public ServerException {
  322. public:
  323. explicit FailedToListenException(const std::string &addr)
  324. : ServerException("Failed to listen to unix socket at %s", addr.c_str()) {
  325. }
  326. FailedToListenException(const std::string &addr, int port)
  327. : ServerException("Failed to listen on %s:%d", addr.c_str(), port) {
  328. }
  329. };
  330. class InvalidUrlException : public ServerException {
  331. public:
  332. explicit InvalidUrlException(const char *part)
  333. : ServerException("Invalid URL: %s", part) {
  334. }
  335. };
  336. class InvalidMethodException : public ServerException {
  337. public:
  338. explicit InvalidMethodException(const char *msg)
  339. : ServerException("Invalid method: %s", msg) {
  340. }
  341. };
  342. class InvalidHeaderException : public ServerException {
  343. public:
  344. InvalidHeaderException(const char *name, const char *value)
  345. : ServerException("Invalid header: %s: %s", name, value) {
  346. }
  347. };
  348. ///////////////////////////////////////////////////////////////////////////////
  349. }
  350. #endif // incl_HPHP_HTTP_SERVER_SERVER_H_