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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_HTTP_SERVER_SERVER_H_
18 #define incl_HPHP_HTTP_SERVER_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/lock.h"
34 * (1) For people who want to quickly come up with an HTTP server handling
35 * their specific requests, we really want to minimize writing an HTTP
36 * server to something like this,
38 * struct MyRequestHandler : RequestHandler {
39 * virtual void handleRequest(Transport *transport) {
44 * Then, run a server like this,
46 * auto server = std::make_shared<LibEventServer>("127.0.0.1", 80, 20);
47 * server->setRequestHandlerFactory<MyRequestHandler>();
48 * Server::InstallStopSignalHandlers(server);
51 * This way, we can easily swap out an implementation like LibEventServer
52 * without any modifications to MyRequestHandler, if LibEventServer model
53 * doesn't perform well with the specific requests.
55 * (2) For people who are interested in implementing a high-performance HTTP
56 * server, derive a new class from Server just like LibEventServer
59 * struct MyTransport : Transport {
60 * // implements transport-related functions
63 * struct MyServer : Server {
64 * // implements how to start/stop a server
67 * (3) LibEventServer is pre-implemented with evhttp, and it has one thread
68 * listening on a socket and dispatching jobs to multiple worker threads.
73 ///////////////////////////////////////////////////////////////////////////////
77 using ServerPtr
= std::unique_ptr
<Server
>;
78 using ServerFactoryPtr
= std::shared_ptr
<ServerFactory
>;
81 * Base class of an HTTP request handler. Defining minimal interface an
82 * HTTP request handler needs to implement.
84 * Note that each request handler may be invoked multiple times for different
87 struct RequestHandler
{
88 explicit RequestHandler(int timeout
) : m_timeout(timeout
) {}
89 virtual ~RequestHandler() {}
92 * Called before and after request-handling work.
94 virtual void setupRequest(Transport
* /*transport*/) {}
95 virtual void teardownRequest(Transport
* /*transport*/) noexcept
{}
98 * Sub-class handles a request by implementing this function.
100 virtual void handleRequest(Transport
* transport
) = 0;
103 * Sub-class handles a request by implementing this function. This is called
104 * when the server determines this request should not be processed (e.g., due
107 virtual void abortRequest(Transport
* transport
) = 0;
110 * Convenience wrapper around {setup,handle,teardown}Request().
112 void run(Transport
* transport
) {
113 SCOPE_EXIT
{ teardownRequest(transport
); };
114 setupRequest(transport
);
115 handleRequest(transport
);
119 * Write an entry to the handler's access log.
121 virtual void logToAccessLog(Transport
* /*transport*/) {}
123 int getDefaultTimeout() const { return m_timeout
; }
129 using RequestHandlerFactory
= std::function
<std::unique_ptr
<RequestHandler
>()>;
130 using URLChecker
= std::function
<bool(const std::string
&)>;
133 * Base class of an HTTP server. Defining minimal interface an HTTP server
134 * needs to implement.
136 struct Server
: IHostHealthObserver
{
137 enum class RunStatus
{
145 * Whether to turn on full stacktrace on internal server errors. Default is
148 static bool StackTraceOnError
;
151 * ...so that we can grarefully stop these servers on signals.
153 static void InstallStopSignalHandlers(ServerPtr server
);
156 struct ServerEventListener
{
157 virtual ~ServerEventListener() {}
158 virtual void serverStopped(Server
* /*server*/) {}
161 Server(const std::string
&address
, int port
);
164 * Set the RequestHandlerFactory that this server will use.
165 * This must be called before start().
167 void setRequestHandlerFactory(RequestHandlerFactory f
) {
168 m_handlerFactory
= f
;
171 * Helper function to set the RequestHandlerFactory to a
172 * GenericRequestHandlerFactory for the specified handler type.
174 template<class TRequestHandler
>
175 void setRequestHandlerFactory(int timeout
) {
176 setRequestHandlerFactory([timeout
] {
177 return std::unique_ptr
<RequestHandler
>(new TRequestHandler(timeout
));
182 * Set the URLChecker function which determines which paths this server is
185 * Defaults to SatelliteServerInfo::checkURL()
187 void setUrlChecker(const URLChecker
& checker
) {
188 m_urlChecker
= checker
;
192 * Add or remove a ServerEventListener.
194 void addServerEventListener(ServerEventListener
* listener
) {
195 m_listeners
.push_back(listener
);
197 void removeServerEventListener(ServerEventListener
* listener
) {
198 auto it
= std::find(m_listeners
.begin(), m_listeners
.end(), listener
);
199 if (it
!= m_listeners
.end()) {
200 m_listeners
.erase(it
);
205 * Add or remove a TakeoverListener to this server.
207 * This is a no-op for servers that do not support socket takeover.
209 virtual void addTakeoverListener(TakeoverListener
* /*listener*/) {}
210 virtual void removeTakeoverListener(TakeoverListener
* /*listener*/) {}
213 * Add additional worker threads
215 virtual void addWorkers(int numWorkers
) = 0;
220 std::string
getAddress() const { return m_address
;}
221 int getPort() const { return m_port
;}
223 RunStatus
getStatus() const { return m_status
;}
224 void setStatus(RunStatus status
) { m_status
= status
;}
226 * IHostHealthObserver interface. Note that m_status doesn't
227 * contain server health information.
229 void notifyNewStatus(HealthLevel newLevel
) override
{
230 m_healthLevel
= newLevel
;
232 HealthLevel
getHealthLevel() override
{
233 return m_healthLevel
;
239 ~Server() override
{}
242 * Start this web server. Note this is a non-blocking call.
244 virtual void start() = 0;
247 * Block until web server is stopped.
249 virtual void waitForEnd() = 0;
252 * Gracefully stop this web server. We will stop accepting new connections
253 * and finish ongoing requests without being interrupted in the middle of
254 * them. Note this is a non-blocking call and it will return immediately.
255 * At background, it will eventually make the thread calling start() quit.
257 virtual void stop() = 0;
260 * How many threads are actively working on handling requests.
262 virtual int getActiveWorker() = 0;
265 * How many jobs are queued waiting to be handled.
267 virtual int getQueuedJobs() = 0;
269 virtual int getLibEventConnectionCount() = 0;
272 * Create a new RequestHandler.
274 std::unique_ptr
<RequestHandler
> createRequestHandler() {
275 return m_handlerFactory();
279 * Check whether a request to the specified server path is allowed.
281 bool shouldHandle(const std::string
&path
) {
282 return m_urlChecker(path
);
286 * To enable SSL of the current server, it will listen to an additional
287 * port as specified in parameter.
289 virtual bool enableSSL(int port
) = 0;
292 * To enable SSL in addition to plaintext of the current server.
294 virtual bool enableSSLWithPlainText() {
299 std::string m_address
;
301 mutable Mutex m_mutex
;
302 RequestHandlerFactory m_handlerFactory
;
303 URLChecker m_urlChecker
;
304 std::list
<ServerEventListener
*> m_listeners
;
307 RunStatus m_status
{RunStatus::NOT_YET_STARTED
};
308 HealthLevel m_healthLevel
{HealthLevel::Bold
};
311 struct ServerOptions
{
312 ServerOptions(const std::string
&address
,
315 int initThreads
= -1)
316 : m_address(address
),
318 m_maxThreads(maxThreads
),
319 m_initThreads(initThreads
),
322 m_takeoverFilename(),
323 m_useFileSocket(false),
324 m_queueToWorkerRatio(1),
326 assertx(m_maxThreads
>= 0);
327 if (m_initThreads
< 0 || m_initThreads
> m_maxThreads
) {
328 m_initThreads
= m_maxThreads
;
332 std::string m_address
;
338 std::string m_takeoverFilename
;
339 bool m_useFileSocket
;
340 int m_queueToWorkerRatio
;
345 * A ServerFactory knows how to create Server objects.
347 struct ServerFactory
{
349 virtual ~ServerFactory() {}
351 ServerFactory(const ServerFactory
&) = delete;
352 ServerFactory
& operator=(const ServerFactory
&) = delete;
354 virtual ServerPtr
createServer(const ServerOptions
&options
) = 0;
356 ServerPtr
createServer(const std::string
&address
,
359 int initThreads
= -1);
363 * A registry mapping server type names to ServerFactory objects.
365 * This allows new server types to be plugged in dynamically, without having to
366 * hard code the list of all possible server types.
368 struct ServerFactoryRegistry
{
369 ServerFactoryRegistry();
371 ServerFactoryRegistry(const ServerFactoryRegistry
&) = delete;
372 ServerFactoryRegistry
& operator=(const ServerFactoryRegistry
&) = delete;
374 static ServerFactoryRegistry
*getInstance();
376 static ServerPtr
createServer(const std::string
&type
,
377 const std::string
&address
,
380 int initThreads
= -1);
382 void registerFactory(const std::string
&name
,
383 const ServerFactoryPtr
&factory
);
385 ServerFactoryPtr
getFactory(const std::string
&name
);
389 std::map
<std::string
, ServerFactoryPtr
> m_factories
;
393 * All exceptions Server throws should derive from this base class.
395 struct ServerException
: Exception
{
396 ServerException(ATTRIBUTE_PRINTF_STRING
const char *fmt
, ...)
397 ATTRIBUTE_PRINTF(2,3);
400 struct FailedToListenException
: ServerException
{
401 explicit FailedToListenException(const std::string
&addr
)
402 : ServerException("Failed to listen to unix socket at %s", addr
.c_str()) {
404 FailedToListenException(const std::string
&addr
, int port
)
405 : ServerException("Failed to listen on %s:%d", addr
.c_str(), port
) {
409 struct InvalidUrlException
: ServerException
{
410 explicit InvalidUrlException(const char *part
)
411 : ServerException("Invalid URL: %s", part
) {
415 struct InvalidMethodException
: ServerException
{
416 explicit InvalidMethodException(const char *msg
)
417 : ServerException("Invalid method: %s", msg
) {
421 struct InvalidHeaderException
: ServerException
{
422 InvalidHeaderException(const char *name
, const char *value
)
423 : ServerException("Invalid header: %s: %s", name
, value
) {
427 ///////////////////////////////////////////////////////////////////////////////
430 #endif // incl_HPHP_HTTP_SERVER_SERVER_H_