Updating submodules
[hiphop-php.git] / hphp / runtime / server / server.h
blob0a7e839a10f258179a6cd84c227df4cf30794801
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 +----------------------------------------------------------------------+
17 #pragma once
19 #include <algorithm>
20 #include <chrono>
21 #include <functional>
22 #include <list>
23 #include <memory>
24 #include <string>
26 #include "hphp/runtime/server/cli-server.h"
27 #include "hphp/runtime/server/takeover-agent.h"
28 #include "hphp/runtime/server/transport.h"
29 #include "hphp/util/exception.h"
30 #include "hphp/util/health-monitor-types.h"
31 #include "hphp/util/job-queue.h"
32 #include "hphp/util/lock.h"
34 /**
35 * (1) For people who want to quickly come up with an HTTP server handling
36 * their specific requests, we really want to minimize writing an HTTP
37 * server to something like this,
39 * struct MyRequestHandler : RequestHandler {
40 * virtual void handleRequest(Transport *transport) {
41 * // ...
42 * }
43 * };
45 * Then, run a server like this,
47 * auto server = std::make_shared<LibEventServer>("127.0.0.1", 80, 20);
48 * server->setRequestHandlerFactory<MyRequestHandler>();
49 * Server::InstallStopSignalHandlers(server);
50 * server->start();
52 * This way, we can easily swap out an implementation like LibEventServer
53 * without any modifications to MyRequestHandler, if LibEventServer model
54 * doesn't perform well with the specific requests.
56 * (2) For people who are interested in implementing a high-performance HTTP
57 * server, derive a new class from Server just like LibEventServer
58 * does.
60 * struct MyTransport : Transport {
61 * // implements transport-related functions
62 * };
64 * struct MyServer : Server {
65 * // implements how to start/stop a server
66 * };
68 * (3) LibEventServer is pre-implemented with evhttp, and it has one thread
69 * listening on a socket and dispatching jobs to multiple worker threads.
73 namespace HPHP {
74 ///////////////////////////////////////////////////////////////////////////////
76 struct Server;
77 struct ServerFactory;
78 using ServerPtr = std::unique_ptr<Server>;
79 using ServerFactoryPtr = std::shared_ptr<ServerFactory>;
81 /**
82 * Base class of an HTTP request handler. Defining minimal interface an
83 * HTTP request handler needs to implement.
85 * Note that each request handler may be invoked multiple times for different
86 * requests.
88 struct RequestHandler {
89 explicit RequestHandler() {}
90 explicit RequestHandler(int timeout) : m_timeout(timeout) {}
91 virtual ~RequestHandler() {}
93 /**
94 * Called before and after request-handling work.
96 virtual void setupRequest(Transport* /*transport*/) {}
97 virtual void teardownRequest(Transport* /*transport*/) = 0;
99 /**
100 * Sub-class handles a request by implementing this function.
102 virtual void handleRequest(Transport* transport) = 0;
105 * Sub-class handles a request by implementing this function. This is called
106 * when the server determines this request should not be processed (e.g., due
107 * to timeout).
109 virtual void abortRequest(Transport* transport) = 0;
112 * Convenience wrapper around {setup,handle,teardown}Request().
114 void run(Transport* transport) {
115 SCOPE_EXIT { teardownRequest(transport); };
116 setupRequest(transport);
117 handleRequest(transport);
121 * Write an entry to the handler's access log.
123 virtual void logToAccessLog(Transport* /*transport*/) {}
125 virtual void setCliContext(CLIContext&& ctx) {}
127 int getDefaultTimeout() const { return m_timeout; }
129 private:
130 int m_timeout;
133 using RequestHandlerFactory = std::function<std::unique_ptr<RequestHandler>()>;
134 using URLChecker = std::function<bool(const std::string&)>;
137 * Base class of an HTTP server. Defining minimal interface an HTTP server
138 * needs to implement.
140 struct Server : IHostHealthObserver {
141 enum class RunStatus {
142 NOT_YET_STARTED = 0,
143 RUNNING,
144 STOPPING,
145 STOPPED,
149 * Whether to turn on full stacktrace on internal server errors. Default is
150 * true.
152 static bool StackTraceOnError;
155 * ...so that we can grarefully stop these servers on signals.
157 static void InstallStopSignalHandlers(ServerPtr server);
159 public:
160 struct ServerEventListener {
161 virtual ~ServerEventListener() {}
162 virtual void serverStopped(Server* /*server*/) {}
165 Server(const std::string &address, int port);
168 * Set the RequestHandlerFactory that this server will use.
169 * This must be called before start().
171 void setRequestHandlerFactory(RequestHandlerFactory f) {
172 m_handlerFactory = f;
175 * Helper function to set the RequestHandlerFactory to a
176 * GenericRequestHandlerFactory for the specified handler type.
178 template<class TRequestHandler>
179 void setRequestHandlerFactory(int timeout) {
180 setRequestHandlerFactory([timeout] {
181 return std::unique_ptr<RequestHandler>(new TRequestHandler(timeout));
186 * Set the URLChecker function which determines which paths this server is
187 * allowed to server.
189 * Defaults to SatelliteServerInfo::checkURL()
191 void setUrlChecker(const URLChecker& checker) {
192 m_urlChecker = checker;
196 * Add or remove a ServerEventListener.
198 void addServerEventListener(ServerEventListener* listener) {
199 m_listeners.push_back(listener);
201 void removeServerEventListener(ServerEventListener* listener) {
202 auto it = std::find(m_listeners.begin(), m_listeners.end(), listener);
203 if (it != m_listeners.end()) {
204 m_listeners.erase(it);
209 * Add or remove a TakeoverListener to this server.
211 * This is a no-op for servers that do not support socket takeover.
213 virtual void addTakeoverListener(TakeoverListener* /*listener*/) {}
214 virtual void removeTakeoverListener(TakeoverListener* /*listener*/) {}
217 * Add additional worker threads
219 virtual void saturateWorkers() = 0;
222 * Informational.
224 std::string getAddress() const { return m_address;}
225 int getPort() const { return m_port;}
227 RunStatus getStatus() const {
228 return m_status.load(std::memory_order_acquire);
230 void setStatus(RunStatus status) {
231 m_status.store(status, std::memory_order_release);
235 * IHostHealthObserver interface. Note that m_status doesn't
236 * contain server health information.
238 void notifyNewStatus(HealthLevel newLevel) override {
239 m_healthLevel = newLevel;
241 HealthLevel getHealthLevel() override {
242 return m_healthLevel;
246 * Destructor.
248 ~Server() override {}
251 * Start this web server. Note this is a non-blocking call.
253 virtual void start() = 0;
256 * Block until web server is stopped.
258 virtual void waitForEnd() = 0;
261 * Gracefully stop this web server. We will stop accepting new connections
262 * and finish ongoing requests without being interrupted in the middle of
263 * them. Note this is a non-blocking call and it will return immediately.
264 * At background, it will eventually make the thread calling start() quit.
266 virtual void stop() = 0;
269 * How many threads can be available for handling requests.
271 virtual size_t getMaxThreadCount() = 0;
274 * Set the max threads that can be used for handling requests.
276 virtual void setMaxThreadCount(size_t count) = 0;
279 * How many threads are actively working on handling requests.
281 virtual int getActiveWorker() = 0;
284 * Update the maximum number of threads allowed to handle requests at a
285 * time.
287 virtual void updateMaxActiveWorkers(int) = 0;
290 * How many jobs are queued waiting to be handled.
292 virtual int getQueuedJobs() = 0;
294 virtual int getLibEventConnectionCount() = 0;
297 * Create a new RequestHandler.
299 std::unique_ptr<RequestHandler> createRequestHandler() {
300 return m_handlerFactory();
304 * Check whether a request to the specified server path is allowed.
306 bool shouldHandle(const std::string &path) {
307 return m_urlChecker(path);
311 * To enable SSL of the current server, it will listen to an additional
312 * port as specified in parameter.
314 virtual bool enableSSL(int port) = 0;
317 * To enable SSL in addition to plaintext of the current server.
319 virtual bool enableSSLWithPlainText() {
320 return false;
323 virtual DispatcherStats getDispatcherStats() = 0;
325 protected:
326 std::string m_address;
327 int m_port;
328 mutable Mutex m_mutex;
329 RequestHandlerFactory m_handlerFactory;
330 URLChecker m_urlChecker;
331 std::list<ServerEventListener*> m_listeners;
333 private:
334 std::atomic<RunStatus> m_status{RunStatus::NOT_YET_STARTED};
335 HealthLevel m_healthLevel{HealthLevel::Bold};
338 struct ServerOptions {
339 ServerOptions(const std::string &address,
340 uint16_t port,
341 int maxThreads,
342 int initThreads = -1,
343 int maxQueue = -1)
344 : m_address(address),
345 m_port(port),
346 m_maxThreads(maxThreads),
347 m_initThreads(initThreads),
348 m_maxQueue(maxQueue == -1 ? maxThreads : maxQueue) {
349 assertx(m_maxThreads >= 0);
350 if (m_initThreads < 0 || m_initThreads > m_maxThreads) {
351 m_initThreads = m_maxThreads;
355 std::string m_address;
356 uint16_t m_port;
357 int m_maxThreads;
358 int m_initThreads;
359 int m_maxQueue;
360 int m_serverFD{-1};
361 int m_sslFD{-1};
362 std::string m_takeoverFilename;
363 bool m_useFileSocket{false};
364 int m_hugeThreads{0};
365 unsigned m_hugeStackKb{0};
366 unsigned m_extraKb{0};
367 uint32_t m_loop_sample_rate{0};
371 * A ServerFactory knows how to create Server objects.
373 struct ServerFactory {
374 ServerFactory() {}
375 virtual ~ServerFactory() {}
377 ServerFactory(const ServerFactory&) = delete;
378 ServerFactory& operator=(const ServerFactory&) = delete;
380 virtual ServerPtr createServer(const ServerOptions &options) = 0;
382 ServerPtr createServer(const std::string &address,
383 uint16_t port,
384 int maxThreads,
385 int initThreads = -1);
389 * A registry mapping server type names to ServerFactory objects.
391 * This allows new server types to be plugged in dynamically, without having to
392 * hard code the list of all possible server types.
394 struct ServerFactoryRegistry {
395 ServerFactoryRegistry();
397 ServerFactoryRegistry(const ServerFactoryRegistry&) = delete;
398 ServerFactoryRegistry& operator=(const ServerFactoryRegistry&) = delete;
400 static ServerFactoryRegistry *getInstance();
402 static ServerPtr createServer(const std::string &type,
403 const std::string &address,
404 uint16_t port,
405 int maxThreads,
406 int initThreads = -1);
408 void registerFactory(const std::string &name,
409 const ServerFactoryPtr &factory);
411 ServerFactoryPtr getFactory(const std::string &name);
413 private:
414 Mutex m_lock;
415 std::map<std::string, ServerFactoryPtr> m_factories;
419 * All exceptions Server throws should derive from this base class.
421 struct ServerException : Exception {
422 ServerException(ATTRIBUTE_PRINTF_STRING const char *fmt, ...)
423 ATTRIBUTE_PRINTF(2,3);
426 struct FailedToListenException : ServerException {
427 explicit FailedToListenException(const std::string &addr)
428 : ServerException("Failed to listen to unix socket at %s", addr.c_str()) {
430 FailedToListenException(const std::string &addr, int port)
431 : ServerException("Failed to listen on %s:%d", addr.c_str(), port) {
435 struct InvalidUrlException : ServerException {
436 explicit InvalidUrlException(const char *part)
437 : ServerException("Invalid URL: %s", part) {
441 struct InvalidMethodException : ServerException {
442 explicit InvalidMethodException(const char *msg)
443 : ServerException("Invalid method: %s", msg) {
447 struct InvalidHeaderException : ServerException {
448 InvalidHeaderException(const char *name, const char *value)
449 : ServerException("Invalid header: %s: %s", name, value) {
453 ///////////////////////////////////////////////////////////////////////////////