summaryrefslogtreecommitdiff
path: root/vendor/open-telemetry/sdk/Common/Export/Stream/StreamTransportFactory.php
blob: 59e4113189d229ca1ee03df903d04a4a23b6b2f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?php

declare(strict_types=1);

namespace OpenTelemetry\SDK\Common\Export\Stream;

use ErrorException;
use function fopen;
use function implode;
use function is_resource;
use LogicException;
use OpenTelemetry\SDK\Common\Export\TransportFactoryInterface;
use OpenTelemetry\SDK\Common\Export\TransportInterface;
use function restore_error_handler;
use function set_error_handler;
use function sprintf;
use function stream_context_create;

/**
 * @psalm-internal \OpenTelemetry
 */
final class StreamTransportFactory implements TransportFactoryInterface
{
    /**
     * @param string|resource $endpoint
     * @param array<string, string|string[]> $headers
     * @param string|string[]|null $compression
     *
     * @psalm-template CONTENT_TYPE of string
     * @psalm-param CONTENT_TYPE $contentType
     * @psalm-return TransportInterface<CONTENT_TYPE>
     */
    public function create(
        $endpoint,
        string $contentType,
        array $headers = [],
        $compression = null,
        float $timeout = 10.,
        int $retryDelay = 100,
        int $maxRetries = 3,
        ?string $cacert = null,
        ?string $cert = null,
        ?string $key = null
    ): TransportInterface {
        assert(!empty($endpoint));
        $stream = is_resource($endpoint)
            ? $endpoint
            : self::createStream(
                $endpoint,
                $contentType,
                $headers,
                $timeout,
                $cacert,
                $cert,
                $key,
            );

        return new StreamTransport($stream, $contentType);
    }

    /**
     * @throws ErrorException
     * @return resource
     */
    private static function createStream(
        string $endpoint,
        string $contentType,
        array $headers = [],
        float $timeout = 10.,
        ?string $cacert = null,
        ?string $cert = null,
        ?string $key = null
    ) {
        $context = stream_context_create([
            'http' => [
                'method' => 'POST',
                'header' => self::createHeaderArray($contentType, $headers),
                'timeout' => $timeout,
            ],
            'ssl' => [
                'cafile' => $cacert,
                'local_cert' => $cert,
                'local_pk' => $key,
            ],
        ]);

        set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline): bool {
            throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
        });

        /**
         * @psalm-suppress PossiblyNullArgument
         */
        try {
            $stream = fopen($endpoint, 'ab', false, $context);
        } finally {
            restore_error_handler();
        }

        /** @phan-suppress-next-line PhanPossiblyUndeclaredVariable */
        if (!$stream) {
            throw new LogicException(sprintf('Failed opening stream "%s"', $endpoint));
        }

        return $stream;
    }

    private static function createHeaderArray(string $contentType, array $headers): array
    {
        $header = [];
        $header[] = sprintf('Content-Type: %s', $contentType);
        foreach ($headers as $name => $value) {
            $header[] = sprintf('%s: %s', $name, implode(', ', (array) $value));
        }

        return $header;
    }
}