2 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
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"
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) {
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);
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
60 * struct MyTransport : Transport {
61 * // implements transport-related functions
64 * struct MyServer : Server {
65 * // implements how to start/stop a server
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.
74 ///////////////////////////////////////////////////////////////////////////////
78 using ServerPtr
= std::unique_ptr
<Server
>;
79 using ServerFactoryPtr
= std::shared_ptr
<ServerFactory
>;
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
88 struct RequestHandler
{
89 explicit RequestHandler() {}
90 explicit RequestHandler(int timeout
) : m_timeout(timeout
) {}
91 virtual ~RequestHandler() {}
94 * Called before and after request-handling work.
96 virtual void setupRequest(Transport
* /*transport*/) {}
97 virtual void teardownRequest(Transport
* /*transport*/) = 0;
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
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
; }
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
{
149 * Whether to turn on full stacktrace on internal server errors. Default is
152 static bool StackTraceOnError
;
155 * ...so that we can grarefully stop these servers on signals.
157 static void InstallStopSignalHandlers(ServerPtr server
);
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
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;
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
;
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
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() {
323 virtual DispatcherStats
getDispatcherStats() = 0;
326 std::string m_address
;
328 mutable Mutex m_mutex
;
329 RequestHandlerFactory m_handlerFactory
;
330 URLChecker m_urlChecker
;
331 std::list
<ServerEventListener
*> m_listeners
;
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
,
342 int initThreads
= -1,
344 : m_address(address
),
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
;
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
{
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
,
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
,
406 int initThreads
= -1);
408 void registerFactory(const std::string
&name
,
409 const ServerFactoryPtr
&factory
);
411 ServerFactoryPtr
getFactory(const std::string
&name
);
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 ///////////////////////////////////////////////////////////////////////////////