• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

azjezz / psl / 22519606807

28 Feb 2026 11:11AM UTC coverage: 97.532% (-1.2%) from 98.733%
22519606807

push

github

web-flow
feat(network): rewrite networking stack with TLS, UDP, SOCKS5, CIDR, and IO utilities (#585)

860 of 937 new or added lines in 31 files covered. (91.78%)

15 existing lines in 6 files now uncovered.

7470 of 7659 relevant lines covered (97.53%)

42.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.67
/src/Psl/TLS/ClientHello.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Psl\TLS;
6

7
use Psl\Network;
8
use Psl\TLS\Exception\HandshakeFailedException;
9

10
use function is_resource;
11
use function stream_context_set_options;
12

13
/**
14
 * Represents a parsed TLS ClientHello, allowing SNI/ALPN inspection before completing the handshake.
15
 *
16
 * Obtained from {@see LazyAcceptor::accept()}, this class lets you inspect the client's
17
 * SNI hostname and ALPN protocols before choosing a {@see ServerConfig} for the handshake.
18
 */
19
final readonly class ClientHello
20
{
21
    /**
22
     * @param ?non-empty-string $serverName
23
     * @param ?list<non-empty-string> $alpnProtocols
24
     */
25
    public function __construct(
26
        private Network\StreamInterface $stream,
27
        private null|string $serverName,
28
        private null|array $alpnProtocols,
29
    ) {}
2✔
30

31
    /**
32
     * The SNI hostname the client requested, or null if not present.
33
     *
34
     * @return ?non-empty-string
35
     */
36
    public function getServerName(): null|string
37
    {
38
        return $this->serverName;
1✔
39
    }
40

41
    /**
42
     * The ALPN protocols the client advertised, or null if not present.
43
     *
44
     * @return ?list<non-empty-string>
45
     */
46
    public function getAlpnProtocols(): null|array
47
    {
48
        return $this->alpnProtocols;
1✔
49
    }
50

51
    /**
52
     * Complete the TLS handshake with the given configuration.
53
     *
54
     * @throws HandshakeFailedException If the TLS handshake fails.
55
     * @throws Network\Exception\RuntimeException If the stream is not available.
56
     */
57
    public function complete(ServerConfig $config): StreamInterface
58
    {
59
        $resource = $this->stream->getStream();
2✔
60
        if (!is_resource($resource)) {
2✔
NEW
61
            throw new Network\Exception\RuntimeException('Stream resource is not available.');
×
62
        }
63

64
        $ssl_context = Internal\server_ssl_context($config);
2✔
65
        stream_context_set_options($resource, ['ssl' => $ssl_context]);
2✔
66

67
        $crypto_method = Internal\crypto_method($config->minimumVersion, $config->maximumVersion, server: true);
2✔
68

69
        Internal\enable_crypto($resource, $crypto_method);
2✔
70

71
        $state = Internal\extract_connection_state($resource);
2✔
72

73
        return new Internal\Stream($this->stream, $state);
2✔
74
    }
75
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc