Skip to content

Add SSL support #78

@thekid

Description

@thekid

Proof of concept

Adding a second socket with ssl context options:

diff --git a/src/main/php/xp/web/srv/Standalone.class.php b/src/main/php/xp/web/srv/Standalone.class.php
index 0e5be20..3d4dccf 100755
--- a/src/main/php/xp/web/srv/Standalone.class.php
+++ b/src/main/php/xp/web/srv/Standalone.class.php
@@ -30,12 +30,27 @@ abstract class Standalone implements Server {
     $environment= new Environment($profile, $webroot, $docroot, $config, $args, $logging);
     $application= (new Source($source, $environment))->application($args);
     $application->routing();
+    $protocol= new HttpProtocol($application, $environment->logging());
+
+    $http= new ServerSocket($this->host, $this->port);
+    $this->server->listen($http, $protocol);
+
+    // TODO: Remove hardcoded port and certificates, fetch from command line arguments
+    $https= new class($this->host, 8443) extends ServerSocket {
+      public function listen($backlog= SOMAXCONN) {
+        $this->setSocketOption('ssl', 'allow_self_signed', true);
+        $this->setSocketOption('ssl', 'disable_compression', true);
+        $this->setSocketOption('ssl', 'verify_peer', false);
+        $this->setSocketOption('ssl', 'local_cert', 'localhost.crt');
+        $this->setSocketOption('ssl', 'local_pk', 'localhost.key');
+        parent::listen($backlog);
+      }
+    };
+    $this->server->listen($https, new SSL($protocol));
 
-    $socket= new ServerSocket($this->host, $this->port);
-    $this->server->listen($socket, new HttpProtocol($application, $environment->logging()));
     $this->server->init();
 
-    Console::writeLine("\e[33m@", nameof($this), '(HTTP @ ', $socket->toString(), ")\e[0m");
+    Console::writeLine("\e[33m@", nameof($this), '(HTTP @ ', $http->toString(), ")\e[0m");
     Console::writeLine("\e[1mServing ", $application, $config, "\e[0m > ", $environment->logging()->target());
     Console::writeLine("\e[36m", str_repeat('═', 72), "\e[0m");
 

...and wrapping the protocol in this class:

<?php namespace xp\web\srv;

use peer\server\ServerProtocol;
use peer\server\protocol\SocketAcceptHandler;

/**
 * HTTPS transport
 *
 * @see  https://github.com/FiloSottile/mkcert
 * @see  https://letsencrypt.org/docs/certificates-for-localhost/
 */
class SSL implements ServerProtocol, SocketAcceptHandler {
  private $underlying;

  public function __construct(ServerProtocol $underlying) {
    $this->underlying= $underlying;
  }

  /**
   * Initialize Protocol
   *
   * @return bool
   */
  public function initialize() {
    return $this->underlying->initialize();
  }

  /**
   * Handle client connect
   *
   * @param  peer.Socket $socket
   * @return bool
   */
  public function handleAccept($socket) {
    return stream_socket_enable_crypto(
      $socket->getHandle(),
      true,
      STREAM_CRYPTO_METHOD_TLS_SERVER
    );
  }

  /**
   * Handle client connect
   *
   * @param  peer.Socket $socket
   * @return void
   */
  public function handleConnect($socket) {
    $this->underlying->handleConnect($socket);
  }

  /**
   * Handle client disconnect
   *
   * @param  peer.Socket $socket
   * @return void
   */
  public function handleDisconnect($socket) {
    $this->underlying->handleDisconnect($socket);
  }

  /**
   * Handle client data
   *
   * @param  peer.Socket $socket
   * @return ?iterable
   */
  public function handleData($socket) {
    return $this->underlying->handleData($socket);
  }

  /**
   * Handle I/O error
   *
   * @param  peer.Socket $socket
   * @param  lang.XPException $e
   * @return void
   */
  public function handleError($socket, $e) {
    $this->underlying->handleError($socket, $e);
  }
}

Both include hints as to where our sockets API in xp-framework/networking is not sufficient yet.

Limitations

This only works for standalone webservers - default, async, fork, prefork - and the ext/sockets version might not be trivial. For the development webserver, we would need to implement a proxy.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions