Request limiting, config improvements
* Added middleware to limit concurrent request and request body size * The default configuration now has the defaults
This commit is contained in:
		@@ -50,15 +50,12 @@ if (isset($opts['C'])) {
 | 
				
			|||||||
    file_put_contents($file, <<<DEFAULTS
 | 
					    file_put_contents($file, <<<DEFAULTS
 | 
				
			||||||
    server:
 | 
					    server:
 | 
				
			||||||
      address: 0.0.0.0:9000
 | 
					      address: 0.0.0.0:9000
 | 
				
			||||||
      public_url: https://example.com
 | 
					 | 
				
			||||||
      websockets: false
 | 
					      websockets: false
 | 
				
			||||||
      cors:
 | 
					      cors:
 | 
				
			||||||
        allow_origin: '*'
 | 
					        allow_origin: '*'
 | 
				
			||||||
        csp: "default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'"
 | 
					        csp: "default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'"
 | 
				
			||||||
      encryption:
 | 
					      encryption:
 | 
				
			||||||
        local_cert: ~
 | 
					        local_cert: ~
 | 
				
			||||||
        local_pk: ~
 | 
					 | 
				
			||||||
        passphrase: ~
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    publish:
 | 
					    publish:
 | 
				
			||||||
      overwrite_ids: false
 | 
					      overwrite_ids: false
 | 
				
			||||||
@@ -78,12 +75,7 @@ if (isset($opts['C'])) {
 | 
				
			|||||||
if (isset($opts['c'])) {
 | 
					if (isset($opts['c'])) {
 | 
				
			||||||
    $config = Configuration::fromFile($opts['c']);
 | 
					    $config = Configuration::fromFile($opts['c']);
 | 
				
			||||||
} else {
 | 
					} else {
 | 
				
			||||||
    $config = Configuration::createDefault()
 | 
					    $config = Configuration::createDefault();
 | 
				
			||||||
        ->setListenAddress('127.0.0.1:8888')
 | 
					 | 
				
			||||||
        ->setAllowOriginHeader("*")
 | 
					 | 
				
			||||||
        ->setContentSecurityPolicyHeader("default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'")
 | 
					 | 
				
			||||||
        ->setAllowAnonymousSubscribe(true)
 | 
					 | 
				
			||||||
        ->setJwtSecret("!ChangeThisMercureHubJWTSecretKey!");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$verbose = isset($opts['v']);
 | 
					$verbose = isset($opts['v']);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,13 @@ server:
 | 
				
			|||||||
    local_pk: ~
 | 
					    local_pk: ~
 | 
				
			||||||
    passphrase: ~
 | 
					    passphrase: ~
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					  # Limits
 | 
				
			||||||
 | 
					  #   max_concurent (int) - how many requests that can be handled at once
 | 
				
			||||||
 | 
					  #   max_request_body (int) - max request body size
 | 
				
			||||||
 | 
					  limits:
 | 
				
			||||||
 | 
					    max_concurrent: 20
 | 
				
			||||||
 | 
					    max_request_body: 102400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
publish:
 | 
					publish:
 | 
				
			||||||
  # Assign a UUID to published messages even if one is already set in the message
 | 
					  # Assign a UUID to published messages even if one is already set in the message
 | 
				
			||||||
  overwrite_ids: false
 | 
					  overwrite_ids: false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,18 @@ class Configuration
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public static function createDefault(): Configuration
 | 
					    public static function createDefault(): Configuration
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return new Configuration();
 | 
					        return new Configuration([
 | 
				
			||||||
 | 
					            "publish.overwrite_ids" => false,
 | 
				
			||||||
 | 
					            "publish.reject_duplicates" => false,
 | 
				
			||||||
 | 
					            "server.address" => "127.0.0.1:9000",
 | 
				
			||||||
 | 
					            "server.enable_api" => true,
 | 
				
			||||||
 | 
					            "server.limits.max_concurrent" => 100,
 | 
				
			||||||
 | 
					            "server.limits.max_request_body" => 102400,
 | 
				
			||||||
 | 
					            "server.cors.allow_origin" => "*",
 | 
				
			||||||
 | 
					            "server.cors.csp" => "default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'",
 | 
				
			||||||
 | 
					            "subscribe.allow_anonymous" => true,
 | 
				
			||||||
 | 
					            "security.jwt_secret" => "!ChangeThisMercureHubJWTSecretKey!",
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static function fromFile(string $file): Configuration
 | 
					    public static function fromFile(string $file): Configuration
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,8 @@ use Psr\Log\NullLogger;
 | 
				
			|||||||
use React\EventLoop\Loop;
 | 
					use React\EventLoop\Loop;
 | 
				
			||||||
use React\EventLoop\LoopInterface;
 | 
					use React\EventLoop\LoopInterface;
 | 
				
			||||||
use React\Http\HttpServer;
 | 
					use React\Http\HttpServer;
 | 
				
			||||||
 | 
					use React\Http\Middleware\LimitConcurrentRequestsMiddleware;
 | 
				
			||||||
 | 
					use React\Http\Middleware\RequestBodyBufferMiddleware;
 | 
				
			||||||
use React\Socket\SecureServer;
 | 
					use React\Socket\SecureServer;
 | 
				
			||||||
use React\Socket\ServerInterface;
 | 
					use React\Socket\ServerInterface;
 | 
				
			||||||
use SplObjectStorage;
 | 
					use SplObjectStorage;
 | 
				
			||||||
@@ -90,7 +92,15 @@ class Server
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    private function createHttpServer(): HttpServer
 | 
					    private function createHttpServer(): HttpServer
 | 
				
			||||||
    {  
 | 
					    {  
 | 
				
			||||||
        $stack = [
 | 
					        $stack = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $maxConcurrent = $this->config->get("server.limits.max_concurrent", 100);
 | 
				
			||||||
 | 
					        $maxRequestBody = $this->config->get("server.limits.max_request_body", 102400);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $stack[] = new LimitConcurrentRequestsMiddleware($maxConcurrent);
 | 
				
			||||||
 | 
					        $stack[] = new RequestBodyBufferMiddleware($maxRequestBody);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $stack = [ ...$stack,
 | 
				
			||||||
            $this->responseMiddleware = new ResponseMiddleware(
 | 
					            $this->responseMiddleware = new ResponseMiddleware(
 | 
				
			||||||
                config: $this->config,
 | 
					                config: $this->config,
 | 
				
			||||||
                logger: $this->logger->withName("http"),
 | 
					                logger: $this->logger->withName("http"),
 | 
				
			||||||
@@ -99,6 +109,7 @@ class Server
 | 
				
			|||||||
                config: $this->config
 | 
					                config: $this->config
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($this->config->getEnableWebSockets()) {
 | 
					        if ($this->config->getEnableWebSockets()) {
 | 
				
			||||||
            $stack = [ ...$stack, 
 | 
					            $stack = [ ...$stack, 
 | 
				
			||||||
                $this->webSocketHandler   = new WebSocketHandler(
 | 
					                $this->webSocketHandler   = new WebSocketHandler(
 | 
				
			||||||
@@ -109,6 +120,7 @@ class Server
 | 
				
			|||||||
            ];
 | 
					            ];
 | 
				
			||||||
            $this->logger->warning("The WebSocket support is incomplete and insecure, but enabling it as requested.");
 | 
					            $this->logger->warning("The WebSocket support is incomplete and insecure, but enabling it as requested.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $stack = [ ...$stack, 
 | 
					        $stack = [ ...$stack, 
 | 
				
			||||||
            $this->mercureHandler     = new MercureHandler(
 | 
					            $this->mercureHandler     = new MercureHandler(
 | 
				
			||||||
                config: $this->config,
 | 
					                config: $this->config,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user